Opened 108 minutes ago
#36986 new Cleanup/optimization
Add a hook to Serializer._value_from_field() for complex fields like CompositePrimaryKey
| Reported by: | Tim Graham | Owned by: | |
|---|---|---|---|
| Component: | Core (Serialization) | Version: | dev |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Unreviewed | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
The Python serializer's _value_from_field() method using isinstance for special-case handling of CompositePrimaryKey.
Custom model fields can't add similar logic without subclassing the serializer, a cumbersome solution which doesn't scale well in the presence of multiple custom fields.
My motivation for a generic hook is to add serialization support for MongoDB's EmbeddedModelField, EmbeddedModelArrayField, PolymorphicEmbeddedModelField, and PolymorphicEmbeddedModelArrayField.
An early prototype:
-
django/core/serializers/python.py
diff --git a/django/core/serializers/python.py b/django/core/serializers/python.py index 2929874b01..1a4f5a1336 100644
a b class Serializer(base.Serializer): 39 39 data["fields"] = self._current 40 40 return data 41 41 42 def get_fields_from_model(self, obj, *, polymorphic=False): 43 data = { 44 field.name: self._value_from_field(obj, field) 45 for field in obj._meta.local_fields 46 } 47 if polymorphic: 48 data["_label"] = obj._meta.label 49 return data 50 42 51 def _value_from_field(self, obj, field): 43 52 if isinstance(field, CompositePrimaryKey): 44 53 return [self._value_from_field(obj, f) for f in field] 54 if hasattr(field, "embedded_model"): 55 sub_obj = getattr(obj, field.attname) 56 if sub_obj is None: 57 return None 58 if isinstance(sub_obj, list): 59 return [self.get_fields_from_model(sub) for sub in sub_obj] 60 return self.get_fields_from_model(sub_obj) 61 if hasattr(field, "embedded_models"): 62 sub_obj = getattr(obj, field.attname) 63 if sub_obj is None: 64 return None 65 if isinstance(sub_obj, list): 66 return [ 67 self.get_fields_from_model(sub, polymorphic=True) for sub in sub_obj 68 ] 69 return self.get_fields_from_model(sub_obj, polymorphic=True) 45 70 value = field.value_from_object(obj) 46 71 # Protected types (i.e., primitives like None, numbers, dates, 47 72 # and Decimals) are passed through as is. All other values are
I don't have an immediate proposal for the API change to accomplish this.