Saltar al contenido

Orden de validación del serializador en Django REST Framework

Solución:

Dado que lo más probable es que tu username el campo tiene unique=True establecido, Django REST Framework agrega automáticamente un validador que verifica para asegurarse de que el nuevo nombre de usuario sea único. De hecho, puede confirmar esto haciendo repr(serializer()), que le mostrará todos los campos generados automáticamente, que incluye los validadores.

La validación se ejecuta en un orden específico no documentado

  1. Deserialización de campo llamada (serializer.to_internal_value y field.run_validators)
  2. serializer.validate_[field] se llama para cada campo
  3. Los validadores de nivel de serializador se denominan (serializer.run_validation seguido por serializer.run_validators)
  4. serializer.validate se llama

Entonces, el problema que está viendo es que la validación a nivel de campo se llama antes de la validación a nivel de serializador. Si bien no lo recomendaría, puede eliminar el validador de nivel de campo configurando extra_kwargs en el meta de su serilalizer.

class Meta:
    extra_kwargs = {
        "username": {
            "validators": [],
        },
    }

Deberá volver a implementar el unique Sin embargo, verifique su propia validación, junto con los validadores adicionales que se hayan generado automáticamente.

También estaba tratando de entender cómo fluye el control durante la validación del serializador y después de revisar cuidadosamente el código fuente de djangorestframework-3.10.3, se me ocurrió el siguiente diagrama de flujo de solicitud. He descrito el flujo y lo que sucede en el flujo a mi mejor entendimiento sin entrar en demasiados detalles, ya que se puede buscar desde la fuente.

Ignore las firmas de métodos incompletas. Solo centrándose en qué métodos se llaman y en qué clases.

DRF_Validation_Control_Flow

Suponiendo que tiene un anulado is_valid método en su clase de serializador (MySerializer(serializers.Serializer)) cuando usted llama my_serializer.is_valid() ocurre lo siguiente.

  1. MySerializer.is_valid() es ejecutado.
  2. Suponiendo que está llamando a la superclase (BaseSerializer) is_valid método (como: super(MySerializer, self).is_valid(raise_exception) en tus MySerializer.is_valid() método, que se llamará.
  3. Ahora desde MySerializer se está extendiendo serializers.Serializer, los run_validation() método de serializer.Serializers se llama. Esto está validando solo los datos dictados por el primero. Por lo tanto, aún no hemos comenzado las validaciones a nivel de campo.
  4. Entonces el validate_empty_values de fields.Field se llama. Esto vuelve a suceder en todo el data y ni un solo campo.
  5. Entonces el Serializer.to_internal_method se llama.
  6. Ahora recorremos cada campo definido en el serializador. Y para cada campo, primero llamamos al field.run_validation() método. Si el campo ha anulado el Field.run_validation() método, entonces se llamará primero. En caso de CharField se anula y llama al run_validation método de Field clase base. Paso 6-2 en la figura.
  7. En ese campo volvemos a llamar al Field.validate_empty_values()
  8. los to_internal_value del tipo de campo se llama a continuación.
  9. Ahora hay una llamada al Field.run_validators() método. Supongo que aquí es donde los validadores adicionales que agregamos en el campo especificando el validators = [] la opción de campo se ejecuta una por una
  10. Una vez hecho todo esto, volvemos a la Serializer.to_internal_value() método. Ahora recuerde que estamos haciendo lo anterior para cada campo dentro del ciclo for. Ahora, los validadores de campo personalizados que escribió en su serializador (métodos como validate_field_name) se ejecutan. Si ocurrió una excepción en cualquiera de los pasos anteriores, sus validadores personalizados no se ejecutarán.
  11. read_only_defaults()
  12. actualizar validar datos con valores predeterminados, creo
  13. ejecutar validadores a nivel de objeto. creo que el validate() El método en su objeto se ejecuta aquí.

No creo que las soluciones anteriores funcionen más. En mi caso, mi modelo tiene campos ‘first_name’ y ‘last_name’, pero la API solo recibirá ‘name’.

La configuración de ‘extra_kwargs’ y ‘validadores’ en la clase Meta parece no tener ningún efecto, first_name y last_name siempre se consideran obligatorios, y los validadores siempre se llaman. No puedo sobrecargar los campos de caracteres first_name / last_name con

anotherrepfor_first_name = serializers.CharField(source=first_name, required=False)

ya que los nombres tienen sentido. Después de muchas horas de frustración, encontré que la única forma en que podía anular los validadores con una instancia de ModelSerializer era anular el inicializador de clase de la siguiente manera (perdone la sangría incorrecta):

class ContactSerializer(serializers.ModelSerializer):
name = serializers.CharField(required=True)

class Meta:
    model = Contact
    fields = [ 'name', 'first_name', 'last_name', 'email', 'phone', 'question' ]

def __init__(self, *args, **kwargs):
    self.fields['first_name'] = serializers.CharField(required=False, allow_null=True, allow_blank=True)
    self.fields['last_name'] = serializers.CharField(required=False, allow_null=True, allow_blank=True)
    return super(ContactSerializer, self).__init__(*args, **kwargs)

def create(self, validated_data):
    return Contact.objects.create()

def validate(self, data):
    """
    Remove name after getting first_name, last_name
    """
    missing = []
    for k in ['name', 'email', 'question']:
        if k not in self.fields:
            missing.append(k)
    if len(missing):
        raise serializers.ValidationError("Ooops! The following fields are required: %s" % ','.join(missing))
    from nameparser import HumanName
    names = HumanName(data['name'])
    names.capitalize()
    data['last_name'] = names.last
    if re.search(r'w+', names.middle):
        data['first_name'] = ' '.join([names.first, names.middle]) 
    else:
        data['first_name'] = names.first
    del(data['name'])

    return data

Ahora el documento dice que permitir espacios en blanco y nulos con campos de caracteres es un no, pero esto es un serializador, no un modelo, y como la API es llamada por todo tipo de vaqueros, necesito cubrir mis bases.

¡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 *