在序列化程序中代表一对一关系的另一面

时间:2018-09-02 17:55:13

标签: django django-rest-framework

我在User模型和UserProfile模型之间建立了一对一的关系。 UserProfile模型包含有关用户的其他信息,并且在保存User模型后立即创建。在UserProfile上设置了OneToOne字段。

当我访问有关UserProfile的任何视图时,序列化的User数据看起来都很好,但是我也希望UserProfile数据出现在User视图中,我想知道如何在UserSerializer中指定它。

编辑:我需要UserProfile数据,以便可以对UserProfile ID进行轻松查找以更改有关User的信息。我将拥有用户ID客户端。理想情况下,我想查找具有该ID的User,找到UserProfile ID(以及其他UserProfile数据),以便随后可以更改与该User相关联的UserProfile的数据。

示例:用户1已通过身份验证。注册后,我收集了一些信息,因此我将视图称为/api/users/1/,该视图告诉我ID为20的用户个人资料与该用户相关联。然后,我可以使用新数据更新该用户个人资料。我不能总是假设用户ID 1与用户个人资料ID 1相关联。

编辑2:解决了类似于安吉拉的答案:

class UserSerializer(serializers.ModelSerializer):
    user_profile = UserProfileSerializer(source="userprofile")

    class Meta:
        model = User
        fields = (
            "id", 
            "username", 
            "email", 
            "first_name",
            "last_name",
            "groups",
            "user_profile"
        )

serializers.py

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = (
            "id", 
            "username", 
            "email", 
            "first_name",
            "last_name",
            "groups"
        )

class UserProfileSerializer(serializers.ModelSerializer):
    user = UserSerializer()
    class Meta:
        model = UserProfile
        fields = (
            "user", 
            "current_city", 
            "current_country"
        )

models.py

class UserProfile(models.Model):
    user = models.OneToOneField(
        User,
        on_delete=models.CASCADE
    )
    avatar = models.FileField(
        upload_to="uploads", 
        blank=True
    )
    age = models.IntegerField(
        null=True
    )
    created_at = models.DateTimeField(
        auto_now_add=True
    )
    current_city = models.CharField(
        max_length=255, 
        blank=True
    )
    current_country = models.CharField(
        max_length=255, 
        blank=True
    )

2 个答案:

答案 0 :(得分:2)

我认为,您应该为此目的使用 两个UserProfileSerializer

#serializer.py
class UserProfileSerializer_Temp(serializers.ModelSerializer):
    class Meta:
        model = UserProfile
        fields = (
            "user",
            "current_city",
            "current_country"
        )


class UserSerializer(serializers.ModelSerializer):
    def __init__(self, *args, **kwargs):
        user_profile = kwargs.pop('user_profile', True)
        super().__init__(*args, **kwargs)
        if user_profile is False:
            self.fields.pop('user_profile', None)

    user_profile = UserProfileSerializer_Temp(source='userprofile_set')

    class Meta:
        model = User
        fields = (
            "id",
            "username",
            "email",
            "first_name",
            "last_name",
            "groups",
            "user_profile"
        )


class UserProfileSerializer_New(UserProfileSerializer_Temp):
    user = UserSerializer(user_profile=False)


#views.py

class UserProfileAPI(ModelViewSet):
    serializer_class = UserProfileSerializer_New
    queryset = UserProfile.objects.all()


class UserAPI(ModelViewSet):
    serializer_class = UserSerializer
    queryset = User.objects.all()


user_profile=False有什么意义?
它就像一个简单的标志。如果我们没有从UserProfileSerializer_New传递类似的信息,它将序列化 UserProfile 两次 。看到这个Screenshot --- image

治愈反应
1。 UserAPI
2。 UserProfileAPI

答案 1 :(得分:0)

因此,要使用户配置文件信息可在用户序列化器中查看,并在用户序列化器中具有用户信息,我建议您按以下方式使用序列化器源争论-

推荐方法

这是基于以下假设:更新用户配置文件时,您不想更新实际用户模型中的任何信息。您可以使用用户端点来做到这一点。

class UserProfileSerializer(serializers.ModelSerializer):
    first_name = serializers.CharField(source='user.first_name',read_only=True)
    last_name = serializers.CharField(source='user.second_name',read_only=True)
    ......  #(other user fields you want to include)
    ......
    ......


   class Meta:
      model = UserProfile
      fields = (
        "first_name",
        "last_name", 
        "current_city", 
        "current_country",
        .......,  # any other user fields
        .......
      )

class UserSerializer(serializers.ModelSerializer):
    user_profile = UserProfileSerializer(partial=True, required=False)

    class Meta:
        model = User
        fields = (
          "id", 
          "username", 
          "email", 
          "first_name",
          "last_name",
          "groups",
          "user_profile"
      ) 

这将为您提供用户对象内的user_profile的嵌套表示形式,其中还将包含源字段,但是您可以选择忽略它。

另一种方法

否则,如果您确实希望在两个序列化程序中都使用嵌套结构,则可以使用不同的序列化程序,但不确定使用情况是什么。

class UserProfileSerializer(serializers.ModelSerializer):

    class Meta:
        model = UserProfile
        fields = (
           "current_city", 
           "current_country",
            .......,  # any other user_profile only fields
            .......
       )

   class UserSerializer(serializers.ModelSerializer):
       user_profile = UserProfileSerializer(partial=True, required=False)
      class Meta:
          model = User
             fields = (
                "id", 
                "username", 
                "email", 
                "first_name",
                "last_name",
                "groups",
                "user_profile"
          )

  class UserSerializerNew(serializers.ModelSerializer):

     class Meta:
        model = User
          fields = (
            "id", 
            "username", 
            "email", 
            "first_name",
            "last_name",
            "groups"
        )

class UserProfileSerializerNew(serializers.ModelSerializer):
    user  = UserSerializerNew(read_only=True)

    class Meta:
        model = UserProfile
        fields = (
            "current_city", 
            "current_country",
            "user"
         )