Dealing with Database Defaults in Django
My issue with how Django handles default values and a way around it.
As a pretty big fan of databases, I sometimes get annoyed with how Django handles the database. Specifically, I prefer to look at the database as the source of truth for a project, but Django does not always treat it as such. More often, it looks to the model classes as the source of truth. One such instance is how Django handles default values for models.
Why This is Annoying #
You set the default value on a field like so:
from django.db.models import BooleanField, Model class MyModel(Model): my_field = BooleanField(default=False)
This would generate a migration that looks something like this:
from django.db import migrations, models class Migration(migrations.Migration): dependencies =  operations = [ migrations.AddField( model_name="mymodel", name="myfield", field=models.BooleanField(default=False, null=False), ), ]
Now, if I did not know better, I would expect this to set the default value to false in my database when I run the migration. But I've been around the block with Django, so I've come to realize that this will (annoyingly) initially set the default on the database field but then it immediately drops that default. This makes it so the setting of the default whenever you create a new
MyModel happens on the application side instead of in the database.
Normally, this would be fine, but it becomes a problem anytime you are interacting directly with the database. You should not be regularly doing that; but when you do, if you ever go to insert into this table, you would need to also manually set the value of this field to
False or else you would be violating the not-null constraint. Also, I have seen instances where code will get rolled back on the server but the database will not be rolled back with it, which would then also violate the not-null constraint whenever anyone creates a new instance of this model through your app as well.
Why Django Does This #
The main reasoning I have seen behind this is that Django allows you to set the default to a Django function, which SQL doesn't allow you to do. I do think that is a cool feature, but I wish that there were two separate variables on the field that could handle this.
Luckily, it seems as if Django is doing something to address this problem. They recently merged a pull request that addresses an 18 year old issue about this problem. The changes in the PR add a new
db_default field for setting the default value on the database, which is exactly what I wanted to fix this annoyance.
How to Get Around It #
Until that new feature is released, really the only way around this problem is to just actually set the default on the database. You should do this as part of the migrations so it still gets checked into your version control. So basically, all you need to do is edit your migration file before actually migrating it so it looks more like this:
from django.db import migrations, models class Migration(migrations.Migration): dependencies =  operations = [ migrations.AddField( model_name="mymodel", name="myfield", field=models.BooleanField(default=False, null=False), ), migrations.RunSQL( """ ALTER TABLE myapp_mymodel ALTER myfield SET DEFAULT false; """ ), ]
I recommend doing this for any field that you are setting a default constant value on. Otherwise, you could run into some of the problems I described above.
I hope someone out there finds this little article helpful. Thank you for letting me vent a bit about this small annoyance I have with Django. And thank you to the Django community for addressing the issue.