如何在 Django 休息框架中使 ModelSerializer 字段可选

How to make ModelSerializer field optional in Django rest framework

我有这个带有代码和评论字段的模型 Reaction。我的 models.py 文件中都有它们 null=True, blank=True 。我希望其中一个被填充而另一个为空,为此我在模型中创建了 clean 方法并在序列化程序中创建了 validate 方法。但是当我尝试在没有 code/comment 的情况下创建反应时,它说 code/comment 是必需的。

models.py
class Reaction(models.Model):
    code = models.ForeignKey(Code, null=True, blank=True, related_name="code_reactions", on_delete=models.CASCADE)
    comment = models.ForeignKey(Comment, null=True, blank=True, related_name="comment_reactions", on_delete=models.CASCADE)
    user = models.ForeignKey(User, related_name="reations", on_delete=models.CASCADE)
    
    REACTION_CHOICES = [
        ("like", "Like"),
        ("dislike", "Dislike"),
        ("wow", "Wow"),
        ("love", "Love"),
        ("sad", "Sad"),
        ("haha", "Haha"),
        ("rocket", "Rocket"),
        ("angry", "Angry"),
    ]
    name = models.CharField(choices=REACTION_CHOICES, max_length=10)
    
    class Meta:
        unique_together = [["code", "user"], ["comment", "user"]]
    
    def clean(self):
        if self.code and self.comment:
            raise ValidationError(_('One reaction cannot be assigned to a code and a comment'))
        
        if not self.code and not self.comment:
            raise ValidationError(_("Please enter a code or a comment"))
     
serializers.py

class ReactionCreateSerializer(serializers.ModelSerializer):
    code = serializers.IntegerField(required=False)
    comment = serializers.IntegerField(required=False)
    
    class Meta:
        model = Reaction
        fields = ["id", "user", "code", "comment", "name"]
        

    def validate(self, data):
        if data["code"] and data["comment"]:
            raise serializers.ValidationError(_('One reaction cannot be assigned to a code and a comment'))
        
        if not data["code"] and not data["comment"]:
            raise serializers.ValidationError(_("Please enter a code or a comment"))
        return data
    

我也试过了

class Meta:
    extra_kwargs = {'code': {'required': False},
                        'comment': {'required': False,}
                        }
example request
{
    "code": 1,
    "name": "love",
    "user": 1
}

returned response 

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

Required=False 允许您在该字段中发送 None/Blank 值。这并不意味着您可以在请求参数中完全跳过发送该字段。 换句话说,'required' 不应与 'exclude' 字段混淆。

供参考:

If a Field has required=False and you pass clean() an empty value, then clean() will return a normalized empty value rather than raising ValidationError. For CharField, this will return empty_value which defaults to an empty string. For other Field classes, it might be None. (This varies from field to field.)

文档:https://docs.djangoproject.com/en/4.0/ref/forms/fields/#required

你在序列化程序中所做的是正确的。只需确保将 None 设置为您不发送的字段:

{
    "code": 1,
    "name": "love",
    "user": 1,
    "comment": None
}

{
    "code": None,
    "name": "love",
    "user": 1,
    "comment": 2
}