首页 文章

相关对象序列化器Django restframework

提问于
浏览
0

我的问题与this one有些相关,但存在一些差异 . 我有一个类似于这个的模型:

class Project(models.Model):
    project_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True)
    created_by_id = models.ForeignKey('auth.User', related_name='project', on_delete=models.SET_NULL, blank=True, null=True)
    created_by = models.CharField(max_length=255, default="unknown")
    created = models.DateTimeField(auto_now_add=True)

使用以下序列化程序:

class ProjectSerializer(serializers.ModelSerializer):

    created_by = serializers.ReadOnlyField(source='created_by_id.username')

    class Meta:
        model = Project
        fields = ('project_id', 'created_by', 'created')

和相应的观点:

class projectsView(mixins.ListModelMixin,
                  mixins.CreateModelMixin,
                  generics.GenericAPIView):
    queryset = Project.objects.all()
    serializer_class = ProjectSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

    def perform_create(self, serializer):
        serializer.save(created_by_id=self.request.user)

此代码的行为与我想要的一样,但强制信息冗余,并且不利用底层关系数据库 . 我试图使用链接问题中的信息来实现“在数据库上写入用户ID,但在平面json中返回用户名”get“”但没有成功:

删除模型中的“created_by”字段 . 用以下代替序列化器:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User


class ProjectSerializer(serializers.ModelSerializer):

    created_by = UserSerializer(read_only=True)
    created_by_id = serializers.PrimaryKeyRelatedField(
    queryset=User.objects.all(), source='created_by', write_only=True)

    class Meta:
        model = Project
        fields = ('project_id', 'created_by', 'created_by_id', 'created')

哪个不会100%给我我想要的东西,即用平面json中的用户名替换用户ID但返回类似的内容: {'project_id': <uuid>, 'created_by': <user json object>, 'created': <data>} . 但我仍然得到一个 {'created_by_id': ['This field is required.']} 400错误 .

问题:如何从request.user信息向数据库对象写入用户id以引用实际用户ID,但在projectsView endpoints 上的GET请求中返回一个简单的用户名,而不在模型中明确存储用户名?或者更一般地说,如何使用默认的序列化DRF功能和默认的DRF视图mixins将数据库对象(Django模型)序列化为客户json响应?

问题的替代公式:如何将ID引用存储到我的模型中的另一个DB记录(可以在没有由有效负载提供的情况下访问),但是在序列化程序级别从该对象引用反序列化派生信息,例如一个特定的引用对象的字段?

2 回答

  • 0

    我建议你使用 Two different serializers 进行 GetPOST 操作 . 将你的_1547422改为

    class ProjectGetSerializer(serializers.ModelSerializer):
        created_by_id = serializers.StringRelatedField()
    
        class Meta:
            model = Project
            fields = '__all__'
    
    
    class ProjectCreateSerializer(serializers.ModelSerializer):
        created_by_id = serializers.PrimaryKeyRelatedField(queryset=User.objects.all(), default=serializers.CurrentUserDefault())
    
        def create(self, validated_data):
            return Project.objects.create(**validated_data, created_by=validated_data['created_by_id'].username)
    
        class Meta:
            model = Project
            fields = '__all__'
    

    另外,如果您正在寻找CRUD operations,我会推荐API类的ModelViewSet . 因此,视图将是这样的,

    class projectsView(viewsets.ModelViewSet):
        queryset = Project.objects.all()
    
        def get_serializer_class(self):
            if self.action == 'create':
                return ProjectCreateSerializer
            return ProjectGetSerializer
    

    那么,创建 Project 的有效负载是,

    {
    }
    

    您应该记住的一件事,当您尝试创建 Project 用户时必须登录

    UPDATE - 1
    serializer.py

    class ProjectCreateSerializer(serializers.ModelSerializer):
        created_by_id = serializers.StringRelatedField()
    
        class Meta:
            model = Project
            fields = '__all__'
    
        def create(self, validated_data):
            return Project.objects.create(**validated_data, created_by_id=self.context['request'].user)
    

    views.py

    class projectsView(viewsets.ModelViewSet):
        queryset = Project.objects.all()
        serializer_class = ProjectCreateSerializer
    
  • 0

    该错误位于write_only字段选项中 . required 参数默认值设置为 True ,而目的是在我们查看模型时不要求它 . 在视图中,我使用perform_create作为后处理来保存Model DB表示 . 由于 required 默认值在创建级别为 True ,因此数据库的第一个 .save() 失败 . 由于这纯粹是内部逻辑,因此不需要 . 所以只需在 PrimaryKeyRelatedField 上添加 required=False 选项即可完成工作:

    class UserSerializer(serializers.ModelSerializer):
        class Meta:
            model = User
    
    
    class ProjectSerializer(serializers.ModelSerializer):
    
        created_by = UserSerializer(read_only=True)
        created_by_id = serializers.PrimaryKeyRelatedField(
        queryset=User.objects.all(), source='created_by', write_only=True, required=False)
    
        class Meta:
            model = Project
            fields = ('project_id', 'created_by', 'created_by_id', 'created')
    

    如果我坚持纯粹在串行器级别使用逻辑进行反序列化,那么在模型级强制执行required = True也需要覆盖串行器的.save函数 . 可能有一种方法可以在序列化程序中获取用户参考,以使视图实现更加'default' ...这可以通过使用Jerin中的默认值来完成:

    class ProjectSerializer(serializers.ModelSerializer):
    
        created_by = UserSerializer(read_only=True)
        created_by_id = serializers.PrimaryKeyRelatedField(
        queryset=User.objects.all(), source='created_by', 
                               write_only=True,
                               required=False,
                               default=serializers.CurrentUserDefault())
    
        class Meta:
            model = Project
            fields = ('project_id', 'created_by', 'created_by_id', 'created')
    

    现在只使用用户名来展开json,你需要使用一个slug字段而不是UserSerializer:

    class ProjectSerializer(serializers.ModelSerializer):
    
        created_by = serializers.SlugRelatedField(
          queryset=User.objects.all(), slug_field="username")
        created_by_id = serializers.PrimaryKeyRelatedField(
          queryset=User.objects.all(), source='created_by', write_only=True, required=False)
    
        class Meta:
            model = Project
            fields = ('project_id', 'created_by', 'created_by_id', 'created')
    

    然后,只有用户模型的用户名字段值将显示在get有效内容的create_by json标记上 .

    UPDATE - 1

    经过一些更多调整后,我提出了最终版本:

    class ProjectSerializer(serializers.ModelSerializer):
    
        created_by_id = serializers.PrimaryKeyRelatedField(
            queryset=User.objects.all(), write_only=True, required=False, default=serializers.CurrentUserDefault())
        created_by = serializers.SerializerMethodField('creator')
    
        def creator(self, obj):
            return obj.created_by_id.username
    
        class Meta:
            model = Project
            fields = ('project_id', 'created_by_id', 'created_by', 'created')
    

相关问题