serializermethodfield - django rest framework tutorial
Django REST Framework: validaciĆ³n de Unique_together en Serializadores (6)
Tener problemas con un serializer.is_valid()
devolviendo True
si la instancia del serializador falla una restricción unique_together
en el lado del modelo.
¿Hay alguna manera de que yo especifique en el serializador para imponer una restricción unique_together
?
Bueno, esto es un poco estúpido y es muy poco probable que alguien que no sea yo cometa este error, pero había puesto el mismo modelo en dos clases de serializadores, como consecuencia tuve este problema.
Espero que mi error ayude a alguien!
Desafortunadamente, la respuesta de Andreas no es del todo completa, ya que no funcionará en el caso de una actualización.
En su lugar, querrías algo más como:
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'')
Esto funcionará para PUT, PATCH y POST.
La clase ModelSerializer tiene esta funcionalidad incorporada, al menos en djangorestframework>=3.0.0
, sin embargo, si está utilizando un serializer
que no incluye todos los campos que se ven afectados por su restricción unique_together
, obtendrá una IntegrityError
al guardar una instancia que la viola. Por ejemplo, usando el siguiente modelo:
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)
y el siguiente serializador y 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)
Si intenta guardar dos instancias con el mismo conjunto foo_a
y foo_b
, obtendrá un IntegrityError
. Sin embargo, si modificamos el serializador de esta manera:
class FooSerializer(serializers.ModelSerializer):
class Meta:
model = models.Foo
fields = (''a'', ''b'', ''foo_a'', ''foo_b'')
a continuación, obtendrá un código de estado HTTP 400 BAD REQUEST
y el correspondiente mensaje descriptivo JSON en el cuerpo de la respuesta:
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."
]
}
Espero que esto te resulte útil, incluso cuando esta es una pregunta un poco antigua ;-)
Necesitaba esto para anular el mensaje predeterminado. Resuelto por 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
Sí, puede hacerlo en el método .validate()
del serializador.
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
La restricción única que estableció en su modelo es para crear restricciones de base de datos, no para validar.
Tenía el mismo problema y de esta respuesta, https://.com/a/26027788/6473175 , pude hacer que funcionara, pero tuve que usar self.instance
lugar de 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'')