【问题标题】:Django serializer - unable to pass correct data in Many to Many relation with nested serializersDjango 序列化程序 - 无法在与嵌套序列化程序的多对多关系中传递正确的数据
【发布时间】:2018-06-30 03:22:48
【问题描述】:

我正在努力解决这个问题:

用户可以在他的个人资料中添加技能,其他用户可以在他的个人资料中为该技能投票。

我已经在系统中实现了添加技能。 现在接下来我正在尝试构建添加一项技能(管理员已在系统中添加)以添加到用户配置文件中。

但在我的 POST API 中,我总是收到以下错误

{
    "user": {
        "user": [
            "This field is required."
        ]
    }
}

身体输入:

{
    "user":{
         "username": "USERN",
         "email": "diahu@gail.com",
         "first_name": "",
          "last_name": ""
    },
    "new_user_skill":
        {
             "id": 1,
             "skill_name": "C"
        }
}

我的观点:

 elif request.method == 'POST':
        data = { 'user':request.data.get('user'),'skill_item':request.data.get('new_user_skill')}
        serializer = UserSkillSerializer(data=data)
        print("-------------------> serializer ")
        print(serializer)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)  

型号:

class UserModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('username', 'first_name', 'last_name', 'email')
        extra_kwargs = {
            'username': {
                'validators': [],
            }
        }    


class UserProfileSerializer(serializers.ModelSerializer):
    user=UserModelSerializer()
    class Meta:
        model = UserProfile
        fields = '__all__'

        def create(self, validated_data):

            user_serializer = UserModelSerializer.create(UserModelSerializer(),validated_data = validated_data)
            user,created=UserProfile.objects.update_or_create(user=user_serializer)
            return user

class UserSkillSerializer(serializers.ModelSerializer):

    user = UserProfileSerializer(required=True)
    skill_item = SkillSerializer(required=True)
    class Meta:
        model = UserSkill
        fields= '__all__'

    def create (self,validated_data):

        user_data = validated_data.pop('user')
        user = UserProfileSerializer.create(UserProfileSerializer(),validated_data= user_data)
        skill_data = validated_data.pop('skill_item')
        skill_item   = SkillSerializer.create(SkillSerializer(),validated_data=skill_data)
        user_skill, created = UserSkill.objects.update_or_create(user=user,skill_item=skill_item)

        return user_skill

序列化器:

class SkillSerializer(serializers.ModelSerializer):

    class Meta:
        model = Skill
        fields = '__all__'
        extra_kwargs = {
            'skill_name': {
                'validators': [],
            }
        }  

class UserModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('username', 'first_name', 'last_name', 'email')
        extra_kwargs = {
            'username': {
                'validators': [],
            }
        }    


class UserProfileSerializer(serializers.ModelSerializer):
    user=UserModelSerializer()
    class Meta:
        model = UserProfile
        fields = '__all__'

        def create(self, validated_data):

            user_serializer = UserModelSerializer.create(UserModelSerializer(),validated_data = validated_data)
            user,created=UserProfile.objects.update_or_create(user=user_serializer)
            return user

class UserSkillSerializer(serializers.ModelSerializer):

    user = UserProfileSerializer(required=True)
    skill_item = SkillSerializer(required=True)
    class Meta:
        model = UserSkill
        fields= '__all__'

    def create (self,validated_data):

        user_data = validated_data.pop('user')
        user = UserProfileSerializer.create(UserProfileSerializer(),validated_data= user_data)
        skill_data = validated_data.pop('skill_item')
        skill_item   = SkillSerializer.create(SkillSerializer(),validated_data=skill_data)
        user_skill, created = UserSkill.objects.update_or_create(user=user,skill_item=skill_item)

        return user_skill

我已经删除了验证器(不确定这是否正确)

编辑 1

我已经根据答案编辑了我的大部分代码(我已经研究并实现了反向关系),即使我有 null=True

也面临一个 Not Null 约束

我的更新代码:

序列化器:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('username', 'first_name', 'last_name', 'email','user_profile')


class UserSkillSerializer(serializers.ModelSerializer):

    user = serializers.PrimaryKeyRelatedField(read_only=True)
    skill_item = serializers.PrimaryKeyRelatedField(read_only=True)
    class Meta:
        model = UserSkill
        fields= ('user', 'skill_item')

观看次数:

elif request.method == 'POST':

    current_user = User.objects.get(pk=request.data.get('user')) # get the user key
    user_profile_id = current_user.user_profile.pk # get the user profile from reverse relation in model
    data = { 'user':user_profile_id,'skill_item':request.data.get('skill_id')}
    serializer = UserSkillSerializer(data=data)
    if serializer.is_valid():
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)            

型号:

# This class will more or less map to a table in the database and defines the many to many relationship between user-skill, this is our intermediate model
class UserSkill(models.Model):
    """ A Model for representing skill in user profile """
    unique_together = (('user', 'skill_item'),)

    user = models.ForeignKey('UserProfile',on_delete=models.CASCADE,related_name='current_user_skills')

    skill_item = models.ForeignKey(Skill,on_delete=models.CASCADE,null=True)

    def __str__(self):
        """Return a human readable representation of the model instance."""
        return "{}".format(self.skill_item.skill_name)

# this class adds a Many to Many field in existing django-rest auth UserProfile class for  user and his/her skills 
class UserProfile(models.Model):
    user = models.OneToOneField('auth.User',unique=True,on_delete=models.CASCADE,related_name='user_profile')
    user_skills = models.ManyToManyField(
            Skill,
            through='UserSkill',
            through_fields=('user','skill_item'),null=True
        )
#create user profile signal handler
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)

post_save.connect(create_user_profile, sender=User)

错误:

return func(*args, **kwargs)   File "C:\code\django\wantedly\src\wantedly_webapp\views\AllViews.py", line

61,在 user_skill_collection 中 serializer.save()

IntegrityError at /api/v1/user/skills/ NOT NULL 约束失败: Wantly_webapp_userskill.skill_item_id

【问题讨论】:

    标签: django serialization django-rest-framework


    【解决方案1】:

    产生此错误是因为UserProfileSerializer 有一个需要完整用户定义的user 字段。一般来说,我相信您在序列化程序中混合了“用户配置文件”/“用户”的概念,这会造成混淆。

    创建User 及其关联的UserProfileSkill 后,将Skill 添加到UserProfile 的方法是通过主键选择它们:

    class UserSkillSerializer(serializers.ModelSerializer):
    
        user = serializers.PrimaryKeyRelatedField()
        skill_item = serializers.PrimaryKeyRelatedField()
    
        class Meta:
            model = UserSkill
            fields= ('user', 'skill_item')
    

    Skill 分配给UserProfile 的POST 数据将是:

    {
        "user": 3,  # PK of the UserProfile, not the User!
        "skill_item": 42  # PK of the SkillItem you want to assign
    }
    

    【讨论】:

    • 这是一个很好的解决方案。我可以想象我应该在创建新用户后立即创建一个 UserProfile。我不知道该怎么做,因为我还在学习序列化程序。其次,对于这个 api,我怎样才能得到 UserProfile 的 pk ?我正在使用 django rest-auth
    • 您可以为使用信号处理程序自动创建的每个新用户创建配置文件,例如:stackoverflow.com/questions/11488974/… 要获取 UserProfile 的 pk,您可以将字段添加到 @987654335 @ 显示其个人资料的 id。见django-rest-framework.org/api-guide/relations/…
    • 我刚刚了解了反向关系并实现了它。我能够获取 UserProfile id 并在创建新用户时创建用户配置文件,但现在我面临完整性约束。请检查我的编辑 - 1
    猜你喜欢
    • 2022-12-12
    • 2017-06-28
    • 1970-01-01
    • 1970-01-01
    • 2016-07-30
    • 2018-07-07
    • 1970-01-01
    • 1970-01-01
    • 2018-10-26
    相关资源
    最近更新 更多