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
-
field.run_validators
campo llamada (serializer.to_internal_value
andfield.run_validators
) -
serializer.validate_[field]
se llama para cada campo - Se llaman los validadores de nivel de
serializer.run_validation
(serializer.run_validation
seguido deserializer.run_validators
) -
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
:
- Tengo un punto final que crea un usuario. Como tal, hay un campo de
password
y un campoconfirm_password
. Si los dos campos no coinciden, no se puede crear el usuario. Del mismo modo, si elusername
solicitado ya existe, el usuario no se puede crear. - Los valores POST del usuario no son adecuados para cada uno de los campos mencionados anteriormente
- Se ha realizado una implementación de
validate
en el serializador (ver más abajo), capturando los campos depassword
no coincidente yconfirm_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.