2014-03-24 3 views
15

serializer.is_valid()과 함께 문제가 발생하면 serializer 인스턴스가 모델 측에서 unique_together 제약 조건을 충족하지 못하면 True을 반환합니다.Django REST Framework : Serializer의 Unique_together 유효성 검사

unique_together 제약 조건을 적용하기 위해 시리얼 라이저에서 지정하는 방법이 있습니까?

+1

문제의 모델을 포함시킬 수 있습니까? – Drewness

답변

5

안드레아스의 대답은 업데이트가 제대로 작동하지 않으므로 완전하지 않습니다. PUT, PATCH 및 POST를 위해 작동

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

이 :

대신, 당신은 더 많은 뭔가를 원하는 것입니다.

+0

재미 있습니다. 나는 당신이''.exists()'를 추가한다면 똑같이 효율적으로 만들 수 있다고 생각한다. ID 확인을하지 않는 것의 파급 효과가 무엇인지 모르겠다. – fangsterr

+1

@fangsterr 맞다. 다음과 같이 할 수있다 :'objects.filter (field1 = field1, field2 = field2) .exists()'당신이 ' 다시 개체를 업데이트하면 일치하는 개체가 존재할 것입니다. 즉, 업데이트중인 ID가있는 개체입니다. – JeffS

2

예, 시리얼 라이저의 .validate() 메소드에서 수행 할 수 있습니다.

def validate(self, attrs): 
    try: 
     Model.objects.get(field1=attrs['field1'], field2=attrs['field2']) 
    except Model.DoesNotExist: 
     pass 
    else: 
     raise serializers.ValidationError('field1 with field2 already exists') 

    return attrs 

모델에서 설정하는 고유 제한 조건은 유효성 검사가 아닌 데이터베이스 제약 조건 생성을위한 것입니다.

9

ModelSerializer 클래스는 그러나 당신이 당신의 unique_together 구속의 영향을받는 분야의 모든를 포함하지 않는 이는 serializer를 사용하는 경우,이 기능 빌드 -에서, 적어도 djangorestframework>=3.0.0에있다, 당신은 얻을 것이다 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) 

하고 다음 시리얼 라이저와 뷰셋 : 같은 foo_afoo_b 세트 두 인스턴스를 저장하려고하면

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) 

, 당신은 IntegrityError를 얻을 수 있습니다 예를 들어, 다음과 같은 모델을 사용하여 . 그러나, 우리는이 같은 시리얼 수정하는 경우 :

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." 
    ] 
} 

나는이 희망 :

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

당신은 응답 본문에 적절한 HTTP 400 BAD REQUEST 상태 코드와 해당 JSON 설명 메시지가 나타납니다 결과가 약간 오래된 질문 인 경우에도 유용합니다.

5

기본 메시지를 덮어 쓰려면이 설정이 필요했습니다. 그것을 this에 의해 해결했습니다.

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.") 
      ) 
     ] 

Similarly you can specify fields

0

음이 좀 바보이며 사람 만 날이 실수를 할 가능성은 매우하지만 나는 결과로 나는이 문제를 가지고, 두 개의 시리얼 클래스에서 같은 모델을 넣어했다

내 실수가 도움이되기를 바랍니다.

1

같은 문제가있어서이 대답 https://stackoverflow.com/a/26027788/6473175에서 작동하게 만들었지 만 대신 self.object을 사용해야했습니다.

def validate(self, data): 
    field1 = data.get('field1',None) 
    field2 = data.get('field2',None) 

    try: 
     obj = self.Meta.model.objects.get(field1=field1, field2=field2) 
    except self.Meta.model.DoesNotExist: 
     return data 
    if self.instance and obj.id == self.instance.id: 
     return data 
    else: 
     raise serializers.ValidationError('custom error message') 
관련 문제