Django REST框架:Serializer上的Unique_together验证

fan*_*err 18 django django-rest-framework

如果序列化程序实例在模型端失败约束,则serializer.is_valid()返回问题.Trueunique_together

有没有办法在序列化程序中指定强制执行unique_together约束?

小智 18

ModelSerializer类具有此功能内置,至少在内部djangorestframework>=3.0.0,但是如果您使用的serializer是不包含受约束影响的所有字段unique_together,那么IntegrityError在保存违反该实例的实例时您将得到一个.例如,使用以下模型:

class Foo(models.Model):
    class Meta:
        unique_together = ('foo_a', 'foo_b')

    a = models.TextField(blank=True)
    b = models.TextField(blank=True)
    foo_a = models.IntegerField()
    foo_b = models.IntegerField(default=2)
Run Code Online (Sandbox Code Playgroud)

和以下序列化程序和ViewSet:

class FooSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Foo
        fields = ('a', 'b', 'foo_a')

class FooViewSet(viewsets.ModelViewSet):
    queryset = models.Foo.objects.all()
    serializer_class = FooSerializer


routes = routers.DefaultRouter()
routes.register(r'foo', FooViewSet)
Run Code Online (Sandbox Code Playgroud)

如果您尝试保存使用相同的两个实例foo_a,并foo_b集,你会得到一个IntegrityError.但是,如果我们像这样修改序列化器:

class FooSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Foo
        fields = ('a', 'b', 'foo_a', 'foo_b')
Run Code Online (Sandbox Code Playgroud)

然后,您将获得正确的HTTP 400 BAD REQUEST状态代码,以及响应正文中相应的JSON描述性消息:

HTTP 400 BAD REQUEST
Content-Type: application/json
Vary: Accept
Allow: GET, POST, HEAD, OPTIONS

{
    "non_field_errors": [
        "The fields foo_a, foo_b must make a unique set."
    ]
}
Run Code Online (Sandbox Code Playgroud)

我希望这对你有帮助,即使这是一个有点老问题的问题;-)


vai*_*ain 12

我需要这个来覆盖默认消息.解决了这个问题.

from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers


class SomeSerializer(serializers.ModelSerializer):
  """
  Demostrating How to Override DRF UniqueTogetherValidator Message
  """

    class Meta:
        model = Some
        validators = [
            serializers.UniqueTogetherValidator(
                queryset=model.objects.all(),
                fields=('field1', 'field2'),
                message=_("Some custom message.")
            )
        ]
Run Code Online (Sandbox Code Playgroud)

Similarly you can specify fields


Jef*_*ffS 8

不幸的是,Andreas的答案并不完全,因为它不适用于更新.

相反,你会想要更像的东西:

def validate(self, attrs):
    field1 = attrs.get('field1', self.object.field1)
    field2 = attrs.get('field2', self.object.field2)

    try:
        obj = Model.objects.get(field1=field1, field2=field2)
    except StateWithholdingForm.DoesNotExist:
        return attrs
    if self.object and obj.id == self.object.id:
        return attrs
    else:
        raise serializers.ValidationError('field1 with field2 already exists')
Run Code Online (Sandbox Code Playgroud)

这适用于PUT,PATCH和POST.

  • @fangsterr你是对的,你可以这样做:`objects.filter(field1 = field1,field2 = field2).exists()`在你正在更新一个对象的情况下,匹配的对象将存在 - 一个你正在更新,这是id比较的内容. (3认同)