Blank, Null, and Required in Django Models and ModelForms - django

So far I haven't come across a clear explanation on blank, null, and required - in Django's models and forms.
I know the default for each is the following:
blank = False
null = False
required = True
I also know that:
blank=True (used in models.py), means on the form level, accept empty forms - the associated field is not required in a form.
null=True (used in models.py), means on the database level that Python None values can be stored in the model and be saved (and then end up as SQL NULL values in the database).
required=False (used in forms.py), means the associated form field is not required.
Hopefully the above information will serve others well (please let me know if there are any flaws in the logic, and I will update it).
My question is the following:
When do I know when to use blank=True vs. required=False. If my goal is to make a form field not required, I could define this in the model using blank=True, or I could define this in the form using required=False. Does this mean you can define blank=True in a model, and in the associated ModelForm override this with required=True?
Also related, what about when you are using a regular form (forms.Form)? Since the form is not associated with a model (other than through view logic), what happens if again, they contradict each other?

The contradictions don't matter. I think this brings flexibility to the development of a Django application. For example, if you're using a third party library that defines some models, and they set blank=True, but for other purposes you need that field is mandatory, then in your forms you can fix it without touching the third party library code.
This just add some flexibility to the framework IMHO, that brings no harm. You can use it for your own purposes. The contradictions are not significant.
Hope this helps!

It depends on the requirement. Sometime we decide later to make field mandatory on the form although on model it is still not required. But the form will ensure that field must be fill.
You can have null=True on the model and then later you can make that field mandatory on form. But you can not make a field optional in form when it is mandatory on model that will result in database error later on.

Related

Prevent Django model field from being rendered

I'm adding a per-user secret key to one of my Django models for internal usage, but I want to make sure that it is not accidentally exposed to the user. Obviously, I can check all the forms using that model today and ensure that they exclude the field, but that is not future proof. Is there any way I can mark a field so it is never rendered or sent to the client even if a form otherwise includes it?
You could use editable=False on your Model field as documented and here
If False, the field will not be displayed in the admin or any other
ModelForm. They are also skipped during model validation. Default is
True.
Note this works for ModelForms and if you are using regular Form you might consider extending it with custom implementation
ModelForm editable removal implementation source

Create fields based on another model

I have a User model with some fields. Some of them will require feedback, are they correctly filled (if not, specific message will be displayed on user profile).
The problem is, how to represent 'invalid' fields in database. My idea is to create another model (call it ExtUser) with OneToOneField to User. And ExtUser should have same fields' names as User, but their types will be all boolean, determining whether field is filled in correctly. For example, if User has a field called email:
email = models.CharField(max_length=100)
ExtUser would have following field:
email = models.BooleanField(default=False)
Here's a problem with this approach. How am I supposed to create fields in ExtUser? Of course I can create them manually, but that would be breaking of DRY principle, and I'm not going to do that. The question is, can I add fields to model dynamically, and have them in database (so I assume it would require to be called before migrate)?
I have django 1.8 and I don't want to use any external modules/libraries.
If someone has an another idea of how to represent that data in database, please add comment, not a reply - as this question is about creating fields dynamically.
You will need to do this manually.
Python does not disallow this behavior; you can take a look at this SO response on dynamically created classes, but Django will not be able to interpret the output. In particular, Django relies on the models to create the SQL tables for the application, and there is essentially no way for this to occur if you model is not statically defined.
In this case, I don't think you have to worry much about DRY; if you need a separate model with fields which happen to be related to, but different from, another model, I think it's probably ok.
Finally, I'm unsure what your goal is, but you could probably define some functions which can determine how "correct" the fields of the user are. This is how I would recommend solving this problem (if it applies).

When should I be using null=False on django model fields

These questions ask what the null argument does:
differentiate null=True, blank=True in django
In Django models.py, what's the difference between default, null, and blank?
But I want to know, when should I be using it?
For example, why should I ever restrict myself? Is it purely to catch bugs as they happen? As a general rule should I use null=False for all model relationships unless I really need it True? Are there cases where i actually need it?
NOT NULL is a tool to enforce data integrity if that column must never be empty, which is always a good thing. It's better to error out hard and early, than to discover later on that something went wrong and you're left with inconsistent or missing data. Data integrity is a big part of database design, so you should use all the tools at your disposal.
Do you need it? No. Should you use it when appropriate? Definitely. Have I used null=True when I should have been using null=False? Yes I have. If your code works as it should, there's no reason to use null=False. But bugs happen, and when they happen, you don't want to discover that half your data is wrong.
The general rule I have heard/used is that your database should be as strict as possible in what it accepts; your DB is your understanding of the world, and precluding bad data (or at least calling your attention to it) is a good trait.
(The field parameters are also useful when you want to generate right data with model_mommy; it will only generate data that fits your fields, so making them narrowly tailored helps CYA and write good tests.)
The default is False, so the easy road is the right one. Just mark what you need nullable :) .
EDIT: One place where you may need nullability is in polling foreign data. If you are mirroring an API that will use new objects in data before it tells you that there are new objects, then you will want data about that object to be nullable to avoid failing to save new data.
For example:
class Person(models.Model):
""" A person that might tweet """
name = models.CharField(max_length=200)
class Tweet(models.Model):
""" A message broadcast by a person. """
msg = models.TextField()
person = models.ForeignKey('Person')
if you are scraping tweets and hit a new Person's tweet before you save that Person, you might get_or_create an object to fill Tweet.person. However, you don't know that Person's name; you would want name to be nullable (and probably to run an integrity task on your DB regularly to find and fix these issues.)
Its part of your duty as backend developer to set the mimimum data is required to have the model defined, if some field isnt null=True or blank=True the database wont allow you to save the model since they required that data to write the row. (inner coherence is a basic behaviour in SQL databases)
So when a field is not required you should mark it as blank=True or Null=True, and its your duty to mark them properlly.
As a plus django uses that data for the forms validation so doing that correctly will help you later on.

How can one best mark a model field as required in Django?

In Django, I would like the ability to mark certain model fields as required at the model (or at least database) level, to make sure that I am specifying them explicitly (i.e. not relying on defaults) when creating objects.
Currently, Django lets you designate a model field as required at the forms level (by specifying blank=False in the model). However, it doesn't seem like there is a similar option to get this behavior at the model or database level.
It does seem like there are various hacks to achieve something similar though. For example, you can set the default to something that violates a database constraint. For example, you can do things like:
models.CharField(_('characters'), max_length=4, default=None)
or
models.CharField(_('characters'), max_length=4, default="abcdef")
The former example works when saving to the database since None violates the default not-null constraint of null=False (raising an IntegrityError). The latter works because a DataError is raised when saving. But I don't know if this is guaranteed to work across all databases, etc.
Am I missing something, or is there a better way?
If django models called full_clean() automatically on save(), your check would run at the model level without a form. I've been playing with making this the default behavior in my django projects by creating an auto-clean model subclass which does full_clean() on save(), then deriving my models off that.
If you want to learn why it isn't already like this: Why doesn't django's model.save() call full_clean()?

How can I use django forms/models to represent choices between fields?

How can I use boolean choices in a model field to enable/disable other fields. If a boolean value is true/false I want it to enable/disable other model fields. Is there a way to natively express these relationships using django models/forms/widgets? I keep writing custom templates to model these relationships, but can't figure out a good way to represent them in django without a special template.
For example:
class PointInTime(models.Model):
is_absolute_time = models.BooleanField()
absolute_time = models.DateTimeField()
is_relative_time = models.BooleanField()
days_before = models.IntegerField()
So if the is_absolute_time is True, I want the absolute_time entry to be editable in the GUI and the days_before entry to be grayed out and not-editable. If the 'is_relative_time' flag is True, I want the absolute_time entry to be grayed out, and the days_before value to be editable. So is_absolute_time and is_relative_time would be radio buttons in the same Group in the GUI and their two corresponding fields would only be editable when their radio button is selected. This is easy to do in a customized template, but is there a way to use a model/form in django to natively show this relationship?
It would be helpful to clarify what you mean by "natively show this relationship," and think clearly about separation of concerns.
If all you want is to "gray out" or disable a certain field based on the value of another field, this is purely a presentation/UI issue, so the template (and/or Javascript) is the appropriate place to handle it.
If you want to validate that the submitted data is internally consistent (i.e. absolute_time is filled in if is_absolute_time is True, etc), that's a form-validation issue. The place for that logic is in the clean() method of your Form or ModelForm object.
If you want to ensure that no PointInTime model can ever be saved to the database without being internally consistent, that's a data-layer concern. The place for that is in a custom save() method on your model object (Django 1.2 will include a more extensive model validation system).
All of those options involve writing imperative code to do what you need with these specific fields. It may be that you're looking for a way to represent the situation declaratively in your model so that the code in all three of the above cases can be written generically instead of specifically. There's no built-in Django way to do this, but you could certainly do something like:
class PointInTime(models.Model):
field_dependencies = {'is_absolute_time': 'absolute_time',
'is_relative_time': 'days_before'}
... fields here ...
Then your model save() code (or your Form clean() code, or your template), could use this dictionary to determine which fields should be enabled/disabled depending on the value of which other one. This generalization is hardly worth the effort, though, unless you anticipate needing to do this same thing in a number of different models.
Lastly, a few schema design alternatives you may want to consider to get your data layer better normalized:
If there are only two valid states (absolute and relative), use a single boolean field instead of two. Then you avoid possible inconsistencies (what does it mean if both booleans are False? Or True?)
Or simplify further by eliminating the booleans entirely and just using Null values in one or the other of absolute_time/days_before.
If there might be more than two valid states, use a single IntegerField or CharField with choices instead of using two boolean fields. Same reason as above, but can accomodate more than two options.
Since a RelativeTime and an AbsoluteTime don't appear to share any data fields with each other, consider splitting them out into separate models entirely. If you have other models that need a ForeignKey to either one or the other, you could model that with inheritance (both RelativeTime and AbsoluteTime inherit from PointInTime, other models have ForeignKeys to PointInTime).
I'm not entirely sure what you're doing with these objects but whichever the user chooses, you're pointing to a single moment in time. "5 days ago" is "Thursday" and vice-versa.
So unless the dates roll with the site (eg the record with "5 days ago" will still mean Thursday, tomorrow, etc), surely this is only an interface problem? If that's the case, I'd stick with a single value for the date in your Model and let the form and view do all the work.
That solves the auto-generated Admin side of things as you'll just have one field to contend with but it won't natively give you the choice between the two unless you write your own form widget and override the ModelAdmin class for your Model.
If this isn't the case, please ignore this answer.