django 在创建新条目时使用带有外键模型的序列化程序

fkvaft9z  于 2023-06-25  发布在  Go
关注(0)|答案(2)|浏览(129)

起初,我有这个序列化器,它对GETPOST工作得很好(创建新条目)

class DrawingSerializer(ModelSerializer):
    drawing = serializers.FileField()
    detail = serializers.JSONField()
    class Meta:
        model = m.Drawing
        fields = ('id','detail','drawing','user','created_at','updated_at')

在创建条目的视图集中。

class DrawingViewSet(viewsets.ModelViewSet):
    queryset = m.Drawing.objects.all()
    serializer_class = s.DrawingSerializer
    def create(self, request, *args, **kwargs):
        request.data['user'] = request.user.id #set userid
        serializer = self.get_serializer(data=request.data)    
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer) # it makes the new entry with user
        return Response(serializer.data)

和models.py

class CustomUser(AbstractUser):
    detail = models.JSONField(default=dict,null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)    
    updated_at = models.DateTimeField(auto_now=True)  
   
class Drawing(models.Model):
    drawing = f.FileField(upload_to='uploads/')
    detail = models.JSONField(default=dict)
    user = models.ForeignKey(CustomUser,on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)    
    updated_at = models.DateTimeField(auto_now=True)

在这种情况下,user是外键模型。
所以我想得到用户的名字,电子邮件等等,然后我像这样修改了Serializer

class DrawingSerializer(ModelSerializer):
    drawing = serializers.FileField()
    detail = serializers.JSONField()
    user = CustomUserSerializer(read_only=True) # change here
    class Meta:
        model = m.Drawing
        fields = ('id','detail','drawing','user','created_at','updated_at')

它也适用于get。我可以从CustomUser模型中获取数据为user
但是,当POST(creating)时,它显示错误
django.db.utils.IntegrityError:(1048,“列'user_id'不能为null”)
为什么会发生这种情况,user_id是什么?
”张云的回答是。
我在下面这样更新,
但是,它不会在响应中显示user_datauser。(我认为user是正确的,虽然没有显示)

class DrawingSerializer(ModelSerializer):
    drawing = serializers.FileField()
    detail = serializers.JSONField()
    user_data = CustomUserSerializer(read_only=True) # change here
    class Meta:
        model = m.Drawing
        fields = ('id','detail','drawing','user','user_data', 'created_at','updated_at')
        extra_kwargs = {"user": {"write_only": True}}
k3bvogb1

k3bvogb11#

当你将ForeignKey添加到模型中时,Django会在数据库中创建FKFIELD_id字段。在您的问题中,您将user设置为read_only字段。因此,您无法将user字段传递给序列化程序,并且您会得到database错误。
最简单的方法是拆分useruser_data

class DrawingSerializer(ModelSerializer):
    drawing = serializers.FileField()
    detail = serializers.JSONField()
    user_data = CustomUserSerializer(read_only=True, source="user") # change here
    class Meta:
        model = m.Drawing
        fields = ('id','detail','drawing','user','user_data', 'created_at','updated_at')
        extra_kwargs = {"user": {"write_only": True}}
mwg9r5ms

mwg9r5ms2#

所以你在这里所做的被称为嵌套序列化器,在这种情况下,你使用CustomUserSerializer序列化User对象来获取它的属性,这就是当你调用GET方法时发生的事情。
但是当你尝试通过调用POST方法创建Drawing对象时,Django会阻止user值,即使你在请求数据中发送了它,因为你已经定义了read_only=True。这就引出了这个错误
django.db.utils.IntegrityError:(1048,“列'user_id'不能为null”)
这基本上告诉你,你有一个字段名为userDrawing模型-这是一个外键-它不能为空,我需要的主键,这是userid模型。

**第一种解决方案:**只需删除read_only=True,并确保在创建新的Drawing对象时将user字段包含在请求数据中。
**第二种解决方案:**在你的序列化器中创建两个不同的属性,一个用于阅读,一个用于写,例如:

class DrawingSerializer(ModelSerializer):
    drawing = serializers.FileField()
    detail = serializers.JSONField()
    user_details = CustomUserSerializer(read_only=True, source='user') # change here
    class Meta:
        model = m.Drawing
        fields = ('id', 'detail',' drawing', 'user', 'user_details', 'created_at', 'updated_at')
        extra_kwargs = {"user": {"write_only": True}}

**第三种方案:**覆盖序列化器的create方法,在保存Drawing对象之前手动设置user字段。这允许您在序列化器中将user字段保留为read-only,但在创建对象时仍然提供值,例如:

class DrawingSerializer(ModelSerializer):
    drawing = serializers.FileField()
    detail = serializers.JSONField()
    user = CustomUserSerializer(read_only=True)
    
    class Meta:
        model = Drawing
        fields = ('id', 'detail', 'drawing', 'user', 'created_at', 'updated_at')

    def create(self, validated_data):
        user = self.context['request'].user
        validated_data['user'] = user
        return super().create(validated_data)

相关问题