weplayinternet
Posted on April 9, 2021
When you define a model in Django without specifying a primary key, Django will automatically create a primary key for you. The primary key is set to be an integer. If you want to override the field type, you can do so on a per model basis.
Starting in Django 3.2, you can now customise the type of the automatically created primary key in your settings.
Starting new projects in Django 3.2, the default type for primary keys is set to a BigAutoField
which is a 64 bit integer. However, earlier versions set the type of implicit primary keys to be integers.
This means that when you upgrade to 3.2, you will start to see warnings about the fact that you do not have an explicitly defined primary key type. Satisfying Django's requirements for an explicitly set primary key type is easy enough, but you also need to choose whether or not you want to upgrade your primary key field types from integer to 64 bit integer.
Having upgraded to 3.2, the suggestion in the official docs is to run
python -Wa manage.py test
You should see the warning and the hint to configure a DEFAULT_AUTO_FIELD
WARNINGS:
blog.BlogPost: (models.W042) Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.
HINT: Configure the DEFAULT_AUTO_FIELD setting or the BlogConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.
There are a few ways to fix this. Broadly speaking they fall into two categories - those that do not require a migration and those that do.
No migrations please
If you want the simplest upgrade path without migrations, you'll need to tell Django to set the DEFAULT_AUTO_FIELD to AutoField
which is, under the hood, an IntegerField
. There are a few places you can do this
Configure DEFAULT_AUTO_FIELD in settings
Open your project's settings.py
and add a new line at the bottom of the file
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
Setting on a per app basis
If you prefer to set your field type on a per app basis rather than for the whole project, you can specify this in apps.py
. You might want to do this if you want a different auto field type per app. For a hypothetical project with a blog app, adding the default_auto_field
line in apps.py
will work:
from django.apps import AppConfig
class BlogConfig(AppConfig):
default_auto_field = 'django.db.models.AutoField'
name = 'blog'
Migrations
If you don't mind creating and running migrations, then you can embrace the new BigAutoField
. Again, there are a few ways to achieve this:
Configure DEFAULT_AUTO_FIELD in settings to use BigAutoField
Open your project's settings.py
and add the following to the bottom:
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
You'll then need to create and run a migration to update your database to use the new field type. The migrations will alter the id field on your models. To create and run migration in a hypothetical application named blog
, you'd run the following commands
> python manage.py makemigrations blog
> python manage.py sqlmigrate blog <migration_number>
Set default_auto_field to BigAutoField on a per app basis
As above, you can configure the setting on a per app basis, so in apps.py
, you can set the default_auto_field
to BigAutoField
:
from django.apps import AppConfig
class BlogConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'my_app'
and again create and run migrations for your app.
Set AutoField or BigAutoField on a per model basis
If you prefer even more fine grained control, you can set a per model id field. A blogging app might have a BlogPost
model. You can explicitly set an id field on each model.
In a hypothetical blog application you would modify blog/models.py
class BlogPost(models.Model):
id = models.BigAutoField(primary_key=True)
# ...other fields
If you prefer, you can instead subclass a common base model. Perhaps it saves you some typing if you have a large number of models. In a hypothetical blog application, you would define a common base model and then inherit from it in each model
from django.db import models
class CommonBaseModel(models.Model):
id = models.BigAutoField(primary_key=True)
class Meta:
abstract = True
# Create your models here.
class BlogPost(CommonBaseModel):
# ...other fields
In either of the two previous examples, you can use AutoField
instead of BigAutoField
if you prefer to keep your primary key as an integer. You still need to make and run migrations to be fully up to date though, because you've changed your model definitions.
Summary
Django 3.2 allows developers to customise the field type used when creating automatic primary keys. Upgrading means you'll Django will warn you that you do not have the field type set. To silence the warnings, you need to set the default auto field at a project, app, or model level.
Posted on April 9, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
September 8, 2024