Mientras actualizaba de Django 1.9.13 a Django 1.10.7, encontré un problema extraño con el UUIDField nativo de Django.
Usamos este UUIDField en nuestro modelo de usuario personalizado como:
username = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)En 1.9, esto siempre devuelve una instancia de UUID. En 1.10, esto devuelve una cadena al crear una nueva instancia de modelo.
Compare los siguientes ejemplos de prueba:
1.9.13
>>> u = User.objects.last() >>> u2 = UserFactory() >>> u3 = User.objects.create() >>> u.pk UUID('e7e0f87d-1ed4-4293-829f-b0b745ccd676') >>> u2.pk UUID('f8e9a4a9-2265-4cd7-9813-00ffe7fd922a') >>> u3.pk UUID('0cb736d7-f8a0-4057-9c89-44fa114f4f82')1.10.7
>>> u = User.objects.last() >>> u2 = UserFactory() >>> u3 = User.objects.create() >>> u.pk UUID('e7e0f87d-1ed4-4293-829f-b0b745ccd676') >>> u2.pk 'f8e9a4a9-2265-4cd7-9813-00ffe7fd922a' >>> u3.pk '0cb736d7-f8a0-4057-9c89-44fa114f4f82'Esta diferencia da problemas con varias pruebas unitarias. Puedo solucionarlo forzando a ambos a encadenar, pero deseo entender por qué UUIDField se comporta de la manera en que lo hace, ya que se siente inconsistente.
El problema fue causado por un cambio de comportamiento en la clase AbstractBaseUser de Django. La clase recibió un método limpio al que llamé para guardar. Dentro del nuevo método de limpieza, se invocó un método normalize_username que obligó a que el nombre de usuario fuera texto.
Al evitar la súper llamada a AbstractBaseUser, ya no normalizamos el nombre de usuario, que no es algo que de todos modos queríamos, ya que nuestro campo de nombre de usuario es un UUID.