Creation authorization decides which principal may create a record and which fields that principal may supply.
Django REST Framework creation ownership: assign the owner from the principal
Operation contract
The local receipt endpoint accepts only a receipt ID and exact bounded integer amount. It rejects an extra owner_id instead of trusting or quietly copying it. Serializer save receives the owner from the authenticated request context, and the created record retains that server-selected owner. A duplicate ID is rejected before this local in-memory save.
Failure and ownership boundary
Force_authenticate provides a test principal, not a production identity provider. This in-memory duplicate check is not race-safe; a database uniqueness constraint and transaction must enforce concurrent creation. Owner assignment alone also does not establish permission to create every record type. Django REST Framework serializers: reject coercion outside the wire contract, Django models: database constraints survive an unchecked save and Django REST Framework list visibility: filter the principal’s rows before paging are connected boundaries.
Tested environment
Dependency check: this program was executed on CPython 3.14.6 with Django==5.2.17, djangorestframework==3.18.1. Install these versions in a separate virtual environment. The download includes the recorded environment snapshot; no third-party package is part of the website runtime.
Working program
from types import SimpleNamespace
from django.conf import settings
settings.configure(INSTALLED_APPS=[], USE_I18N=False, SECRET_KEY="owned-create-fixture", REST_FRAMEWORK={"DEFAULT_AUTHENTICATION_CLASSES": [], "UNAUTHENTICATED_USER": None})
import django
django.setup()
from rest_framework import serializers
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.test import APIRequestFactory, force_authenticate
RECEIPTS = {}
class ExactAmount(serializers.Field):
def to_internal_value(self, value):
if type(value) is not int or not 0 <= value <= 1000000: raise serializers.ValidationError("amount rejected")
return value
class ReceiptCreation(serializers.Serializer):
receipt_id = serializers.RegexField(r"\AR-[0-9]{4}\Z", trim_whitespace=False)
amount = ExactAmount()
def to_internal_value(self, data):
if not isinstance(data, dict) or set(data) != {"receipt_id", "amount"}: raise serializers.ValidationError({"non_field_errors": ["fields rejected"]})
return super().to_internal_value(data)
def create(self, accepted):
RECEIPTS[accepted["receipt_id"]] = accepted.copy()
return accepted
class ReceiptCreateView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
serializer = ReceiptCreation(data=request.data); serializer.is_valid(raise_exception=True)
if serializer.validated_data["receipt_id"] in RECEIPTS: return Response({"error": "duplicate"}, status=409)
accepted = serializer.save(owner_id=request.user.pk)
return Response({"receipt_id": accepted["receipt_id"]}, status=201)
def local_create(payload):
request = APIRequestFactory().post("/receipts", payload, format="json")
force_authenticate(request, user=SimpleNamespace(pk=7, is_authenticated=True))
return ReceiptCreateView.as_view()(request).status_code
print("created:", local_create({"receipt_id": "R-0041", "amount": 125}))
print("assigned owner:", RECEIPTS["R-0041"]["owner_id"])
print("spoof rejected:", local_create({"receipt_id": "R-0042", "amount": 250, "owner_id": 8}))
print("retained records:", len(RECEIPTS))Output
created: 201
assigned owner: 7
spoof rejected: 400
retained records: 1Costs and limits
The owned mapping has expected constant lookup work under suitable hashes. This fixture is not a durable datastore and imposes no complete multi-request storage quota. A production create path needs database enforcement, request limits and real authentication.
Common Mistakes
- Never assign ownership from an untrusted received owner field.
- A pre-save duplicate lookup is not a concurrent uniqueness guarantee.
Connected lessons
Django REST Framework serializers: reject coercion outside the wire contract, Django models: database constraints survive an unchecked save, Django REST Framework list visibility: filter the principal’s rows before paging.
Follow the service contract
Python Django database constraints: enforce receipt identity per owner.
