Kaydet (Commit) 74a575eb authored tarafından João Sampaio's avatar João Sampaio Kaydeden (comit) Tim Graham

Fixed #24607 -- Serialized natural keys in multi-table inheritance models.

üst 794f866c
......@@ -88,7 +88,7 @@ class Serializer(object):
if self.selected_fields is None or field.attname in self.selected_fields:
self.handle_field(obj, field)
else:
if self.selected_fields is None or field.attname[:-3] in self.selected_fields:
if self.field_is_selected(field) and self.output_pk_field(obj, field):
self.handle_fk_field(obj, field)
for field in concrete_model._meta.many_to_many:
if field.serialize:
......@@ -101,6 +101,12 @@ class Serializer(object):
self.end_serialization()
return self.getvalue()
def field_is_selected(self, field):
return self.selected_fields is None or field.attname[:-3] in self.selected_fields
def output_pk_field(self, obj, pk_field):
return self.use_natural_primary_keys or pk_field != obj._meta.pk
def start_serialization(self):
"""
Called when serializing of the queryset starts.
......
......@@ -13,6 +13,7 @@ from django.db import connections
from django.db.models import Manager
from django.db.models.fields import AutoField
from django.db.models.fields.proxy import OrderWrt
from django.db.models.fields.related import OneToOneField
from django.utils import six
from django.utils.datastructures import ImmutableList, OrderedSet
from django.utils.deprecation import (
......@@ -296,7 +297,11 @@ class Options(object):
def setup_pk(self, field):
if not self.pk and field.primary_key:
self.pk = field
field.serialize = False
# If the field is a OneToOneField and it's been marked as PK, then
# this is a multi-table inheritance PK. It needs to be serialized
# to relate the subclass instance to the superclass instance.
if not isinstance(field, OneToOneField):
field.serialize = False
def setup_proxy(self, target):
"""
......
from .base import * # NOQA
from .data import * # NOQA
from .multi_table import * # NOQA
from .natural import * # NOQA
from django.db import models
class ParentManager(models.Manager):
def get_by_natural_key(self, parent_data):
return self.get(parent_data=parent_data)
class Parent(models.Model):
parent_data = models.CharField(max_length=30, unique=True)
objects = ParentManager()
def natural_key(self):
return (self.parent_data, )
class Child(Parent):
child_data = models.CharField(max_length=30, unique=True)
class Meta:
manager_inheritance_from_future = True
......@@ -4,7 +4,7 @@ from django.core import serializers
from django.db import connection
from django.test import TestCase
from .models import FKDataNaturalKey, NaturalKeyAnchor
from .models import Child, FKDataNaturalKey, NaturalKeyAnchor
from .tests import register_tests
......@@ -69,6 +69,37 @@ def natural_key_test(format, self):
self.assertIsNone(books[1].object.pk)
def natural_pk_mti_test(format, self):
"""
If serializing objects in a multi-table inheritance relationship using
natural primary keys, the natural foreign key for the parent is output in
the fields of the child so it's possible to relate the child to the parent
when deserializing.
"""
child_1 = Child.objects.create(parent_data='1', child_data='1')
child_2 = Child.objects.create(parent_data='2', child_data='2')
string_data = serializers.serialize(
format,
[child_1.parent_ptr, child_2.parent_ptr, child_2, child_1],
use_natural_foreign_keys=True, use_natural_primary_keys=True,
)
child_1.delete()
child_2.delete()
for obj in serializers.deserialize(format, string_data):
obj.save()
children = Child.objects.all()
self.assertEqual(len(children), 2)
for child in children:
# If it's possible to find the superclass from the subclass and it's
# the correct superclass, it's working.
self.assertEqual(child.child_data, child.parent_data)
# Dynamically register tests for each serializer
register_tests(NaturalKeySerializerTests, 'test_%s_natural_key_serializer', natural_key_serializer_test)
register_tests(NaturalKeySerializerTests, 'test_%s_serializer_natural_keys', natural_key_test)
register_tests(NaturalKeySerializerTests, 'test_%s_serializer_natural_pks_mti', natural_pk_mti_test)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment