Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/django/core/serializers/python.py: 18%
102 statements
« prev ^ index » next coverage.py v7.0.5, created at 2023-01-17 06:13 +0000
« prev ^ index » next coverage.py v7.0.5, created at 2023-01-17 06:13 +0000
1"""
2A Python "serializer". Doesn't do much serializing per se -- just converts to
3and from basic Python data types (lists, dicts, strings, etc.). Useful as a basis for
4other serializers.
5"""
7from django.apps import apps
8from django.core.serializers import base
9from django.db import DEFAULT_DB_ALIAS, models
10from django.utils.encoding import is_protected_type
13class Serializer(base.Serializer):
14 """
15 Serialize a QuerySet to basic Python objects.
16 """
18 internal_use_only = True
20 def start_serialization(self):
21 self._current = None
22 self.objects = []
24 def end_serialization(self):
25 pass
27 def start_object(self, obj):
28 self._current = {}
30 def end_object(self, obj):
31 self.objects.append(self.get_dump_object(obj))
32 self._current = None
34 def get_dump_object(self, obj):
35 data = {"model": str(obj._meta)}
36 if not self.use_natural_primary_keys or not hasattr(obj, "natural_key"):
37 data["pk"] = self._value_from_field(obj, obj._meta.pk)
38 data["fields"] = self._current
39 return data
41 def _value_from_field(self, obj, field):
42 value = field.value_from_object(obj)
43 # Protected types (i.e., primitives like None, numbers, dates,
44 # and Decimals) are passed through as is. All other values are
45 # converted to string first.
46 return value if is_protected_type(value) else field.value_to_string(obj)
48 def handle_field(self, obj, field):
49 self._current[field.name] = self._value_from_field(obj, field)
51 def handle_fk_field(self, obj, field):
52 if self.use_natural_foreign_keys and hasattr(
53 field.remote_field.model, "natural_key"
54 ):
55 related = getattr(obj, field.name)
56 if related:
57 value = related.natural_key()
58 else:
59 value = None
60 else:
61 value = self._value_from_field(obj, field)
62 self._current[field.name] = value
64 def handle_m2m_field(self, obj, field):
65 if field.remote_field.through._meta.auto_created:
66 if self.use_natural_foreign_keys and hasattr(
67 field.remote_field.model, "natural_key"
68 ):
70 def m2m_value(value):
71 return value.natural_key()
73 def queryset_iterator(obj, field):
74 return getattr(obj, field.name).iterator()
76 else:
78 def m2m_value(value):
79 return self._value_from_field(value, value._meta.pk)
81 def queryset_iterator(obj, field):
82 return getattr(obj, field.name).only("pk").iterator()
84 m2m_iter = getattr(obj, "_prefetched_objects_cache", {}).get(
85 field.name,
86 queryset_iterator(obj, field),
87 )
88 self._current[field.name] = [m2m_value(related) for related in m2m_iter]
90 def getvalue(self):
91 return self.objects
94def Deserializer(
95 object_list, *, using=DEFAULT_DB_ALIAS, ignorenonexistent=False, **options
96):
97 """
98 Deserialize simple Python objects back into Django ORM instances.
100 It's expected that you pass the Python objects themselves (instead of a
101 stream or a string) to the constructor
102 """
103 handle_forward_references = options.pop("handle_forward_references", False)
104 field_names_cache = {} # Model: <list of field_names>
106 for d in object_list:
107 # Look up the model and starting build a dict of data for it.
108 try:
109 Model = _get_model(d["model"])
110 except base.DeserializationError:
111 if ignorenonexistent:
112 continue
113 else:
114 raise
115 data = {}
116 if "pk" in d:
117 try:
118 data[Model._meta.pk.attname] = Model._meta.pk.to_python(d.get("pk"))
119 except Exception as e:
120 raise base.DeserializationError.WithData(
121 e, d["model"], d.get("pk"), None
122 )
123 m2m_data = {}
124 deferred_fields = {}
126 if Model not in field_names_cache:
127 field_names_cache[Model] = {f.name for f in Model._meta.get_fields()}
128 field_names = field_names_cache[Model]
130 # Handle each field
131 for (field_name, field_value) in d["fields"].items():
133 if ignorenonexistent and field_name not in field_names:
134 # skip fields no longer on model
135 continue
137 field = Model._meta.get_field(field_name)
139 # Handle M2M relations
140 if field.remote_field and isinstance(
141 field.remote_field, models.ManyToManyRel
142 ):
143 try:
144 values = base.deserialize_m2m_values(
145 field, field_value, using, handle_forward_references
146 )
147 except base.M2MDeserializationError as e:
148 raise base.DeserializationError.WithData(
149 e.original_exc, d["model"], d.get("pk"), e.pk
150 )
151 if values == base.DEFER_FIELD:
152 deferred_fields[field] = field_value
153 else:
154 m2m_data[field.name] = values
155 # Handle FK fields
156 elif field.remote_field and isinstance(
157 field.remote_field, models.ManyToOneRel
158 ):
159 try:
160 value = base.deserialize_fk_value(
161 field, field_value, using, handle_forward_references
162 )
163 except Exception as e:
164 raise base.DeserializationError.WithData(
165 e, d["model"], d.get("pk"), field_value
166 )
167 if value == base.DEFER_FIELD:
168 deferred_fields[field] = field_value
169 else:
170 data[field.attname] = value
171 # Handle all other fields
172 else:
173 try:
174 data[field.name] = field.to_python(field_value)
175 except Exception as e:
176 raise base.DeserializationError.WithData(
177 e, d["model"], d.get("pk"), field_value
178 )
180 obj = base.build_instance(Model, data, using)
181 yield base.DeserializedObject(obj, m2m_data, deferred_fields)
184def _get_model(model_identifier):
185 """Look up a model from an "app_label.model_name" string."""
186 try:
187 return apps.get_model(model_identifier)
188 except (LookupError, TypeError):
189 raise base.DeserializationError(
190 "Invalid model identifier: '%s'" % model_identifier
191 )