Chapter 7 — Forms + serializer
6 tests covering ModelFormFor<T> parse/from_json/error aggregation/
bound-validation/null handling/insert-query emission. No DB needed.
Run with cargo test --test cookbook_chapter07_forms.
- §7.95
ModelFormFor::<T>::parse(&HashMap<String,String>)— form- encoded payload →(columns, values)with per-field bound validation. Auto PK andauto_now_addcolumns are skipped (DB fills them). →modelform_parses_form_encoded_into_typed_values - §7.95 missing required fields aggregate into
FormErrors, one entry per field. →modelform_missing_required_fields_aggregate_errors - §7.96
ModelFormFor::<T>::from_json(&serde_json::Value)— JSON request body. Null values onOption<T>write explicitSqlValue::Null. →modelform_from_json_parses_object,modelform_from_json_null_writes_explicit_null - §7.98
min/maxbounds run at parse time. Out-of-range values land inFormErrorskeyed by field. →modelform_bound_violation_lands_in_form_errors - §7.99
into_insert_query()emits anInsertQueryagainst the model's table. →modelform_into_insert_query_targets_model_table
Framework bug fixed during this slice: ModelFormFor::parse
required EVERY field including auto_now_add columns (e.g.
joined_at: Auto<DateTime<Utc>>), which the macro skips on INSERT
because DEFAULT NOW() fills them. Fix: skip every auto = true
field (was: only auto && primary_key).
7.99b #[derive(Serializer)] — DRF-shape JSON façade
6 tests in tests/cookbook_chapter07b_serializer.rs exercise the
serializer derive against the cookbook's Author model. Run with
cargo test --test cookbook_chapter07b_serializer.
from_model+to_valueround-trip — every field maps from the model and lands in the JSON output. →serializer_from_model_then_to_value_round_trip#[serializer(read_only)]— excluded fromwritable_fields(), still appears in JSON output. →read_only_field_omitted_from_writable_fields#[serializer(write_only)]— excluded from JSON output, accepted on input. →write_only_field_excluded_from_json_output#[serializer(source = "x")]— renames the JSON key to a different model field. →source_attribute_renames_json_key#[serializer(skip)]— usesDefault::default(), leaves the field in JSON but excludes it fromwritable_fields(). →skip_field_uses_default_and_appears_in_json_unchangedmany_to_value— batches aVec<Model>into a JSON array. →many_to_value_batches_into_json_array
Framework fix during this slice: Auto<T> was missing an
OpenApiSchema impl, so #[derive(Serializer)] failed to build with
the openapi feature on for any model with Auto<T> fields. Added
impl<T: OpenApiSchema> OpenApiSchema for Auto<T> (forwards to T's
schema).
Gaps tracked in v0.18 DRF parity roadmap:
- Auto-nested FK —
#[serializer(nested = AuthorSerializer)]that lazy-loads + nests the parent. Today: manual. SerializerMethodField—#[serializer(method = "fn_name")]computed fields. Today: manual afterfrom_model.- ViewSet ↔ Serializer wiring —
ViewSet::for_model(...).serializer::<T>(). Today: ViewSet serializes the bare model. - M2M many-relations —
#[serializer(many = TagSerializer, source = "tags")]. Today: no automatic M2M traversal in serializers. - Per-field validators chain —
#[serializer(validate = "fn_name")]per-field validator callable. Today: only model-levelmin/max/max_length.
Sub-sections 7.93 (raw Form derive), 7.94 (admin's hand-rolled
ModelForm engine), 7.97 (parse_form_value per type), 7.98b (custom
validators) queued for Slice 7c.