Django models with factory_boy and pytest-django db fixtures: working versions (tested 2026-10-15)
Django models built with factory_boy DjangoModelFactory (SubFactory, get_or_create, traits) and tested offline on in-memory SQLite with pytest-django database access rules and on_commit capture.
passed6 passed · 0 failed2026-10-15 14:11 UTC- Status
- passed
- Last passed
- 2026-10-15 14:11 UTC
- Tests
- 6 / 6
- Language
- Python
- Runtime
- Python 3.13.16
uv venv -q .venv && uv pip install -q --python .venv/bin/python -r requirements.txt .venv/bin/python -m pytest -q
Python 3.13.16 linux 6.17.0-1022-azure x64 runner: github-actions 38748988915
The code
Exactly the files that passed. Your agent can pull them with get_recipe("django-pytest-factoryboy") (install), or see them on GitHub.
django==6.1.2 factory-boy==3.3.3 pytest-django==4.14.0 pytest==9.1.1 faker==37.4.0
SECRET_KEY = "test-only-not-secret"
INSTALLED_APPS = ["shop"]
DATABASES = {
"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"},
}
USE_TZ = True
[pytest] pythonpath = . DJANGO_SETTINGS_MODULE = settings
from django.db import models, transaction
class Author(models.Model):
name = models.CharField(max_length=100, unique=True)
class Book(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name="books")
title = models.CharField(max_length=200)
price_cents = models.PositiveIntegerField(default=0)
class Meta:
ordering = ["title"]
def publish(self, notify):
# runs only after the surrounding transaction commits
transaction.on_commit(lambda: notify(self.pk))
import factory
from factory.django import DjangoModelFactory
from shop.models import Author, Book
class AuthorFactory(DjangoModelFactory):
class Meta:
model = Author
django_get_or_create = ("name",) # reuse existing row instead of hitting unique constraint
name = factory.Sequence(lambda n: f"Author {n}")
class BookFactory(DjangoModelFactory):
class Meta:
model = Book
author = factory.SubFactory(AuthorFactory)
title = factory.Sequence(lambda n: f"Book {n}")
price_cents = 1000
class Params:
cheap = factory.Trait(price_cents=99)
import pytest
from factories import AuthorFactory, BookFactory
from shop.models import Author
@pytest.mark.django_db
def test_subfactory_creates_author():
book = BookFactory()
assert Author.objects.count() == 1
assert book.author.pk is not None
def test_build_strategy_skips_database():
# no django_db mark needed: build() never writes, SubFactory follows the strategy
book = BookFactory.build()
assert book.pk is None and book.author.pk is None
def test_db_access_blocked_without_mark():
# pytest-django blocks ORM access unless the test opts in with django_db
with pytest.raises(RuntimeError):
Author.objects.count()
@pytest.mark.django_db
def test_get_or_create_reuses_row():
a = AuthorFactory(name="Ann")
b = AuthorFactory(name="Ann")
assert a.pk == b.pk and Author.objects.count() == 1
@pytest.mark.django_db
def test_trait_overrides_field():
assert BookFactory(cheap=True).price_cents == 99
@pytest.mark.django_db
def test_publish_runs_on_commit(django_capture_on_commit_callbacks):
# on_commit never fires inside the test's rolled-back transaction, so capture it
book = BookFactory()
calls = []
with django_capture_on_commit_callbacks(execute=True):
book.publish(calls.append)
assert calls == [book.pk]
Connect to ProvenPin
Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp
{ "mcpServers": { "provenpin": { "url": "https://mcp.provenpin.com/mcp" } } }{ "servers": { "provenpin": { "type": "http", "url": "https://mcp.provenpin.com/mcp" } } }{ "mcpServers": { "provenpin": { "serverUrl": "https://mcp.provenpin.com/mcp" } } }{ "mcpServers": { "provenpin": { "type": "streamableHttp", "url": "https://mcp.provenpin.com/mcp" } } }Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.
Related stacks
Django 6 + Django REST Framework model API with pytest-django
A DRF ModelViewSet with a serializer, router and token-free permissions, tested with pytest-django and APIClient on in-memory SQLite.
Django Ninja API with Schema models and pagination on sqlite
A typed Django Ninja CRUD API with Schema input and output models, page-number pagination and sqlite, tested offline with the ninja TestClient and pytest-django.
Django post_save signal enqueuing a Celery task, tested with eager mode and on_commit
A post_save signal queues a Celery task only after the row commits via transaction.on_commit, then tests run offline on in-memory SQLite with Celery eager mode and pytest-django's on_commit capture.
Django REST Framework JWT auth with simplejwt, tested offline
Obtain and refresh JWT pairs with simplejwt, add custom claims, protect a DRF view, and test expired-token rejection on sqlite in-memory with pytest-django.
All Django recipesAll factory-boy recipesAll pytest-django recipes