Skip to content

Commit

Permalink
Restore all ptr_id attributes with multi table inheritance
Browse files Browse the repository at this point in the history
A model/table with multi table inheritance has field_ptr_id for the relationship to the parent model - this should be restored when deserializing.
  • Loading branch information
tomkins authored and gasman committed Oct 13, 2021
1 parent 73ed0ef commit 5b05baf
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 4 deletions.
9 changes: 7 additions & 2 deletions modelcluster/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,16 @@ def get_serializable_data_for_fields(model):

def model_from_serializable_data(model, data, check_fks=True, strict_fks=False):
pk_field = model._meta.pk
# If model is a child via multitable inheritance, use parent's pk
kwargs = {}

# If model is a child via multitable inheritance, we need to set ptr_id fields all the way up
# to the main PK field, as Django won't populate these for us automatically.
while pk_field.remote_field and pk_field.remote_field.parent_link:
kwargs[pk_field.attname] = data['pk']
pk_field = pk_field.remote_field.model._meta.pk

kwargs = {pk_field.attname: data['pk']}
kwargs[pk_field.attname] = data['pk']

for field_name, field_value in data.items():
try:
field = model._meta.get_field(field_name)
Expand Down
13 changes: 11 additions & 2 deletions tests/tests/test_serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from django.test import TestCase
from django.utils import timezone

from tests.models import Band, BandMember, Album, Restaurant, Dish, MenuItem, Chef, Wine, \
Review, Log, Document, Article, Author, Category
from tests.models import Band, BandMember, Album, Place, Restaurant, SeafoodRestaurant, Dish, \
MenuItem, Chef, Wine, Review, Log, Document, Article, Author, Category


class SerializeTest(TestCase):
Expand Down Expand Up @@ -112,6 +112,15 @@ def test_deserialize_with_multi_table_inheritance(self):
self.assertEqual(fat_duck.serves_hot_dogs, False)
self.assertEqual(fat_duck.reviews.all()[0].author, "Michael Winner")

def test_deserialize_with_second_level_multi_table_inheritance(self):
oyster_club = SeafoodRestaurant.from_json('{"pk": 43, "name": "The Oyster Club"}')
self.assertEqual(oyster_club.id, 43)
self.assertEqual(oyster_club.restaurant_ptr_id, 43)
self.assertEqual(oyster_club.place_ptr_id, 43)
self.assertEqual(oyster_club.restaurant_ptr.__class__, Restaurant)
self.assertEqual(oyster_club.place_ptr.__class__, Place)
self.assertEqual(oyster_club.name, "The Oyster Club")

def test_dangling_foreign_keys(self):
heston_blumenthal = Chef.objects.create(name="Heston Blumenthal")
snail_ice_cream = Dish.objects.create(name="Snail ice cream")
Expand Down

0 comments on commit 5b05baf

Please sign in to comment.