Issue with save/save_model/clean from admin (django 1.6.3dev)

307 views
Skip to first unread message

Stefano Crosta

unread,
Feb 24, 2014, 10:17:21 PM2/24/14
to django-d...@googlegroups.com
Hello!

I'm trying to understand if this is a bug, or a not clearly documented feature.

I have a simple model where one field should be calculated at save. eg.

class MyModel(models.Model):
    a = models.CharField(max_length=255) 
    b = models.CharField(max_length=255, blank = True)

Now, if I create an instance in the admin and I try to save leaving `b` empty (that's ok because it's blank=True) I get a ValueError:

Cannot assign None: "app.MyModel" does not allow null values.

Now, I would expect to be able to set `b` to my calculated value in one of the following places, according to the documentation:


- overriding save() in the model class
- in the clean() method in the model class
- with a custom save_model() in the admin class

Instead, none of those locations are reached, and I get the ValueError from 

django/db/models/fields/related.py in __set__
  1.             return rel_obj
  2.     def __set__(self, instance, value):
  3.         # If null=True, we can assign null here, but otherwise the value needs
  4.         # to be an instance of the related class.
  5.         if value is None and self.field.null == False:
  6.             raise ValueError('Cannot assign None: "%s.%s" does not allow null values.' %
  1.                                 (instance._meta.object_name, self.field.name))

now, also checking the stack (and even debugging) it seems like this comes earlier than save.


My question: Is this somehow expected, is this a bug/a regression?

If it's expected, I'll find another workaround; if it's a bug, I can add a ticket.


Thanks!

Stefano



Stacktrack

  • /home/3h/django/django/contrib/admin/options.py in add_view
    1.             if form.is_valid():
      ...
  • /home/3h/django/django/forms/forms.py in is_valid
    1.         return self.is_bound and not bool(self.errors)
      ...
  • /home/3h/django/django/forms/forms.py in errors
    1.             self.full_clean()
      ...
  • /home/3h/django/django/forms/forms.py in full_clean
    1.         self._post_clean()
      ...
  • /home/3h/django/django/forms/models.py in _post_clean
    1.         self.instance = construct_instance(self, self.instance, opts.fields, opts.exclude)
      ...
  • /home/3h/django/django/forms/models.py in construct_instance
    1.             f.save_form_data(instance, cleaned_data[f.name])
      ...
  • /home/3h/django/django/db/models/fields/__init__.py in save_form_data
    1.         setattr(instance, self.name, data)
      ...
  • /home/3h/django/django/db/models/fields/related.py in __set__
    1.                                 (instance._meta.object_name, self.field.name))
      ...

Jonathan Pentecost

unread,
Feb 24, 2014, 10:59:39 PM2/24/14
to django-d...@googlegroups.com
I _think_ your problem might lie in the confusion between "blank" and "null"; taken from https://docs.djangoproject.com/en/dev/ref/models/fields/#blank

 null is purely database-related, whereas blank is validation-related. If a field has blank=True, form validation will allow entry of an empty value. If a field has blank=False, the field will be required.

Shai Berger

unread,
Feb 25, 2014, 2:59:50 AM2/25/14
to django-d...@googlegroups.com
Hi Stefano,

You are leaving out important details -- the error you are getting is clearly
about a "related field" (ForeignKey, OneToOne or ManyToMany), but there is no
such field in the model you provided.

I suspect it is more likely to be a usage issue rather than a problem in
Django code or documentation, and therefore I suggest you bring it up (with
the missing details) at the django-users list.

HTH,
Shai.

On Tuesday 25 February 2014 05:17:21 Stefano Crosta wrote:
> Hello!
>
> I'm trying to understand if this is a bug, or a not clearly documented
> feature.
>
> I have a simple model where one field should be calculated at save. eg.
>
> class MyModel(models.Model):
> a = models.CharField(max_length=255)
> b = models.CharField(max_length=255, blank = True)
>
> Now, if I create an instance in the admin and I try to save leaving `b`
> empty (that's ok because it's blank=True) I get a ValueError:
>
> Cannot assign None: "app.MyModel" does not allow null values.
>
> Now, I would expect to be able to set `b` to my calculated value in one of
> the following places, according to the documentation:
>
>
> - overriding save() in the model class
> - in the clean() method in the model class
> - with a custom save_model() in the admin class
>
> Instead, none of those locations are reached, and I get the ValueError from
>
> django/db/models/fields/related.py in __set__
>
> 1.
>
> return rel_obj
>
> 2.
>
> 3.
>
> def __set__(self, instance, value):
>
> 4.
>
> # If null=True, we can assign null here, but otherwise the value
> needs
>
> 5.
>
> # to be an instance of the related class.
>
> 6.
>
> if value is None and self.field.null == False:
>
> 7.
>
> raise ValueError('Cannot assign None: "%s.%s" does not allow
> null values.' %
>
>
>
> 1.
>
> (instance._meta.object_name,
> self.field.name))
>
>
>
> now, also checking the stack (and even debugging) it seems like this comes
> earlier than save.
>
>
> *My question: **Is this somehow expected, is this a bug/a regression?*
>
> If it's expected, I'll find another workaround; if it's a bug, I can add a
> ticket.
>
>
> Thanks!
>
> Stefano
>
>
>
> Stacktrack
>
>
> - /home/3h/django/django/contrib/admin/options.py in add_view
> 1.
>
> if form.is_valid():
>
> ...
> ▶ Local vars <http://grigio.vm:8000/admin/ipr/ipr/add/#>
> - /home/3h/django/django/forms/forms.py in is_valid
> 1.
>
> return self.is_bound and not bool(self.errors)
>
> ...
> ▶ Local vars <http://grigio.vm:8000/admin/ipr/ipr/add/#>
> - /home/3h/django/django/forms/forms.py in errors
> 1.
>
> self.full_clean()
>
> ...
> ▶ Local vars <http://grigio.vm:8000/admin/ipr/ipr/add/#>
> - /home/3h/django/django/forms/forms.py in full_clean
> 1.
>
> self._post_clean()
>
> ...
> ▶ Local vars <http://grigio.vm:8000/admin/ipr/ipr/add/#>
> - /home/3h/django/django/forms/models.py in _post_clean
> 1.
>
> self.instance = construct_instance(self, self.instance,
> opts.fields, opts.exclude)
>
> ...
> ▶ Local vars <http://grigio.vm:8000/admin/ipr/ipr/add/#>
> - /home/3h/django/django/forms/models.py in construct_instance
> 1.
>
> f.save_form_data(instance, cleaned_data[f.name])
>
> ...
> ▶ Local vars <http://grigio.vm:8000/admin/ipr/ipr/add/#>
> - /home/3h/django/django/db/models/fields/__init__.py in save_form_data
> 1.
>
> setattr(instance, self.name, data)
>
> ...
> ▶ Local vars <http://grigio.vm:8000/admin/ipr/ipr/add/#>
> - /home/3h/django/django/db/models/fields/related.py in __set__
> 1.
>
> (instance._meta.object_name,
> self.field.name))
>
> ...
> ▶ Local vars <http://grigio.vm:8000/admin/ipr/ipr/add/#>
Reply all
Reply to author
Forward
0 new messages