info.field_resolution
Overview
Shared resolution of a serializer field's backing Django model field.
Used by both ModelInfoSerializer.get_model_fields_data (to derive type_db/type_model metadata) and the vueda_info system check (to warn about a path that fails to resolve), so the two cannot disagree about whether a given field's path resolves.
field.source and a model's <field>_lookup_expression are resolved through two different mechanisms, because they have different runtime semantics:
field.sourceis DRF's own attribute lookup (rest_framework.fields.get_attribute), which chains plaingetattr()acrosssource.split('.'). It is walked here the same way, so this module never claims a source resolves when DRF's own runtime traversal would not reach it.- A
<field>_lookup_expressionis fed directly tomodels.F()for queryset annotation (seeannotate_formatted_nameinvueda.core.models) and to Django admin'slookup_field(). It is resolved here through Django's own query-expression machinery (F(...).resolve_expression), the same mechanismannotate_formatted_nameuses, so this module never claims an expression is broken when the ORM would actually accept it (a relation, or a transform such as"__year").
resolve_serializer_field_model_field
Resolve the concrete, terminal Django model field a serializer field's value is drawn from.
Returns a (model_field, unresolved_path) pair:
- A field bound to the whole object (
field.source == "*") is never model-backed by design.SerializerMethodFieldforces this; a plainFieldsubclass that computes its own value from the instance can set it explicitly the same way (ObjectRevisionFieldinvueda.history.revisiondoes). Returns(None, None)-- callers must not treat this as an unresolved path worth a warning. - A model declaring
<field_name>_lookup_expression(theformatted_namemechanism) takes priority overfield.sourceand is resolved via Django's own query-expression semantics (see_resolve_lookup_expression). - Otherwise,
field.source(a dotted path for a nested/traversing source, or a plain field name for the common case) is walked via DRF's own attribute-lookup semantics (see_walk_source).
unresolved_path carries the path that failed to resolve, for the system check to name in its warning. A field is only exempt from reporting when it opts out of model-backing by one of two explicit conventions -- never merely because field.source happened to default to field_name rather than being set explicitly:
field.source == "*"(SerializerMethodFieldforces this; a plainFieldsubclass that computes its own value can set it the same way --ObjectRevisionField,AvailableActionsField, andAvailableTransitionFieldall do, since each overridesget_attribute()outright and never readssourceat runtime).- A model defining a callable
get_<field_name>(), mirroring theget_formatted_name()conventionFormattedNameBaseModel._get_formatted_namealready reads this way: a model may opt out of a generated column (for exampleformatted_name = None) in favor of a plain method, and that method is exactly as legitimate a source of the value as a real column.
Absent either opt-out, an unresolved path is reported regardless of whether field.source was set explicitly or left to DRF's default -- a field name that fails to resolve is exactly as likely to be a typo or a stale rename as an explicit source= that fails partway through a relation, and DRF's default gives no way to tell the difference from the outside.
<field>_lookup_expression is resolved through Django's own query-expression semantics (see _resolve_lookup_expression) rather than _walk_source, since it is fed directly to models.F() for queryset annotation and to Django admin's lookup_field(), both of which resolve purely at the database level and cannot reach a @property or method.
field may be unbound (as returned by a bare serializer_instance.get_fields() call, which does not run DRF's binding step) so field.source may still be None rather than already defaulted to field_name -- this mirrors DRF's own Field.bind() default.
Signature
resolve_serializer_field_model_field(model, field_name, field)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| model | yes | ||
| field_name | yes | ||
| field | yes |
Source
server/vueda/info/field_resolution.py:91
Source
server/vueda/info/field_resolution.py