Complete worked example
python
from drf_lab import setup
setup()
from contextlib import nullcontext
from django.db import IntegrityError, transaction
from rest_framework import serializers
from drf_lab import reset_fixture
from drf_lab.models import Role
class Input(serializers.Serializer):
first = serializers.CharField(max_length=80)
second = serializers.CharField(max_length=80)
slots = serializers.IntegerField(min_value=1, max_value=2, default=1)
def inspect_example(payload):
alice, _, company = reset_fixture()
serializer = Input(data=payload)
if not serializer.is_valid():
return {"error": "validation", "titles": list(Role.objects.filter(owner=alice).order_by("id").values_list("title", flat=True))}
values = serializer.validated_data
created = None
try:
with transaction.atomic():
Role.objects.filter(pk=1, owner=alice).update(title=values["first"])
created = Role.objects.create(owner=alice, company=company, country="UA",
title=values["second"], slots=values["slots"])
committed = True
except IntegrityError:
committed = False
return {"committed": committed, "titles": list(Role.objects.filter(owner=alice).order_by("id").values_list("title", flat=True)),
"new_slots": created.slots if committed else None}- Reasoning
- Validation runs before opening the atomic block. IntegrityError is caught outside it, after Django has had the opportunity to roll back the failed transaction. The helper then reads actual stored titles and the created slots value rather than trusting an optimistic response label. The owned database resets between cases. A successful operation produces both intended changes; a duplicate second title leaves the original four fixture rows and original first title intact. The helper never opens the ApplyDjinn database or contacts a feed.