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

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""" 

6 

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 

11 

12 

13class Serializer(base.Serializer): 

14 """ 

15 Serialize a QuerySet to basic Python objects. 

16 """ 

17 

18 internal_use_only = True 

19 

20 def start_serialization(self): 

21 self._current = None 

22 self.objects = [] 

23 

24 def end_serialization(self): 

25 pass 

26 

27 def start_object(self, obj): 

28 self._current = {} 

29 

30 def end_object(self, obj): 

31 self.objects.append(self.get_dump_object(obj)) 

32 self._current = None 

33 

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 

40 

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) 

47 

48 def handle_field(self, obj, field): 

49 self._current[field.name] = self._value_from_field(obj, field) 

50 

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 

63 

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 ): 

69 

70 def m2m_value(value): 

71 return value.natural_key() 

72 

73 def queryset_iterator(obj, field): 

74 return getattr(obj, field.name).iterator() 

75 

76 else: 

77 

78 def m2m_value(value): 

79 return self._value_from_field(value, value._meta.pk) 

80 

81 def queryset_iterator(obj, field): 

82 return getattr(obj, field.name).only("pk").iterator() 

83 

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] 

89 

90 def getvalue(self): 

91 return self.objects 

92 

93 

94def Deserializer( 

95 object_list, *, using=DEFAULT_DB_ALIAS, ignorenonexistent=False, **options 

96): 

97 """ 

98 Deserialize simple Python objects back into Django ORM instances. 

99 

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> 

105 

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 = {} 

125 

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] 

129 

130 # Handle each field 

131 for (field_name, field_value) in d["fields"].items(): 

132 

133 if ignorenonexistent and field_name not in field_names: 

134 # skip fields no longer on model 

135 continue 

136 

137 field = Model._meta.get_field(field_name) 

138 

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 ) 

179 

180 obj = base.build_instance(Model, data, using) 

181 yield base.DeserializedObject(obj, m2m_data, deferred_fields) 

182 

183 

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 )