DEV Community

weplayinternet
weplayinternet

Posted on

Upgrading to Django 3.2 and fixing DEFAULT_AUTO_FIELD warnings

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
Enter fullscreen mode Exit fullscreen mode

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'.
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (1)

Collapse
 
alanana profile image
Allan L. Anatoli

Hello, thanks for the post. Kind of new to django. So under the heading 'Configure DEFAULT_AUTO_FIELD in settings to use BigAutoField", how do you set the ?
I am getting the following error:
"CommandError: Cannot find a migration matching '1' from app 'auction'. Is it in INSTALLED_APPS?"