Code

Ticket #2843: include_reverse_relations.3.diff

File include_reverse_relations.3.diff, 3.7 KB (added by supervacuo, 2 years ago)

I see that there is now a GSOC proposal including this functionality, but that plan involves a completely new serialization interface. 5 years later, Nikolaus's patch applies to trunk with only minimal changes (attached) -- is there any chance that, once it has tests and documentation, this approach could make it into trunk if / in case the GSOC idea doesn't work out?

Line 
1Index: django/core/serializers/xml_serializer.py
2===================================================================
3--- django/core/serializers/xml_serializer.py   (revision 17876)
4+++ django/core/serializers/xml_serializer.py   (working copy)
5@@ -5,6 +5,7 @@
6 from django.conf import settings
7 from django.core.serializers import base
8 from django.db import models, DEFAULT_DB_ALIAS
9+from django.db.models.fields.related import OneToOneRel
10 from django.utils.xmlutils import SimplerXMLGenerator
11 from django.utils.encoding import smart_unicode
12 from xml.dom import pulldom
13@@ -131,6 +132,17 @@
14 
15             self.xml.endElement("field")
16 
17+    def handle_o2m_field(self, obj, field):
18+        if not isinstance(field.field.rel, OneToOneRel):
19+            self.xml.startElement("field", {
20+                "name" : field.get_accessor_name(),
21+                "rel"  : field.field.rel.__class__.__name__,
22+                "to"   : field.field.name,
23+            })
24+            for relobj in getattr(obj, field.get_accessor_name()).iterator():
25+                self.xml.addQuickElement("object", attrs={"pk" : str(relobj._get_pk_val())})
26+            self.xml.endElement("field")
27+
28     def _start_relational_field(self, field):
29         """
30         Helper to output the <field> element for relational fields
31Index: django/core/serializers/base.py
32===================================================================
33--- django/core/serializers/base.py     (revision 17876)
34+++ django/core/serializers/base.py     (working copy)
35@@ -38,6 +38,10 @@
36         self.selected_fields = options.pop("fields", None)
37         self.use_natural_keys = options.pop("use_natural_keys", False)
38 
39+        self.include_reverse_relations = options.get("include_reverse_relations", False)
40+        if self.options.has_key("include_reverse_relations"):
41+            del self.options["include_reverse_relations"]
42+
43         self.start_serialization()
44         for obj in queryset:
45             self.start_object(obj)
46@@ -56,6 +60,9 @@
47                 if field.serialize:
48                     if self.selected_fields is None or field.attname in self.selected_fields:
49                         self.handle_m2m_field(obj, field)
50+            if self.include_reverse_relations:
51+                for field in concrete_model._meta.get_all_related_objects():
52+                    self.handle_o2m_field(obj, field)
53             self.end_object(obj)
54         self.end_serialization()
55         return self.getvalue()
56@@ -102,6 +109,12 @@
57         """
58         raise NotImplementedError
59 
60+    def handle_o2m_field(self, obj, field):
61+        """
62+        Called to handle a OneToManyField.
63+        """
64+        raise NotImplementedError
65+
66     def getvalue(self):
67         """
68         Return the fully serialized queryset (or None if the output stream is
69Index: django/core/serializers/python.py
70===================================================================
71--- django/core/serializers/python.py   (revision 17876)
72+++ django/core/serializers/python.py   (working copy)
73@@ -7,6 +7,7 @@
74 from django.conf import settings
75 from django.core.serializers import base
76 from django.db import models, DEFAULT_DB_ALIAS
77+from django.db.models.fields.related import OneToOneRel
78 from django.utils.encoding import smart_unicode, is_protected_type
79 
80 class Serializer(base.Serializer):
81@@ -64,6 +65,10 @@
82             self._current[field.name] = [m2m_value(related)
83                                for related in getattr(obj, field.name).iterator()]
84 
85+    def handle_o2m_field(self, obj, field):
86+        if not isinstance(field.field.rel, OneToOneRel):
87+            self._current[field.get_accessor_name()] = [related._get_pk_val() for related in getattr(obj, field.get_accessor_name()).iterator()]
88+
89     def getvalue(self):
90         return self.objects
91