Saltar al contenido

Validación de campos personalizados de Django REST Framework

Solución:

Debe utilizar una validación de todo el objeto (validate()), ya que validate_date nunca será llamado desde date no es un campo en el serializador. De la documentación:

class MySerializer(serializers.ModelSerializer):
    def validate(self, data):
        """
        Check that the start is before the stop.
        """
        if data['start_date'] > data['end_date']:
            raise serializers.ValidationError("finish must occur after start")
        return data

Como sugirió Michel Sabchuk, puede agregar el error de validación al end_date campo:

class MySerializer(serializers.ModelSerializer):
    def validate(self, data):
        """
        Check that the start is before the stop.
        """
        if data['start_date'] > data['end_date']:
            raise serializers.ValidationError({"end_date": "finish must occur after start"})
        return data

Otra posibilidad es crear un validador. Creé uno basado en el código para UniqueTogetherValidator:

from rest_framework.utils.representation import smart_repr

class DateBeforeValidator:
    """
    Validator for checking if a start date is before an end date field.
    Implementation based on `UniqueTogetherValidator` of Django Rest Framework.
    """
    message = _('{start_date_field} should be before {end_date_field}.')

    def __init__(self, start_date_field="start_date", end_date_field="end_date", message=None):
        self.start_date_field = start_date_field
        self.end_date_field = end_date_field
        self.message = message or self.message

    def __call__(self, attrs, serializer):
        if attrs['start_date'] > attrs['end_date']:
            message = self.message.format(
                start_date_field=self.start_date_field,
                end_date_field=self.end_date_field,
            )
            # Replace the following line with
            #   raise serializers.ValidationError(
            #       {self.end_date_field: message},
            #       code="date_before",
            #   )
            # if you want to raise the error on the field level
            raise serializers.ValidationError(message, code="date_before")

    def __repr__(self):
        return '<%s(start_date_field=%s, end_date_field=%s)>' % (
            self.__class__.__name__,
            smart_repr(self.start_date_field),
            smart_repr(self.end_date_field)
        )


class MySerializer(serializers.ModelSerializer):
    class Meta:
        # If your start/end date fields have another name give them as kwargs tot the
        # validator:
        #   DateBeforeValidator(
        #       start_date_field="my_start_date", 
        #       end_date_field="my_end_date",
        #   )
        validators = [DateBeforeValidator()]

Antes de DRF 3.0, también podría agregarlo a la función de limpieza de un modelo, pero ya no se llama en DRF 3.0.

class MyModel(models.Model):
    start_date = models.DateField()
    end_date = models.DateField()
    def clean(self):
        if self.end_date < self.start_date:
            raise ValidationError("End date must be after start date.")

La respuesta de jgadelange funcionó antes del descanso 3 de django probablemente. Si alguien usa la versión django rest framework 3 *, creo que esto sería útil para esa gente. uno debe mantener el proceso de validación a nivel de modelo y el método limpio puede ser la única solución. Pero el anuncio del marco de descanso de django dice aquí que, si alguien quiere validar la llamada de descanso en el método modelo .clean, debe anular el método de validación del serializador y debe llamar al método limpio desde esta clase de serializador de la siguiente manera

(porque el documento dice: el método clean () no se llamará como parte de la validación del serializador)

class MySerializer(serializers.ModelSerializer):

   def validate(self, attrs):
     instance = MyModel(**attrs)
     instance.clean()
     return attrs

y modelo

class MyModel(models.Model):
    start_date = models.DateField()
    end_date = models.DateField()

    def clean(self):
        if self.end_date < self.start_date:
            raise ValidationError("End date must be after start date.")

Otra respuesta aquí podría ser útil, con respecto a la situación si uno elige anular el serializador validate() método.

Con respecto a la respuesta sobre el orden de validación del serializador en Django REST Framework, debo decir que serializer.validate() se llama al método al final de la secuencia de validación. Sin embargo, los validadores de campo se llaman antes de eso, en serializer.to_internal_value(), levantando ValidationError al final.

Esto significa que los errores de validación personalizados no se acumulan con los predeterminados.

En mi opinión, la forma más limpia de lograr el comportamiento deseado es mediante el uso de la validación del método de campo de destino en la clase de serializador:

def validate_end_date(self, value):
    # validation process...
    return value

En caso de que necesite otro valor de campo del modelo, como start_date en este caso, puede obtenerlos (aún sin validar, ya que un proceso no está completo) con:

# `None` here can be replaced with the field's default value
start_date = self.initial_data.get('start_date')
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *