代码之家  ›  专栏  ›  技术社区  ›  Sebastien

相关对象序列化程序django restframew

  •  0
  • Sebastien  · 技术社区  · 6 年前

    我的问题与 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)
    

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

    删除模型中的“创建人”字段。将序列化程序替换为:

    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')
    

    这并不能百分之百地满足我的需求,也就是说,用一个简单的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端点的get请求中返回简单用户名,而不在模型中显式存储用户名?或者更一般地说,如何通过使用默认序列化DRF特性和默认DRF视图MIXIN,将数据库对象(Django模型)序列化为客户JSON响应?

    问题的另一种表述方式是:如何在模型中存储对另一个db记录的id引用(该记录可以在没有负载提供的情况下访问),但在序列化器级别反序列化来自该对象引用的派生信息,例如被引用对象的一个特定字段?

    2 回复  |  直到 6 年前
        1
  •  0
  •   JPG    6 年前

    我建议你使用 两个不同的序列化程序 对于 Get POST 操作。改变你的 serializers.py 作为

    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__'
    


    另外,我建议 ModelViewSet 对于API类 CRUD operations 是的。因此景色会是这样,

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


    所以,要创建的有效载荷 Project 是,

    {
    }
    

    当你试图创造 项目 用户必须登录

    更新-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
    
        2
  •  0
  •   Sebastien    6 年前

    错误在只写字段选项中。这个 required 参数默认值设置为 True 如果我们看一下模型的话,目的是不需要它。在这个视图中,我使用perform_create作为后期处理保存在model db表示上。自从 必修的 默认值为 真的 在创造层面,第一个 .save() 到数据库失败。因为这纯粹是内部逻辑,所以不需要。所以简单地添加 required=False 上的选项 PrimaryKeyRelatedField 工作是:

    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函数。可能有一种方法可以在序列化程序中获取用户引用,并使视图实现更加“默认”…这可以通过使用 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')
    

    现在要仅使用username格式化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')
    

    然后,只有用户模型的username字段值将显示在get负载的create_by json标记上。

    更新-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')