How many times have you defined a model and thought how should I define my fields visa ve blank and true. Let me demystify this for you/.
Lets define an address model
class Address(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
address_line_one = models.CharField(blank=True, max_length=100)
address_line_two = models.CharField(blank=True, max_length=100)
address_line_three = models.CharField(blank=True, max_length=100)
address_line_four = models.CharField(blank=True, max_length=100)
town_or_city = models.CharField(blank=True, max_length=100)
county = models.CharField(blank=True, max_length=100)
postcode = models.CharField(blank=True, max_length=10)
Is this right? Lets answer a couple questions and then lets go through it field by field and maybe make some changes.
null is purely database-related, whereas blank is validation-related
So if null=True the database will accept no value or an empty value
If null=False the database will not accept an empty string or no value and it will blow up with an integrity error
If blank=True no validation will happen on this field when it is used in a form or in the django admin
If blank=False you will get required field errors in the django admin for your model and if using a model form.
One of the first questions you can ask is what are the defaults? They are a helpful guide. Django being a framework is opinionated , so in its opinion the defaults are
null = False
blank = False
The default position and the safest :) which means if you define a field CharField( max_length=100) it the same as CharField(null=False, blank=False, max_length=100)
This doesn't make any sense, a database field allowing null but the form not allowing empty or nothing. Crazy!!
blank=True can be used with fields having null=False, but this will require implementing clean() on the model in order to programmatically supply any missing values.
This makes sense for fields that sometimes have values but you are not concerned if they don't have. address_line_four is a great candidate for this.
One piece of advice in the docs is Avoid using null on string-based fields such as CharField and TextField. This is a good guide but sometimes we need to deviate from this to ensure data integrity.
So now with our new knowledge what should our model definition look like:
user = null=False, blank=False - Correct as I never want an address to exist that is not related to a user
address_line_one = null=False, blank=True - Incorrect in my case. I think that if an address exists it needs to have at least and address_line_one so I think this should be null=False, blank=False
address_line_two = null=False, blank=True - Incorrect. I am happy for this field to be empty in my database and my form fields. Not all addresses have a second line So it should be null=True, blank=True. This applies to all the other address lines
town_or_city = null=False, blank=True - Incorrect for my app. But may be correct in another app. Maybe the app you are building can have an address that does not belong to a city, like a caravan in a dessert. In my case my app is only interested in addresses that belong to addresses in UK cities. https://peoplevsparkingtickets.co.uk/ so I say null=False, blank=False
county = null=False, blank=True - Incorrect for me , my app is not so precious about the county so null=False, blank=False
postcode = null=False, blank=True - Incorrect. In the UK you cannot have and address without a postcode so null=False, blank=False
When do we use null=False, blank=True then? Say you wanted to store a calculated field or a field that was a combination of the other fields.
say postcode_prefix then that would be a good time to use it.
So our model now becomes:
class Address(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
address_line_one = models.CharField(max_length=100)
address_line_two = models.CharField(null=True, blank=True, max_length=100)
address_line_three = models.CharField(null=True, blank=True, max_length=100)
address_line_four = models.CharField(null=True, blank=True, max_length=100)
town_or_city = models.CharField(max_length=100)
county = models.CharField(null=True, blank=True, max_length=100)
postcode = models.CharField(max_length=10)
postcode_prefix = models.CharField(null=False, blank=True, max_length=4)
Hope that helps and please do let me know on twitter @chriswedgwood if I have got something wrong :) #alwayslearning