Upgrading to Django 3.2 and fixing DEFAULT_AUTO_FIELD warnings 
Tags: django, python, database
Published: 2021-04-09 07:50:28

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](https://docs.djangoproject.com/en/3.2/releases/3.2/#customizing-type-of-auto-created-primary-keys) 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

```bash
python -Wa manage.py test
```

You should see the warning and the hint to configure a DEFAULT_AUTO_FIELD

```bash
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`](https://docs.djangoproject.com/en/3.2/ref/models/fields/#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

```python
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:

```python
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:

```python
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

```bash
> 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`:
 
```python
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`

```python
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

```python
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.