Blog
Wild & Free Tools

Django UUIDField: Use UUID as Primary Key in Your Models

Last updated: January 2026 6 min read
Quick Answer

Table of Contents

  1. Model Definition
  2. Migrations
  3. Admin Display
  4. DRF Serializers
  5. PostgreSQL Tips
  6. Frequently Asked Questions

Django ships with UUIDField out of the box. You don't need a third-party library — just import Python's uuid module, set a sensible default, and run a migration. This guide covers every step: model definition, migration gotchas, admin display, and how Django REST Framework handles UUID primary keys automatically.

Defining a UUID Primary Key on a Django Model

The simplest, most common pattern looks like this:

import uuid
from django.db import models

class Order(models.Model):
    id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False,
    )
    created_at = models.DateTimeField(auto_now_add=True)
    total = models.DecimalField(max_digits=10, decimal_places=2)

    class Meta:
        ordering = ['-created_at']

Two key details:

Migrations: What Changes with UUID Primary Keys

Run the standard migration commands:

python manage.py makemigrations
python manage.py migrate

Django stores UUIDs differently depending on your database backend:

If you're adding UUID primary keys to an existing table that already has integer IDs, you need a multi-step migration: add the UUID column, backfill values, drop the old ID, then set the UUID as primary key. Django won't do this automatically — you'll need a custom RunPython step in your migration file.

Sell Custom Apparel — We Handle Printing & Free Shipping

Django Admin: Displaying UUIDs Cleanly

By default the admin shows the full UUID string in the list view, which is readable but long. You can format it or shorten it in admin.py:

from django.contrib import admin
from .models import Order

@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
    list_display = ('short_id', 'total', 'created_at')
    readonly_fields = ('id',)

    def short_id(self, obj):
        return str(obj.id)[:8] + '...'
    short_id.short_description = 'ID'

The readonly_fields = ('id',) line ensures the UUID is visible in the detail view even though editable=False — without this, it won't appear at all in admin.

Django REST Framework: UUID Fields in Serializers

DRF automatically maps UUIDField to serializers.UUIDField, which outputs the standard hyphenated format (550e8400-e29b-41d4-a716-446655440000). You don't need to declare it manually:

from rest_framework import serializers
from .models import Order

class OrderSerializer(serializers.ModelSerializer):
    class Meta:
        model = Order
        fields = ['id', 'total', 'created_at']
        read_only_fields = ['id']

When a client POSTs to create an order, Django generates the UUID server-side — the client never needs to send an ID. When the client later fetches the order, the response includes the full UUID for subsequent requests.

URL routing works naturally too:

# urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('orders/<uuid:pk>/', views.OrderDetailView.as_view()),
]

The <uuid:pk> converter validates the format automatically — malformed UUIDs return a 404 without hitting your view.

PostgreSQL-Specific: gen_random_uuid() and Indexes

If your database is PostgreSQL (the recommended production backend for Django), you can also let the database generate UUIDs instead of Python:

from django.db.models.functions import Now
from django.db.models import UUIDField
from django.db import models

# PostgreSQL only: database-generated UUID
id = models.UUIDField(
    primary_key=True,
    default=None,  # DB will generate it
    db_default=models.expressions.DatabaseDefault(),
)

More commonly, teams stick with default=uuid.uuid4 (Python-generated) because it's database-agnostic. For indexing, PostgreSQL handles UUID primary keys well — but if you're doing range scans or want time-ordered inserts, consider UUID v7 (available in Python 3.12+) which embeds a millisecond timestamp for better B-tree locality.

Use the free UUID generator above to create test values for fixtures, Postman collections, or seed scripts while building your Django app.

Generate Test UUIDs for Your Django Project

The Cheetah UUID Generator produces RFC-compliant UUID v4 strings — copy them directly into Django fixtures, test factories, or Postman collections.

Open Free UUID Generator

Frequently Asked Questions

Does Django's UUIDField work with all databases?

Yes. PostgreSQL stores it as a native UUID type. SQLite and MySQL store it as a 32-char VARCHAR. Behavior is transparent — Django handles the conversion automatically.

Should I use uuid.uuid4 or uuid.uuid4() as the default?

Always use uuid.uuid4 (no parentheses). Passing the function reference means Django calls it fresh for each new row. Using uuid.uuid4() evaluates once at class definition time and every row gets the same UUID — a data-corrupting bug.

Can I use UUID fields on non-primary-key columns?

Yes. Any column can be a UUIDField. Common uses: correlation IDs for logging, idempotency keys, external-facing reference numbers when you want to hide the real integer PK.

How do I generate test UUIDs for Django fixtures?

Use the free UUID generator on this page — copy and paste values into your fixture JSON, seed scripts, or Postman environments.

Kevin Harris
Kevin Harris Finance & Calculator Writer

Kevin is a certified financial planner passionate about making financial literacy tools free and accessible.

More articles by Kevin →
Launch Your Own Clothing Brand — No Inventory, No Risk