﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
36986	Add model field serialization API	Tim Graham	Tim Graham	"The Python serializer's `_value_from_field()` method using `isinstance` for [https://github.com/django/django/blob/main/django/core/serializers/python.py#L43-L44 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 [https://django-mongodb-backend.readthedocs.io/en/latest/ref/models/fields/#embeddedmodelfield EmbeddedModelField], `EmbeddedModelArrayField`, `PolymorphicEmbeddedModelField`, and `PolymorphicEmbeddedModelArrayField`.

An early prototype:
{{{#!diff
diff --git a/django/core/serializers/python.py b/django/core/serializers/python.py
index 2929874b01..1a4f5a1336 100644
--- a/django/core/serializers/python.py
+++ b/django/core/serializers/python.py
@@ -39,9 +39,34 @@ class Serializer(base.Serializer):
         data[""fields""] = self._current
         return data
 
+    def get_fields_from_model(self, obj, *, polymorphic=False):
+        data = {
+            field.name: self._value_from_field(obj, field)
+            for field in obj._meta.local_fields
+        }
+        if polymorphic:
+            data[""_label""] = obj._meta.label
+        return data
+
     def _value_from_field(self, obj, field):
         if isinstance(field, CompositePrimaryKey):
             return [self._value_from_field(obj, f) for f in field]
+        if hasattr(field, ""embedded_model""):
+            sub_obj = getattr(obj, field.attname)
+            if sub_obj is None:
+                return None
+            if isinstance(sub_obj, list):
+                return [self.get_fields_from_model(sub) for sub in sub_obj]
+            return self.get_fields_from_model(sub_obj)
+        if hasattr(field, ""embedded_models""):
+            sub_obj = getattr(obj, field.attname)
+            if sub_obj is None:
+                return None
+            if isinstance(sub_obj, list):
+                return [
+                    self.get_fields_from_model(sub, polymorphic=True) for sub in sub_obj
+                ]
+            return self.get_fields_from_model(sub_obj, polymorphic=True)
         value = field.value_from_object(obj)
         # Protected types (i.e., primitives like None, numbers, dates,
         # 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."	Cleanup/optimization	assigned	Core (Serialization)	dev	Normal				Accepted	1	0	0	0	0	0
