Skip to content
Back to skills

Pytest Django

ASecurity

pytest-django integration testing specialist. Covers all fixtures (db, transactional_db, client, rf, settings, mailoutbox, django_user_model), @pytest.mark.django_db options, DRF APIClient, factory_boy integration, async views, signals, management commands, and multi-database testing. USE WHEN: user mentions "pytest-django", "django test", "@pytest.mark.django_db", asks about "django client fixture", "DRF APIClient", "django signals test", "management command test", "django async view test"....

  • 31 stars
  • 0 votes
  • 0 copies
  • 5 views
  • Added September 8, 2026
ai-agentspythongofastapidjangotestingapidatabasebackenddocumentation

Works with

  • cli
  • api
  • mcp

Security analysis

A100/100

Scanned September 8, 2026

npx -y skills add claude-dev-suite/claude-dev-suite --skill pytest-django --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Pytest Django?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Pytest Django
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/claude-dev-suite-pytest-django/badge)](https://www.skillsdirectory.com/skills/claude-dev-suite-pytest-django)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: pytest-django
description: |
  pytest-django integration testing specialist. Covers all fixtures (db,
  transactional_db, client, rf, settings, mailoutbox, django_user_model),
  @pytest.mark.django_db options, DRF APIClient, factory_boy integration,
  async views, signals, management commands, and multi-database testing.

  USE WHEN: user mentions "pytest-django", "django test", "@pytest.mark.django_db",
  asks about "django client fixture", "DRF APIClient", "django signals test",
  "management command test", "django async view test".

  DO NOT USE FOR: Non-Django Python tests - use `pytest` or `python-integration`;
  FastAPI - use `fastapi-testing`; Pure container setup - use `testcontainers-python`
allowed-tools: Read, Grep, Glob, Write, Edit
---
# pytest-django

> **Deep Knowledge**: Use `mcp__documentation__fetch_docs` with technology: `pytest-django`
> for comprehensive documentation on all fixtures, markers, and advanced patterns.

## Setup

```toml
# pyproject.toml
[tool.pytest.ini_options]
DJANGO_SETTINGS_MODULE = "myproject.settings.test"
python_files = ["tests.py", "test_*.py", "*_tests.py"]
```

## @pytest.mark.django_db Options

```python
@pytest.mark.django_db                               # basic DB access, rollback
@pytest.mark.django_db(transaction=True)             # real commits (TransactionTestCase)
@pytest.mark.django_db(transaction=True, reset_sequences=True)  # reset auto-increment
@pytest.mark.django_db(databases=["default", "analytics"])      # multiple DBs
@pytest.mark.django_db(databases="__all__")          # all databases
@pytest.mark.django_db(serialized_rollback=True)     # for data migration tests
```

## Core Fixtures

```python
def test_basic(db):               # DB access fixture (use in other fixtures)
    pass

def test_client(client):          # django.test.Client
    response = client.get("/")
    assert response.status_code == 200

def test_admin(admin_client):     # pre-logged-in superuser client
    response = admin_client.get("/admin/")
    assert response.status_code == 200

def test_rf(rf, admin_user):      # RequestFactory (bypasses middleware)
    request = rf.get("/items/")
    request.user = admin_user
    response = my_view(request)

def test_settings(settings):      # modify settings, auto-reverted
    settings.DEBUG = True
    settings.CACHES = {"default": {"BACKEND": "...DummyCache"}}

def test_mail(mailoutbox):        # access sent emails
    send_mail("Subject", "Body", "from@x.com", ["to@x.com"])
    assert len(mailoutbox) == 1
    assert mailoutbox[0].subject == "Subject"

def test_user(django_user_model): # AUTH_USER_MODEL
    user = django_user_model.objects.create_user("alice", password="pass")
    assert user.check_password("pass")
```

## Authentication Patterns

```python
def test_force_login(client, django_user_model):
    user = django_user_model.objects.create_user("alice", password="pass")
    client.force_login(user)            # fastest, no password check
    response = client.get("/private/")
    assert response.status_code == 200

def test_client_login(client, django_user_model):
    django_user_model.objects.create_user("alice", password="pass")
    client.login(username="alice", password="pass")
    response = client.get("/private/")
    assert response.status_code == 200
```

## DRF APIClient

```python
import pytest
from rest_framework.test import APIClient
from rest_framework import status

@pytest.fixture
def api_client():
    return APIClient()

@pytest.fixture
def auth_client(api_client, django_user_model, db):
    user = django_user_model.objects.create_user("alice", password="pass")
    api_client.force_authenticate(user=user)
    return api_client

@pytest.mark.django_db
def test_create(auth_client):
    resp = auth_client.post("/api/items/", {"name": "Widget"}, format="json")
    assert resp.status_code == status.HTTP_201_CREATED
    assert resp.data["name"] == "Widget"

@pytest.mark.django_db
def test_token_auth(api_client, django_user_model):
    from rest_framework.authtoken.models import Token
    user = django_user_model.objects.create_user("alice", password="pass")
    token = Token.objects.create(user=user)
    api_client.credentials(HTTP_AUTHORIZATION="Token " + token.key)
    resp = api_client.get("/api/me/")
    assert resp.status_code == status.HTTP_200_OK
```

## factory_boy Integration

```python
# factories.py
from factory.django import DjangoModelFactory
import factory

class UserFactory(DjangoModelFactory):
    class Meta:
        model = "auth.User"
        django_get_or_create = ("username",)

    username = factory.Sequence(lambda n: f"user{n}")
    email    = factory.LazyAttribute(lambda o: f"{o.username}@example.com")
    password = factory.django.Password("testpass123")

class ArticleFactory(DjangoModelFactory):
    class Meta:
        model = "myapp.Article"

    title  = factory.Sequence(lambda n: f"Article {n}")
    author = factory.SubFactory(UserFactory)
    body   = factory.Faker("paragraph")

# conftest.py
@pytest.fixture
def user(db):
    return UserFactory()

@pytest.fixture
def article(db):
    return ArticleFactory()
```

## Testing Signals

```python
from unittest.mock import MagicMock
from django.db.models.signals import post_save

@pytest.mark.django_db
def test_signal_fires(db):
    handler = MagicMock()
    post_save.connect(handler, sender=Article)
    try:
        Article.objects.create(title="Test", body="Content")
        assert handler.called
        assert handler.call_args[1]["created"] is True
    finally:
        post_save.disconnect(handler, sender=Article)
```

## Testing Management Commands

```python
from io import StringIO
from django.core.management import call_command

@pytest.mark.django_db
def test_command_output():
    out = StringIO()
    call_command("my_command", stdout=out, verbosity=2)
    assert "Success" in out.getvalue()
```

## Async Views (Django 4.1+)

```python
@pytest.mark.asyncio
@pytest.mark.django_db(transaction=True)
async def test_async_view(async_client):
    response = await async_client.get("/async-endpoint/")
    assert response.status_code == 200
```

## Query Count Assertions

```python
def test_no_n_plus_one(client, django_assert_max_num_queries):
    with django_assert_max_num_queries(5):
        response = client.get("/api/articles/")
    assert response.status_code == 200

def test_exact_queries(django_assert_num_queries):
    with django_assert_num_queries(1):
        Article.objects.get(pk=1)
```

## on_commit Callbacks

```python
def test_email_on_commit(client, mailoutbox, django_capture_on_commit_callbacks):
    with django_capture_on_commit_callbacks(execute=True):
        client.post("/orders/", {"item_id": 1})
    assert len(mailoutbox) == 1
```

## Recommended conftest.py

```python
# conftest.py
import pytest

@pytest.fixture(autouse=True)
def fast_password_hasher(settings):
    settings.PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"]

@pytest.fixture(autouse=True)
def dummy_cache(settings):
    settings.CACHES = {"default": {"BACKEND": "django.core.cache.backends.dummy.DummyCache"}}

@pytest.fixture(autouse=True)
def email_backend(settings):
    settings.EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
```

## Anti-Patterns

| Anti-Pattern | Solution |
|---|---|
| `transaction=True` for everything | Use default (rollback) unless you need real commits |
| `db` in session fixture | Use `django_db_blocker` for session scope |
| Not resetting factory sequences | `UserFactory.reset_sequence(0)` in fixtures |
| Not using `force_login` | Prefer `force_login` over `login` for speed |

**Official docs:** https://pytest-django.readthedocs.io/

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.