update queryset primarykeyrelatedfield password jsonfield framework foreign python django validation django-rest-framework

python - queryset - listfield django rest framework



Orden de validaciĆ³n del serializador en el marco REST de Django (2)

Como es muy probable que su campo de username tenga un valor unique=True , Django REST Framework agrega automáticamente un validador que verifica que el nuevo nombre de usuario sea único. Puede confirmar esto haciendo repr(serializer()) , que le mostrará todos los campos generados automáticamente, que incluyen los validadores.

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

  1. field.run_validators campo llamada ( serializer.to_internal_value and field.run_validators )
  2. serializer.validate_[field] se llama para cada campo
  3. Se llaman los validadores de nivel de serializer.run_validation ( serializer.run_validation seguido de 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 que la validación a nivel de serializador. Aunque no lo recomendaría, puedes eliminar el validador de nivel de campo configurando extra_kwargs en el meta de tu serilalizador.

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

Sin embargo, deberá volver a implementar la comprobación unique en su propia validación, junto con cualquier validador adicional que se haya generado automáticamente.

Situación

Mientras trabajaba con la validación en el ModelSerializer Django REST Framework, he notado que los campos de Meta.model siempre se validan, incluso cuando no necesariamente tiene sentido hacerlo. Tomemos el siguiente ejemplo para la serialización de un modelo de User :

  1. Tengo un punto final que crea un usuario. Como tal, hay un campo de password y un campo confirm_password . Si los dos campos no coinciden, no se puede crear el usuario. Del mismo modo, si el username solicitado ya existe, el usuario no se puede crear.
  2. Los valores POST del usuario no son adecuados para cada uno de los campos mencionados anteriormente
  3. Se ha realizado una implementación de validate en el serializador (ver más abajo), capturando los campos de password no coincidente y confirm_password

Implementación de validate :

def validate(self, data): if data[''password''] != data.pop(''confirm_password''): raise serializers.ValidationError("Passwords do not match") return data

Problema

Incluso cuando el ValidationError se ModelSerializer por validate , el ModelSerializer todavía consulta la base de datos para verificar si el username ya está en uso. Esto es evidente en la lista de errores que se devuelve desde el punto final; Tanto el modelo como los errores de no-campo están presentes.

Por consiguiente, me gustaría saber cómo evitar la validación del modelo hasta después de que haya finalizado la validación sin campo, guardándome una llamada a mi base de datos.

Intento de solución

He estado tratando de revisar la fuente del DRF para averiguar dónde está sucediendo esto, pero no he logrado ubicar lo que necesito anular para que esto funcione.


No creo que las soluciones anteriores funcionen más. En mi caso, mi modelo tiene los 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 efecto, el primer nombre y el último nombre siempre se consideran necesarios y siempre se llama a los validadores. No puedo sobrecargar los campos del primer nombre / último nombre con

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

como los nombres tienen sentido. Después de muchas horas de frustración, encontré que la única manera de anular los validadores con una instancia de ModelSerializer era anular el inicializador de clase de la siguiente manera (perdonar 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 campos de caracteres en blanco y nulo es un no, no, pero este es un serializador, no un modelo, y como la API es llamada por todo tipo de vaqueros, necesito cubrir mis bases.