v3
latestOpenAPI 3.1.02026-07-311,4541,5202.3 MBAnnotations Retrieve
Stamp server-controlled fields at save time — never by mutating request.data.
DRF's contract: post() → create() → serializer.is_valid() → perform_create(serializer) → serializer.save(**kwargs). Server values belong in that final save(**kwargs) — they override validated_data, never pass through client validation, and don't need to be writable serializer fields. The matching serializer field becomes read_only=True (or is dropped from fields), shrinking — not widening — the mass-assignment surface, and the immutable-QueryDict (multipart) failure mode of the old request.data[...] = pattern disappears.
Declare the fields to stamp as field -> fn(view) -> value maps::
class ExperimentV2sView(ServerStampedFieldsMixin, ...):
create_stamped_fields = {"created_by": stamp_request_user_id}
# + serializer: created_by = ...(read_only=True)
FK columns: when the stamped value is an int and the field names a relation on the serializer's Meta.model, the kwarg is rewritten to <field>_id so Model.objects.create accepts it (a raw int on the FK attribute itself would raise). Non-relation fields (scorer = email) and instance values pass through unchanged.
Cooperative composition: subclasses that need to stamp additional server values (e.g. OrganizationInjectionMixin stamping org/project) override get_create_save_kwargs / get_update_save_kwargs and merge onto super() — yielding exactly ONE serializer.save() per request (calling save() twice would re-run create/update side effects).
Path parameters
Headers
JWT access token or Respan API key