Python 适当的自定义可写(和可读)ModelSerializer字段

Python 适当的自定义可写(和可读)ModelSerializer字段,python,django-rest-framework,django-serializer,Python,Django Rest Framework,Django Serializer,我在做一个管理学校员工的项目。在我看来,两者之间的关系实现得很差,所以我正在尝试重构它。然而,为了最大限度地减少影响,因为这不是一个优先事项,所以我正在尝试在不破坏前端的情况下做到这一点,前端应该在以后进行重构。当前的Staff模型如下所示: class Staff(models.Model): principal_at = models.ForeignKey(School, null=True) teacher_at = models.ForeignKey(School, nu

我在做一个管理学校员工的项目。在我看来,两者之间的关系实现得很差,所以我正在尝试重构它。然而,为了最大限度地减少影响,因为这不是一个优先事项,所以我正在尝试在不破坏前端的情况下做到这一点,前端应该在以后进行重构。当前的
Staff
模型如下所示:

class Staff(models.Model):
    principal_at = models.ForeignKey(School, null=True)
    teacher_at = models.ForeignKey(School, null=True)
    # I'm only showing these two roles for the sake of simplicity but there are more.
class StaffSerializer(serializers.ModelSerializer):

    class Meta:
        model = Staff
        fields = (
            "principal_at",
            "teacher_at",
            # ...
        )

    # There is also some custom validation to ensure the Staff can only have
    # one role.
我正在将其重构为:

class Staff(models.Model):
    ROLE_CHOICES = (
        "principal",
        "teacher",
        # ...
    )
    school = models.ForeignKey(School)
    role = models.CharField(choices=ROLE_CHOICES)
    # ...

    @property
    def principal_at(self):
        return self.school if self.role == "principal" else None
    # ...
我的
StaffSerializer
如下所示:

class Staff(models.Model):
    principal_at = models.ForeignKey(School, null=True)
    teacher_at = models.ForeignKey(School, null=True)
    # I'm only showing these two roles for the sake of simplicity but there are more.
class StaffSerializer(serializers.ModelSerializer):

    class Meta:
        model = Staff
        fields = (
            "principal_at",
            "teacher_at",
            # ...
        )

    # There is also some custom validation to ensure the Staff can only have
    # one role.
如果我只是保持it不变,则位于的
主体字段将成为一个
只读字段
,并且不会保存,这是有意义的,因为我的模型属性现在是一个属性,而不是实际的可写字段。因此,我将序列化程序更改为:

class StaffSerializer(serializers.ModelSerializer):

    kwargs = {"required": False, "queryset": School.objects.all()}

    principal_at = serializers.PrimaryKeyRelatedField(**kwargs)
    teacher_at = serializers.PrimaryKeyRelatedField(**kwargs)

    class Meta:
        model = Staff
        fields = (
            "principal_at",
            "teacher_at",
            # ...
        )

    def validate(self, data):
        principal_at = data.pop("principal_at", None)
        teacher_at = data.pop("teacher_at", None)
        # ...
        if principal_at:
            data.update(school_id=principal_at, role="principal")
        elif teacher_at:
            data.update(school_id=teacher_at, role="teacher")
        # ...
        return data
现在模型已正确保存(我使用ipdb进行了检查),但在构建响应的过程中,我得到以下结果:

TypeError: Object of type School is not JSON serializable
在这一点之后,我真的不记得我试过什么,但我试过很多东西,但都不管用。我记得有一件事我试过了,当时让我大吃一惊,那就是创建了一个自定义字段并将
重写为_表示法

class RelatedSchoolSerializer(serializers.PrimaryKeyRelatedField):
    def to_representation(self, value):
        import ipdb; ipdb.set_trace()
        return value.pk

class StaffSerializer(serializers.ModelSerializer):

    kwargs = {"required": False, "queryset": School.objects.all()}

    principal_at = serializers.PrimaryKeyRelatedField(**kwargs)
    teacher_at = serializers.PrimaryKeyRelatedField(**kwargs)
    # ...
但是,由于同样的错误,这一直失败,提示我添加一个断点并检查f**k正在发生什么。在调试器内部,我得到了以下结果,这让我非常沮丧:

ipdb> value                                                                                                                                                                                
<rest_framework.relations.PKOnlyObject object at 0x7f9563c87f90>
ipdb> value.pk                                                                                                                                                                             
<School: School 0>
ipdb> value.pk.pk                                                                                                                                                                          
1
ipdb>
ipdb>值
ipdb>value.pk
ipdb>value.pk.pk
1.
ipdb>
如果我返回
value.pk.pk
而不是
value.pk
,则一切正常。但是,即使我的测试套件通过了,我担心这样一个奇怪的黑客可能会在未来产生意想不到的神秘后果。到底发生了什么事?这样做的正确方式是什么