Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Django REST Framework creation ownership: assign the owner from the principal

Last updated: 30 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

Creation authorization decides which principal may create a record and which fields that principal may supply.

Download Python source kit

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

python
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

Output
created: 201
assigned owner: 7
spoof rejected: 400
retained records: 1

Costs 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.

python
drf-creation-ownership
Storage details