Ticket #13252: 13252.3.diff
File 13252.3.diff, 8.8 KB (added by , 14 years ago) |
---|
-
django/core/serializers/base.py
diff --git a/django/core/serializers/base.py b/django/core/serializers/base.py index 190636e..9f535e3 100644
a b class DeserializedObject(object): 170 170 # prevent a second (possibly accidental) call to save() from saving 171 171 # the m2m data twice. 172 172 self.m2m_data = None 173 174 def build_instance(Model, data, db): 175 """ 176 Build a model instance. 177 178 If the model instance doesn't have a primary key and the model supports 179 natural keys, try to retrieve it from the database. 180 """ 181 obj = Model(**data) 182 if obj.pk is None and hasattr(Model, 'natural_key') and\ 183 hasattr(Model._default_manager, 'get_by_natural_key'): 184 pk = obj.natural_key() 185 try: 186 obj.pk = Model._default_manager.db_manager(db)\ 187 .get_by_natural_key(*pk).pk 188 except Model.DoesNotExist: 189 pass 190 return obj -
django/core/serializers/python.py
diff --git a/django/core/serializers/python.py b/django/core/serializers/python.py index a68ea21..839fee1 100644
a b class Serializer(base.Serializer): 27 27 self._current = {} 28 28 29 29 def end_object(self, obj): 30 self.objects.append({ 31 "model" : smart_unicode(obj._meta), 32 "pk" : smart_unicode(obj._get_pk_val(), strings_only=True), 33 "fields" : self._current 34 }) 30 data = { 31 "model": smart_unicode(obj._meta), 32 "fields": self._current 33 } 34 if not self.use_natural_keys or not hasattr(obj, 'natural_key'): 35 data['pk'] = smart_unicode(obj._get_pk_val(), strings_only=True) 36 self.objects.append(data) 35 37 self._current = None 36 38 37 39 def handle_field(self, obj, field): … … def Deserializer(object_list, **options): 82 84 for d in object_list: 83 85 # Look up the model and starting build a dict of data for it. 84 86 Model = _get_model(d["model"]) 85 data = {Model._meta.pk.attname : Model._meta.pk.to_python(d["pk"])} 87 data = {} 88 if 'pk' in d: 89 data[Model._meta.pk.attname] = Model._meta.pk.to_python(d['pk']) 86 90 m2m_data = {} 87 91 88 92 # Handle each field … … def Deserializer(object_list, **options): 127 131 else: 128 132 data[field.name] = field.to_python(field_value) 129 133 130 yield base.DeserializedObject(Model(**data), m2m_data) 134 obj = base.build_instance(Model, data, db) 135 136 yield base.DeserializedObject(obj, m2m_data) 131 137 132 138 def _get_model(model_identifier): 133 139 """ -
django/core/serializers/xml_serializer.py
diff --git a/django/core/serializers/xml_serializer.py b/django/core/serializers/xml_serializer.py index 5fef3b6..4fcb400 100644
a b class Serializer(base.Serializer): 42 42 raise base.SerializationError("Non-model object (%s) encountered during serialization" % type(obj)) 43 43 44 44 self.indent(1) 45 self.xml.startElement("object", {46 "pk" : smart_unicode(obj._get_pk_val()),47 "model" : smart_unicode(obj._meta),48 })45 object_data = {"model": smart_unicode(obj._meta)} 46 if not self.use_natural_keys or not hasattr(obj, 'natural_key'): 47 object_data['pk'] = smart_unicode(obj._get_pk_val()) 48 self.xml.startElement("object", object_data) 49 49 50 50 def end_object(self, obj): 51 51 """ … … class Deserializer(base.Deserializer): 166 166 # bail. 167 167 Model = self._get_model_from_node(node, "model") 168 168 169 # Start building a data dictionary from the object. If the node is 170 # missing the pk attribute, bail. 171 pk = node.getAttribute("pk") 172 if not pk: 173 raise base.DeserializationError("<object> node is missing the 'pk' attribute") 174 175 data = {Model._meta.pk.attname : Model._meta.pk.to_python(pk)} 169 # Start building a data dictionary from the object. 170 data = {} 171 if node.hasAttribute('pk'): 172 data[Model._meta.pk.attname] = Model._meta.pk.to_python( 173 node.getAttribute('pk')) 176 174 177 175 # Also start building a dict of m2m data (this is saved as 178 176 # {m2m_accessor_attribute : [list_of_related_objects]}) … … class Deserializer(base.Deserializer): 203 201 value = field.to_python(getInnerText(field_node).strip()) 204 202 data[field.name] = value 205 203 204 obj = base.build_instance(Model, data, self.db) 205 206 206 # Return a DeserializedObject so that the m2m data has a place to live. 207 return base.DeserializedObject( Model(**data), m2m_data)207 return base.DeserializedObject(obj, m2m_data) 208 208 209 209 def _handle_fk_field_node(self, node, field): 210 210 """ -
docs/topics/serialization.txt
diff --git a/docs/topics/serialization.txt b/docs/topics/serialization.txt index 1cf8e86..475035c 100644
a b into the primary key of an actual ``Person`` object. 313 313 fields will be effectively unique, you can still use those fields 314 314 as a natural key. 315 315 316 .. versionadded:: 1.3 317 318 Deserialization of objects with no primary key will always check whether the 319 model's manager has a ``get_by_natural_key()`` method and if so, use it to 320 populate the deserialized object's primary key. 321 316 322 Serialization of natural keys 317 323 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 318 324 … … use the `--natural` command line flag to generate natural keys. 359 365 natural keys during serialization, but *not* be able to load those 360 366 key values, just don't define the ``get_by_natural_key()`` method. 361 367 368 .. versionadded:: 1.3 369 370 When ``use_natural_keys=True`` is specified, the primary key is no longer 371 provided in the serialized data of this object since it can be calculated 372 during deserialization:: 373 374 ... 375 { 376 "model": "store.person", 377 "fields": { 378 "first_name": "Douglas", 379 "last_name": "Adams", 380 "birth_date": "1952-03-11", 381 } 382 } 383 ... 384 362 385 Dependencies during serialization 363 386 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 364 387 -
tests/regressiontests/serializers_regress/models.py
diff --git a/tests/regressiontests/serializers_regress/models.py b/tests/regressiontests/serializers_regress/models.py index bec0a98..32c55c0 100644
a b class LengthModel(models.Model): 264 264 265 265 def __len__(self): 266 266 return self.data 267 268 #Tests for natural keys. 269 class BookManager(models.Manager): 270 def get_by_natural_key(self, isbn13): 271 return self.get(isbn13=isbn13) 272 273 class Book(models.Model): 274 isbn13 = models.CharField(max_length=14) 275 title = models.CharField(max_length=100) 276 277 objects = BookManager() 278 279 def natural_key(self): 280 return (self.isbn13,) -
tests/regressiontests/serializers_regress/tests.py
diff --git a/tests/regressiontests/serializers_regress/tests.py b/tests/regressiontests/serializers_regress/tests.py index be920c6..a67f429 100644
a b def streamTest(format, self): 414 414 self.assertEqual(string_data, stream.getvalue()) 415 415 stream.close() 416 416 417 def naturalKeyTest(format, self): 418 book1 = {'isbn13': '978-1590597255', 'title': 'The Definitive Guide to ' 419 'Django: Web Development Done Right'} 420 book2 = {'isbn13':'978-1590599969', 'title': 'Practical Django Projects'} 421 422 # Create the books. 423 adrian = Book.objects.create(**book1) 424 james = Book.objects.create(**book2) 425 426 # Serialize the books. 427 string_data = serializers.serialize(format, Book.objects.all(), indent=2, 428 use_natural_keys=True) 429 430 # Delete one book (to prove that the natural key generation will only 431 # restore the primary keys of books found in the database via the 432 # get_natural_key manager method). 433 james.delete() 434 435 # Deserialize and test. 436 books = list(serializers.deserialize(format, string_data)) 437 self.assertEqual(len(books), 2) 438 self.assertEqual(books[0].object.title, book1['title']) 439 self.assertEqual(books[0].object.pk, adrian.pk) 440 self.assertEqual(books[1].object.title, book2['title']) 441 self.assertEqual(books[1].object.pk, None) 442 417 443 for format in serializers.get_serializer_formats(): 418 444 setattr(SerializerTests, 'test_' + format + '_serializer', curry(serializerTest, format)) 419 445 setattr(SerializerTests, 'test_' + format + '_serializer_fields', curry(fieldsTest, format)) 446 setattr(SerializerTests, 'test_' + format + '_serializer_natural_key', 447 curry(naturalKeyTest, format)) 420 448 if format != 'python': 421 449 setattr(SerializerTests, 'test_' + format + '_serializer_stream', curry(streamTest, format))