Annotations Retrieve
Authentication
Path parameters
Response
numerical- Numericalcategorical- Categoricalboolean- Boolean
numerical - Numericalcategorical - Categoricalboolean - BooleanStamp 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}
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).