我以稍微不同的方式解决了这个问题。
使用:
- DRF 3.5.x
- django-model-utils 2.5.x
我的models.py 看起来像这样:
class Person(models.Model):
first_name = models.CharField(max_length=40, blank=False, null=False)
middle_name = models.CharField(max_length=80, blank=True, null=True)
last_name = models.CharField(max_length=80, blank=False, null=False)
family = models.ForeignKey(Family, blank=True, null=True)
class Clergy(Person):
category = models.IntegerField(choices=CATEGORY, blank=True, null=True)
external = models.NullBooleanField(default=False, null=True)
clergy_status = models.ForeignKey(ClergyStatus, related_name="%(class)s_status", blank=True, null=True)
class Religious(Person):
religious_order = models.ForeignKey(ReligiousOrder, blank=True, null=True)
major_superior = models.ForeignKey(Person, blank=True, null=True, related_name="%(class)s_superior")
class ReligiousOrder(models.Model):
name = models.CharField(max_length=255, blank=False, null=False)
initials = models.CharField(max_length=20, blank=False, null=False)
class ClergyStatus(models.Model):
display_name = models.CharField(max_length=255, blank=True, null=True)
description = models.CharField(max_length=255, blank=True, null=True)
基本上 - 基本模型是“人”模型 - 一个人可以是神职人员、宗教人士,或者两者都不是,而只是一个“人”。而继承Person的模型也有特殊关系。
在我的 views.py 中,我使用 mixin 将子类“注入”到查询集中,如下所示:
class PersonSubClassFieldsMixin(object):
def get_queryset(self):
return Person.objects.select_subclasses()
class RetrievePersonAPIView(PersonSubClassFieldsMixin, generics.RetrieveDestroyAPIView):
serializer_class = PersonListSerializer
...
然后真正的“unDRY”部分出现在 serializers.py 中,我在其中声明了“base”PersonListSerializer,但覆盖了 to_representation 方法以根据实例类型返回特殊的 serailzer,如下所示:
class PersonListSerializer(serializers.ModelSerializer):
def to_representation(self, instance):
if isinstance(instance, Clergy):
return ClergySerializer(instance=instance).data
elif isinstance(instance, Religious):
return ReligiousSerializer(instance=instance).data
else:
return LaySerializer(instance=instance).data
class Meta:
model = Person
fields = '__all__'
class ReligiousSerializer(serializers.ModelSerializer):
class Meta:
model = Religious
fields = '__all__'
depth = 2
class LaySerializer(serializers.ModelSerializer):
class Meta:
model = Person
fields = '__all__'
class ClergySerializer(serializers.ModelSerializer):
class Meta:
model = Clergy
fields = '__all__'
depth = 2
“切换”发生在主序列化程序 (PersonListSerializer) 的 to_representation 方法中。它查看实例类型,然后“注入”所需的序列化程序。由于Clergy、Religious 都是从Person 继承的,返回一个Person 也是Clergy 成员,返回所有Person 字段和所有Clergy 字段。 Religious 也是如此。如果Person 既不是Clergy 也不是Religious - 仅返回基本模型字段。
不确定这是否是正确的方法 - 但它看起来非常灵活,适合我的用例。请注意,我通过不同的视图/序列化程序保存/更新/创建 Person - 所以我不必担心这种类型的设置。