Tutorial

How to seed a Django database with realistic test data

Fixtures rot, factories are per-test, and a hand-written seed command breaks on every schema change. Here is how to fill a Django database with realistic, foreign-key-consistent data straight from your models.py.

SeedBase · ~6 min read

Why seeding Django is annoying

Every Django project hits the same wall once the schema grows past a handful of models. Your options for test data all have a catch:

What you actually want is to point something at the models you already have and get a populated database where every foreign key resolves. Here is the whole loop.

Step 1, Point it at your models.py

SeedBase reads your Django models directly. Paste your models.py, or push the whole project in one click from the PyCharm or VS Code plugin. Take a typical shop:

class Customer(models.Model):
    name  = models.CharField(max_length=120)
    email = models.EmailField(unique=True)
    city  = models.CharField(max_length=80)

class Product(models.Model):
    sku   = models.CharField(max_length=32, unique=True)
    name  = models.CharField(max_length=200)
    price = models.DecimalField(max_digits=10, decimal_places=2)

class Order(models.Model):
    STATUS = [("pending", "Pending"), ("paid", "Paid"), ("shipped", "Shipped")]
    customer   = models.ForeignKey(Customer, on_delete=models.CASCADE)
    status     = models.CharField(max_length=16, choices=STATUS)
    created_at = models.DateTimeField(auto_now_add=True)

class OrderItem(models.Model):
    order    = models.ForeignKey(Order, related_name="items", on_delete=models.CASCADE)
    product  = models.ForeignKey(Product, on_delete=models.PROTECT)
    quantity = models.PositiveIntegerField()

The parser understands Django, not just generic SQL:

Step 2, Generate

Hit generate. The part that makes Django data actually loadable happens here:

Step 3, Realistic, not just valid

Valid data where every row looks identical still hides bugs. A few things that make it behave like production:

Step 4, Load it into your database

Export as SQL and pipe it straight into your project database, with constraints on, because the inserts are already in FK order:

# straight into the Django-configured database
python manage.py dbshell < seed.sql

# or plain psql
psql "$DATABASE_URL" -f seed.sql

Or skip the file and pull from the CLI, handy in a Makefile or a fresh dev setup:

pip install seedbase
seedbase pull --project <id> --format sql --out seed.sql

You can also connect a database in the UI and push the rows directly, no SQL file at all.

Step 5, Make it reproducible in CI

Generation is deterministic per seed, so a CI run gets the exact same database every time. The Python SDK and pytest plugin pull seeded data straight into your test database, and you can commit the generation config as JSON next to your migrations so the whole team regenerates the same dataset from the same models.

Where this fits. This fills a dev database, staging, a demo, or a CI container with a coherent dataset straight from your models. For object-level setup inside a single test, factory_boy is still the right tool. They solve different problems and pair well.

That's the whole loop

models.py in, generate, load. The hard parts (insert ordering, resolving every foreign key, abstract bases, through tables, realistic skew) are handled, so you do not hand-write another seed command. It was tested against a real 20-app Django project with 226 models, which is where most of the edge cases came from. The same approach works for any schema, SQL or Prisma included.

Seed your Django database, free

Paste your models.py or push it from your IDE, generate a populated, FK-consistent database, and load it with manage.py dbshell. Free tier, no credit card.

  • Every FK resolves
  • Realistic distributions
  • SQL / CSV / JSON
  • EU-hosted
Generate Django test data, free

More: Django test data · vs Faker · Prisma