Django休息框架序列化器与反向关系

时间:2018-03-21 19:23:55

标签: python django django-models django-rest-framework django-related-manager

我有两个模型employeeperson模型有关,但personemployee模型无关。

像:

class Person(models.Model):
    name = models.CharField(max_length=100)
    address = models.CharField(max_length=100)

class Employee(models.Model):
    person = models.ForeignKey(Person, related_name='person_info')
    code = models.CharField()

在这种情况下,我希望{cn}字段数据中的code字段数据。

我可以通过个人模型中的编写方法或使用 SerializerMethodField 亲自序列化器来解决这个问题

像这样:

def get_employee_code(self):
    return Employee.objects.get(person=self).id

并将其添加为人员序列化程序中的源

employee_code = serializers.CharField(source='get_employee_code')

或将员工序列化程序添加到人员序列化程序

class PersonSerializer(serializers.ModelSerializer):
    employee = EmployeeSerializer()
    class Meta:
        model = Person
        fields = ('name', 'address', 'employee')

但我试图用反向关系来做这件事,但我做不到。我试过这样,它给出了一个错误

串行器:

class PersonSerializer(serializers.ModelSerializer):
    employee_code = serializers.CharField(source='person_info.code')
    class Meta:
        model = Person
        fields = ('name', 'address', 'employee_code')

我如何用反向关系解决这个问题?

2 个答案:

答案 0 :(得分:6)

目前因为你在person属性上使用ForeignKey字段,这意味着当你访问反向关系时它会返回一个列表。

一种解决方案是使用与slug相关的字段,但必须将manyread_only设置为True,并且由于ForeignKey字段将返回一个列表。

class PersonSerializer(serializers.ModelSerializer):
    employee_code = serializers.SlugRelatedField(
        source='person_info',
        slug_field='code',
        many=True,
        read_only=True,
    )

    class Meta:
        model = Person
        fields = ('name', 'address', 'employee_code')

另一个选项是将您的ForeignKey更改为OneToOneField,它仍然需要read_only设置为True但不会返回列表。

class Person(models.Model):
    name = models.CharField(max_length=100)
    address = models.CharField(max_length=100)

class Employee(models.Model):
    person = models.OneToOneField(Person, related_name='person_info')
    code = models.CharField()

class PersonSerializer(serializers.ModelSerializer):
    employee_code = serializers.SlugRelatedField(
        source='person_info',
        slug_field='code',
        read_only=True,
    )

    class Meta:
        model = Person
        fields = ('name', 'address', 'employee_code')

或者,如果您不想更改ForeignKey,则可以向模型添加employee_code属性方法,而不是返回person_info关系中的第一个员工代码。

class Person(models.Model):
    name = models.CharField(max_length=100)
    address = models.CharField(max_length=100)

    @property
    def employee_code(self):
        employees = self.person_info.filter()
        if employees.exists():
            return employees.first().code
        return ''

class Employee(models.Model):
    person = models.OneToOneField(Person, related_name='person_info')
    code = models.CharField()

class PersonSerializer(serializers.ModelSerializer):
    employee_code = serializers.CharField(
        read_only=True,
    )

    class Meta:
        model = Person
        fields = ('name', 'address', 'employee_code')

答案 1 :(得分:0)

您可以使用自定义 SerializerMethodField()

访问反向关系
class PersonSerializer(serializers.ModelSerializer):
    employee_code = serializers.SerializerMethodField()

    def get_employee_code(self, obj):
        return obj.person_info.code

    class Meta:
        model = Person
        fields = ('name', 'address', 'employee_code')