Django unclear behaviour on missed values on model initialization - django

I have a postgres Database and a model with a field as blank=False and null=True.
Let's say:
class MyModel(models.Model):
param1 = models.CharField(max_length=1024)
param2 = models.CharField(max_length=1024)
info = models.CharField(max_length=1024, blank=False, null=False)
Now, when I am creating a model like this:
m = MyModel(param1=val1, param2=val2)
it basically won't raise any exception for info field on saving. Even more, it will keep an empty value for info in the database after using save method.
UPDATED
When instantiating the model like this:
m = MyModel(param1=val1, param2=val2, info=None)
saving will raise an exception in that case
Any suggestions why does it happen? In my opinion if I miss to add a value in the model initialization, it should be at least assumed as None, but it's not. I googled that and couldn't find an specific answer for that. But, found that only full_clean() model method performs checking and raises exceptions like these:
ValidationError: {'info': ['This field cannot be blank.'], 'owner': ['This field cannot be blank.']}
Any help is welcome!

So after researching I came up with this answer:
First of all, blank stands only for form validation, and null for DB validation (docs). As well, Django always assume the empty value for a missing parameter, but with a little bit different behavior for those field types.
The key difference is that for:
Char fields - it uses an empty string (which is ''), the default Django implementation. So if Django sees that there is a missing parameter, it won't pass None for that type of field, since NULL are not being recommended to be stored in DB for char fields. ( details here )
Other fields - it uses an empty value (which is None). So Django sees that there is a missing parameter, it will assume it's None. But since the database restriction null=False, it will raise the exception.
So the conclusion is that only non-charfields that are being supposed to use database constraint null=False - are being checked on save method for missing params by raising exceptions.
Now if you wanna raise exceptions for Charfields as well, you need to use full_clean (used by forms) that will tell you what type of field can't be blank (or missing). So in the end, the right way is to use blank=False and then full_clean to detect missing Charfields. Or/And, you can override the model`s clean() method if have some additional logic to those fields.

info = models.CharField('Facts and features', max_length=1024)

Related

Django: Does not raise error if CharField and TextField are not provided

In Django model fields by default blank=False and null=False
class Test(models.Model):
name = models.CharField()
Now i try to save Test without supplying name
Test.objects.create(pk=1)
Now i am expecting it should raise an exception "null value in column "name" violates not-null constraint" saying that name is required. Whereas for other fields it will raise an exception that we have to provide the value
So is it some default behaviour for CharField and TextField that will allow to store empty string irrespective of blank and null, if we try to save a model directly without any forms.
Something else is wrong.
CharField is required to define a 'max_length' attribute.
Test should not have made it past makemigrations, yet alone get to the stage of creating objects. Did you remember to run a migration? I ran into that error testing this.
Here is the raw SQL query which Django is running (assuming you add the max_length and makemigrations):
'INSERT INTO "polls_test" ("id", "name") SELECT 4, \'\'', 'time': '0.007'
Apparently Django takes it upon itself to just set name to blank if you create it deliberately with .create().
One thing I did find is that Django specifically wants null to be avoided in CharField and TextField, with instead an empty string being the empty value. This is probably a side effect of that decision.

Problems with django rest framework default field validation

I have the following problems for a nested model like this:
def Post(models.Model)
name = models.CharField(unique=True)
content = models.TextField()
def Comment(models.Model)
post = models.ForeignKey(Post)
content = models.CharField()
I created default model serializers with all fields.
Problems:
The default model serializer does not work for nested models. I have to explicitly write create/update. This has been explained in the documentation, so nothing against it. Although I think choosing sane default can cater to 99% of use cases (and for the rest, behaviour can be customisable). I will try to take a shot at this.
When I try to use json from existing post object, serializer is_valid() fails saying "unique constraint on name fails". But I wanted it to update and not create. Should is_valid not be create/update aware based on id being passed in json.
When creating a new nested json with many comments, is_valid() fails saying that "post is empty". Of course I will not have post id in the json, as post creation is yet to happen. So is_valid becomes useless. Should is_valid not depend on if id is passed in json? Also, I can not use data/validated_data without having is_valid pass.
Setting validators = [] also does not remove field validations. I have not yet found a way to suppress field validations.
I have gone through source code and documentation and spent more than a day to set up something so simple.
I must be missing something simple, so any help is appreciated.

django model form clean method with foreign key

I try override clean method for model form with foreign key.
Model:
class Doc(Model):
name = CharField()
doc_type = ForeignKey(DictDocType)
Form:
class DocForm(ModelForm):
class Meta:
model = Doc
fields = '__all__'
def clean_doc_type(self)
doc_type_name = self.cleaned_data['doc_type']
try:
DictDocType.objects.get(name=doc_type_name)
except DictDocType.DoesNotExist:
msg = '{0} does not exist in dictdoc {1}.'.format(
doc_type_name, self.cleaned_data['name'])
raise ValidationError(msg)
return name
In the test I get an error:
KeyError: 'name'.
If I remove self.cleaned_data['name'] from msg - I do not get self.cleaned_data['doc_type'].
Where I'm wrong?
You can't cross reference other fields in clean_foo methods, because not all fields' clean_foo methods are called when you are in one of them. There might be some values of the form that are not populated yet, so clean_name() is not yet called when you call clean_doc_type(), thus you don't have self.cleaned_data['name'].
This should be done in clean method. Django doc very explicitly documented this:
By the time the form’s clean() method is called, all the individual
field clean methods will have been run (the previous two sections), so
self.cleaned_data will be populated with any data that has survived so
far. So you also need to remember to allow for the fact that the
fields you are wanting to validate might not have survived the initial
individual field checks.
Also, your clean method doesn't make much sense and not necessary at all. You wouldn't able to choose a foreignkey that doesn't exist in ModelForm. Even if you force the front end to do so, the field would auto fail the validation and give error:
Select a valid choice. foo is not one of the available choices.

Django model blank=False does not work?

I have the following model in Django 1.5:
class Person(models.Model):
name = models.CharField(max_length=50)
Note that according to https://docs.djangoproject.com/en/dev/ref/models/fields/
name.blank is by default False which means it must be specified.
However, I could successfully create a Person object as follows:
Person.objects.create()
Notice the name is not specified. What is going on?
Ok, the answer from the docs is :
Note that this is different than null. 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.
Another catch:
Note that validators will not be run automatically when you save a model, but if you are using a ModelForm, it will run your validators on any fields that are included in your form.
It's your responsibility to call the clean methods before saving if you're not using a form.
blank only applies to form field validation as in the admin, django forms, etc.
null on the other hand is a database level nullable column.
As for why blank results in a default '', I had really just accepted it as "that's the way it works" but here's where it appears to be in django.db.models.Field
def get_default(self):
"""
Returns the default value for this field.
"""
if self.has_default():
if callable(self.default):
return self.default()
return force_unicode(self.default, strings_only=True)
if (not self.empty_strings_allowed or (self.null and
not connection.features.interprets_empty_strings_as_nulls)):
return None
return ""
# ^ this
Django creates your user with an empty string. You can actually run Person.objects.all() and it will give you a list, if you save that to a variable called user_list and do something like user_list[0], it will return a user object with an empty string. I do not know how or why it does this.

Does model.CharField('blank=False') work with save()?

I've a model like this with Django 1.1:
class Booking(models.Model):
name = models.CharField(max_length=100)
By default, I'm reading that both 'null' and 'blank' are False.
So with a test like this...
class SimpleTest(TestCase):
def test_booking_save(self):
b = Booking()
b.save()
... I expected the save to throw an exception. But it doesn't. It seems quite happy to create a new record with a blank name (Postgres and SQLite3).
I note that via the admin interface a save does indeed fail with a "this field is required".
Questions are:
Is the 'blank' attribute only applied by forms?
Is the fix to override the save() method and explicitly check that len(name) != 0?
Have I misunderstood something which once understood resolves my misunderstanding?
UPDATE: See the model validation documentation in recent Django versions.
Original answer: blank=True/False only applies to forms. Data validation currently only happens at the form level; this will change when the model-validation Google Summer of Code work gets merged in to trunk.
The only kind of validation that currently happens at the model layer is whatever errors your database backend will throw if it can't handle what it gets. In the case of an empty CharField you'll generally never get errors from the database, as Django sets the field to an empty string by default.
For now, you should use the save() method for any model-level validation you want. Soon (if you're on trunk) or when 1.2 comes out, use the model validation stuff.
From the Django Docs:
"Note that empty string values will always get stored as empty strings, not as NULL. Only use null=True for non-string fields such as integers, booleans and dates."
Your code is storing an empty string.
To illustrate this, try:
class SimpleTest(TestCase):
def test_booking_save(self):
b = Booking()
b.name = None
b.save()