Skip to main content

Python Django: How to Resolve Warning "Auto-Created Primary Key Used When Not Defining a Primary Key Type" in Django

If you've upgraded to Django 3.2 or later, you've likely encountered this warning:

WARNINGS:
myapp.MyModel: (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 AppConfig.default_auto_field
attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.

This warning appears because Django changed its default primary key behavior starting in version 3.2. This guide explains why the warning occurs and walks you through three methods to fix it, so you can choose the approach that best fits your project.

Why Does This Warning Appear?

Every Django model needs a primary key: a unique identifier for each row in the database. If you don't define one explicitly, Django auto-creates one for you.

  • Before Django 3.2: The auto-created primary key was an AutoField (32-bit integer, max ~2.1 billion).
  • Django 3.2 and later: The default changed to BigAutoField (64-bit integer, max ~9.2 quintillion).

The warning tells you that Django is auto-creating a primary key and wants you to explicitly choose which type to use. This prevents silent, potentially breaking changes, especially when upgrading existing projects where the database already uses 32-bit integer keys.

note

This is a warning, not an error. Your project will still run, but the warning will persist until you explicitly configure the primary key behavior.

Method 1: Set the Global Default in settings.py

The quickest way to silence the warning across your entire project is to set DEFAULT_AUTO_FIELD in your settings.py file.

settings.py
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

This uses a 64-bit integer, which supports a much larger range of IDs and is the modern Django default.

Option B: Use AutoField (For Backward Compatibility)

settings.py
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'

Use this if you're upgrading an existing project and want to maintain compatibility with your current database schema without generating unnecessary migrations.

tip

If you're starting a new project with Django 3.2+, the startproject command already includes DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' in settings.py. The warning typically affects projects created with older Django versions and later upgraded.

Method 2: Set the Default per App in apps.py

If different apps in your project need different primary key types, you can configure the default at the app level using AppConfig.default_auto_field:

myapp/apps.py
from django.apps import AppConfig

class MyappConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'myapp'

This setting overrides the global DEFAULT_AUTO_FIELD for all models within that specific app.

Example: Mixed Configuration

legacy_app/apps.py
from django.apps import AppConfig

class LegacyAppConfig(AppConfig):
default_auto_field = 'django.db.models.AutoField' # Keep 32-bit for legacy tables
name = 'legacy_app'
new_app/apps.py
from django.apps import AppConfig

class NewAppConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField' # Use 64-bit for new tables
name = 'new_app'
caution

Make sure the AppConfig subclass is correctly referenced in your app's __init__.py or in INSTALLED_APPS:

settings.py
INSTALLED_APPS = [
'legacy_app.apps.LegacyAppConfig',
'new_app.apps.NewAppConfig',
# ...
]

Method 3: Explicitly Define a Primary Key in Each Model

For maximum control, you can define the primary key directly in each model. This overrides both the global and app-level defaults and makes the schema completely explicit.

Using BigAutoField

from django.db import models

class Product(models.Model):
id = models.BigAutoField(primary_key=True)
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)

Using AutoField

from django.db import models

class Category(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=50)

Using UUIDField

UUID primary keys are useful for distributed systems, APIs, or when you don't want sequential, guessable IDs:

import uuid
from django.db import models

class Order(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
customer_name = models.CharField(max_length=100)
total = models.DecimalField(max_digits=10, decimal_places=2)

Using CharField with a Custom Generator

For human-readable or formatted primary keys:

import random
import string
from django.db import models

def generate_order_code():
"""Generate a code like 'ORD-A3bX9k'."""
chars = string.ascii_letters + string.digits
random_part = ''.join(random.choices(chars, k=6))
return f"ORD-{random_part}"

class Order(models.Model):
code = models.CharField(
max_length=20,
primary_key=True,
default=generate_order_code,
editable=False
)
description = models.TextField()
caution

Custom string-based primary keys require careful handling to avoid collisions. For high-volume applications, consider adding uniqueness checks or using UUIDs instead.

Which Method Should You Choose?

ApproachScopeBest For
DEFAULT_AUTO_FIELD in settings.pyEntire projectNew projects or full upgrades. Quickest single fix
default_auto_field in apps.pySingle appProjects with mixed legacy and new apps
Explicit field in each modelSingle modelModels needing UUID, CharField, or custom primary keys

Recommended strategy:

  1. Set DEFAULT_AUTO_FIELD in settings.py as your baseline.
  2. Override at the app level only if specific apps need different behavior.
  3. Define explicit primary keys on individual models only when you need a non-integer type (UUID, CharField, etc.).

Handling Migrations After the Fix

After configuring your primary key settings, you may need to generate and apply migrations:

python manage.py makemigrations
python manage.py migrate

Important Considerations

  • Setting DEFAULT_AUTO_FIELD to AutoField on an existing project that already uses AutoField will typically generate no new migrations. It just silences the warning.
  • Changing from AutoField to BigAutoField on existing models will generate migrations that alter the column type in the database. This can be time-consuming on large tables.
  • Changing from AutoField to UUIDField is a breaking change that requires careful data migration, as existing integer IDs cannot be directly converted to UUIDs.
danger

Changing the primary key type on a production database with existing data and foreign key relationships is a complex operation. Always:

  1. Back up your database before migrating.
  2. Test the migration on a staging environment first.
  3. Plan for downtime if tables are large, as ALTER TABLE operations can lock the table.

Safe Approach for Existing Projects

If you're upgrading an existing project and simply want to stop the warning without changing your database, set:

settings.py
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'

This tells Django to continue using the same AutoField your existing database already uses, generating no migrations and requiring no schema changes.

Conclusion

The "Auto-created primary key" warning in Django 3.2+ is easy to resolve once you understand the three available approaches:

  • Set DEFAULT_AUTO_FIELD in settings.py for a project-wide fix: this is the simplest and most common solution.
  • Configure default_auto_field in apps.py when different apps need different primary key types.
  • Define primary keys explicitly in models when you need non-standard types like UUIDField or CharField.

For existing projects being upgraded, setting DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' is the safest choice: it preserves your current schema and eliminates the warning without generating any migrations. For new projects, BigAutoField is the recommended default, providing ample room for growth.