DRF 获取 OneToOne 模型的所有字段

DRF Get All Fields of OneToOne Model

我对 DRF 比较陌生,目前遇到了一个问题。经过多次试验,我试着环顾四周,但找不到我想要的东西。如果这个问题已经得到回答,请直接告诉我原来的问题。在此先感谢您的帮助!

问题: 我有一个与用户模型具有一对一关系的配置文件模型。当我创建一个新的用户对象时,配置文件对象会按预期自动创建。我想创建一个 API,这样当我像 api/profile/ 一样执行它时,除了 return 配置文件模型字段外,它还应该 return 用户模型中的所有字段即 first_namelast_nameusernameemail 等...

class Profile(models.Model):
    rater = models.OneToOneField(User, on_delete=models.CASCADE, related_name='approval')
    certified = models.ManyToManyField(Protocol, blank=True, default=None, related_name='trained')
    is_approved = models.BooleanField(default=False)

我的ProfileSerializer如下:

class ProfileSerializer(serializers.ModelSerializer):
    approval = UserSerializer(read_only=True)

    class Meta:
        model = Profile
        fields = '__all__'

当我 运行 API 我得到以下响应:

[
    {
        "id": 1,
        "rater": 3,
        "certified": [],
        "is_approved": false
    }
]

如何获得以下响应:

[
    {
        "id": 1,
        "rater": 3,
        "certified": [],
        "is_approved": false,
        "first_name": xyz,
        "last_name": abc,
        "username": 123,
        "email": abc@gmail.com,
    }
]

尝试将 approval 更改为 rater:

class ProfileSerializer(serializers.ModelSerializer):
    rater = UserSerializer(read_only=True)

    class Meta:
        model = Profile
        fields = '__all__'

这将自动从 Profile 中获取 rater 字段并将其传递给 UserSerializer

这样你最终会得到:

[
    {
        "id": 1,
        "certified": [],
        "is_approved": false,
        "rater": {
            "id": 3,
            "first_name": "xyz",
            "last_name": "abc",
            "username": "123",
            "email": "abc@gmail.com"
        }
    }
]

您可以通过几种方式做到这一点。最好的方法是制作一个包含来自两个模型的字段的序列化程序。您所拥有的很接近,但是因为您的相关字段名称在关系的配置文件端是 rater。 (例如,您使用 profile.rater.email,而不是 profile.approval

您应该使用名称 rater 或指定 source 关键字参数。

class ProfileSerializer(serializers.ModelSerializer):
    approval = UserSerializer(read_only=True, source='rater')
    class Meta:
        model = Profile
        fields = '__all__'

如果您希望结果是扁平的,而不是嵌套的,您可以指定一个 to_representation 方法。

    def to_representation(self, instance):
        # get the usual response as a dictionary
        representation = super().to_representation(instance)
        # pop the nested field and flatten
        user_details = representation.pop('approval')
        representation.update(user_details)
        return representation

您也可以 'cheat' 并完全从 to_representation 方法直接执行此操作,尽管它需要更冗长一点并且您无法从 UserSerializer 中获得所有定义的优势。但如果您没有序列化程序并且出于某种原因不想制作序列化程序,这可能会有用。

   def to_representation(self, instance):
       representation = super().to_representation(instance)
       user = instance.rater
       representation.update({'email': user.email,
                              'first_name', user.first_name,
                              ...
                              })
       return representation