Skip to main content

Python Django: How to Resolve "django.db.backends.dbapi.DuplicateKeyError" in Python

When working with Django, you may encounter the django.db.backends.dbapi.DuplicateKeyError (or its more common variant django.db.utils.IntegrityError: duplicate key value violates unique constraint). This error occurs when you try to save a record to the database with a value that already exists in a field marked as unique.

In this guide, we'll explain why this happens, show real examples that trigger the error, and walk through multiple solutions to handle it properly.

What Causes DuplicateKeyError?

This error is triggered when a database operation violates a unique constraint. In Django, unique constraints are defined in your models using unique=True, unique_together, UniqueConstraint, or by the primary key itself.

When you attempt to insert a new row (or update an existing one) with a value that duplicates an existing unique field, the database rejects the operation and Django raises the error.

Common scenarios include:

  • Creating an object with a value that already exists in a unique=True field.
  • Concurrent processes or requests trying to save the same data simultaneously.
  • Bulk importing data that contains duplicate entries.
  • Re-running a data migration or seed script without accounting for existing records.

Reproducing the Error

Consider this model with a unique product name:

# models.py
from django.db import models

class Product(models.Model):
product_name = models.CharField(max_length=100, unique=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
category = models.CharField(max_length=50)

def __str__(self):
return self.product_name

❌ Wrong: Creating a duplicate entry:

# First creation:  works fine
Product.objects.create(product_name="iPhone 15", price=999.99, category="smartphones")

# Second creation with the same product_name: raises error
Product.objects.create(product_name="iPhone 15", price=899.99, category="smartphones")

Output:

django.db.utils.IntegrityError: duplicate key value violates unique constraint "myapp_product_product_name_key"
DETAIL: Key (product_name)=(iPhone 15) already exists.

Solutions

Solution 1: Use get_or_create()

Django's get_or_create() method checks if an object with the specified attributes already exists. If it does, the existing object is returned. If not, a new one is created. This is the cleanest solution for most use cases.

product, created = Product.objects.get_or_create(
product_name="iPhone 15",
defaults={
"price": 999.99,
"category": "smartphones",
}
)

if created:
print(f"New product created: {product.product_name}")
else:
print(f"Existing product found: {product.product_name}")

Output (if product already exists):

Existing product found: iPhone 15
How get_or_create() Works
  • The first set of keyword arguments (product_name="iPhone 15") is used for the lookup.
  • The defaults dictionary contains values that are only used when creating a new object, i.e. they're not part of the lookup query.
  • The method returns a tuple: (object, created) where created is a boolean indicating whether a new object was made.

Solution 2: Use update_or_create()

If you want to update an existing record when a duplicate is found (instead of simply retrieving it), use update_or_create():

product, created = Product.objects.update_or_create(
product_name="iPhone 15",
defaults={
"price": 899.99, # Updated price
"category": "smartphones",
}
)

if created:
print(f"New product created: {product.product_name} at ${product.price}")
else:
print(f"Product updated: {product.product_name} - new price: ${product.price}")

Output (if product already exists):

Product updated: iPhone 15 - new price: $899.99

This is especially useful for syncing data from external sources where you want to keep existing records up to date.

Solution 3: Check for Existence Before Saving

If you need more control over the logic, explicitly check whether the object exists before creating it:

if not Product.objects.filter(product_name="iPhone 15").exists():
Product.objects.create(
product_name="iPhone 15",
price=999.99,
category="smartphones"
)
print("Product created successfully.")
else:
print("Product already exists. Skipping creation.")

Output:

Product already exists. Skipping creation.
Race Condition Warning

The check-then-create pattern has a race condition: between the exists() check and the create() call, another process could insert the same record. For concurrent environments, get_or_create() is safer because it handles this atomically at the database level.

Solution 4: Catch IntegrityError with Try/Except

When dealing with bulk operations or situations where duplicates are expected, catch the exception and handle it gracefully:

from django.db import IntegrityError

try:
Product.objects.create(
product_name="iPhone 15",
price=999.99,
category="smartphones"
)
print("Product created successfully.")
except IntegrityError:
print("Product with this name already exists. Skipping.")

Output (if duplicate exists):

Product with this name already exists. Skipping.

For bulk inserts, this approach is more efficient when combined with Django's bulk_create():

from django.db import IntegrityError

products_to_create = [
Product(product_name="Galaxy S24", price=799.99, category="smartphones"),
Product(product_name="iPhone 15", price=999.99, category="smartphones"), # Might exist
Product(product_name="Pixel 8", price=699.99, category="smartphones"),
]

# ignore_conflicts=True skips rows that violate unique constraints
Product.objects.bulk_create(products_to_create, ignore_conflicts=True)
print("Bulk insert completed. Duplicates were skipped.")
tip

bulk_create() with ignore_conflicts=True (Django 2.2+) is the most efficient way to handle bulk imports where some records may already exist. It performs a single database query and silently skips duplicates.

Solution 5: Handle Concurrent Access with select_for_update()

In high-concurrency environments (e.g., web APIs handling simultaneous requests), multiple processes may try to create the same object at the same time. Use database-level locking to prevent this:

from django.db import transaction

with transaction.atomic():
try:
product = Product.objects.select_for_update().get(
product_name="iPhone 15"
)
# Product exists: update it
product.price = 899.99
product.save()
print("Product updated.")
except Product.DoesNotExist:
# Product doesn't exist: create it
Product.objects.create(
product_name="iPhone 15",
price=999.99,
category="smartphones"
)
print("Product created.")

Solution 6: Review and Fix Your Model Constraints

Sometimes the error indicates that your unique constraints are too strict or incorrectly defined. Review your model to ensure the constraints match your business logic:

class Product(models.Model):
product_name = models.CharField(max_length=100)
store = models.ForeignKey('Store', on_delete=models.CASCADE)
price = models.DecimalField(max_digits=10, decimal_places=2)

class Meta:
# A product name should be unique PER STORE, not globally
constraints = [
models.UniqueConstraint(
fields=['product_name', 'store'],
name='unique_product_per_store'
)
]

With this constraint, the same product name can exist across different stores but not within the same store.

Choosing the Right Solution

ScenarioRecommended Solution
Create if doesn't exist, get if it doesget_or_create()
Create or update existing recordupdate_or_create()
Bulk importing databulk_create(ignore_conflicts=True)
Need full control over logictry/except IntegrityError
High-concurrency environmentget_or_create() or select_for_update()
Constraints are too restrictiveReview and adjust model UniqueConstraint

Debugging Checklist

When you encounter this error, work through these steps:

# 1. Read the full error message: it tells you which constraint was violated
# DETAIL: Key (product_name)=(iPhone 15) already exists.

# 2. Check what's already in the database
python manage.py shell
>>> from myapp.models import Product
>>> Product.objects.filter(product_name="iPhone 15").values()

# 3. Review your model for unique constraints
>>> [f.name for f in Product._meta.get_fields() if getattr(f, 'unique', False)]

# 4. Check for unique_together or UniqueConstraint in Meta
>>> Product._meta.unique_together
>>> Product._meta.constraints

Conclusion

The DuplicateKeyError (or IntegrityError: duplicate key) in Django occurs when you attempt to save a record that violates a unique constraint in your database.

The best fix depends on your specific situation: use get_or_create() for simple "create if missing" logic, update_or_create() when existing records should be updated, bulk_create(ignore_conflicts=True) for efficient bulk imports, or try/except IntegrityError when you need explicit error handling.

In all cases, understanding your model's unique constraints and designing your code to account for existing records will prevent this error from disrupting your application.