with password contrib auth abstractuser django django-models django-authentication

password - login url django



¿Puede auth_user.username de django ser varchar(75)? ¿Cómo podría hacerse eso? (12)

¿Hay auth_user con ejecutar alter table en auth_user para hacer que username sea varchar(75) para que se ajuste a un correo electrónico? ¿Qué rompe eso si algo?

Si auth_user.username cambiar auth_user.username para que sea varchar(75) dónde debería modificar django? ¿Es simplemente una cuestión de cambiar de 30 a 75 en el código fuente?

username = models.CharField(_(''username''), max_length=30, unique=True, help_text=_("Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters"))

¿O hay otra validación en este campo que debería cambiarse o cualquier otra repercusión para hacerlo?

Vea la discusión de comentarios con Bartek a continuación sobre la razón para hacerlo.

Editar : Mirando hacia atrás en esto después de muchos meses. Para cualquiera que no conozca la premisa: algunas aplicaciones no tienen un requisito o deseo de usar un nombre de usuario, solo usan el correo electrónico para registrarse y autenticar. Desafortunadamente en django auth.contrib, se requiere nombre de usuario. Podría comenzar a colocar correos electrónicos en el campo de nombre de usuario, pero el campo tiene solo 30 caracteres y los correos electrónicos pueden ser largos en el mundo real. Potencialmente incluso más largo que el 75 char sugerido aquí, pero 75 char acomoda la mayoría de las direcciones de correo electrónico. La pregunta está dirigida a esta situación, como lo hacen las aplicaciones basadas en autenticación de correo electrónico.


Estoy usando django 1.4.3, lo que lo hace bastante fácil y no tuve que cambiar nada más en mi código después de darme cuenta de que quería usar direcciones de correo electrónico largas como nombres de usuario.

Si tiene acceso directo a la base de datos, cámbiela a la cantidad de caracteres que desea, en mi caso 100 caracteres.

En su modelo de aplicación (myapp / models.py) agregue lo siguiente

from django.contrib.auth.models import User class UserProfile(models.Model): # This field is required. User._meta.get_field("username").max_length = 100 user = models.OneToOneField(User)

Luego, en su configuración.py especifica el modelo:

AUTH_USER_MODEL = ''myapp.UserProfile''


Fundamentalmente, el problema es que algunas personas desean utilizar una dirección de correo electrónico como identificador único, mientras que el sistema de autenticación de usuarios en Django requiere un nombre de usuario único de como máximo 30 caracteres. Quizás eso cambie en el futuro, pero ese es el caso con Django 1.3 mientras escribo.

Sabemos que 30 caracteres son demasiado cortos para muchas direcciones de correo electrónico; incluso 75 caracteres no son suficientes para representar algunas direcciones de correo electrónico, como se explica en ¿Cuál es la longitud óptima para una dirección de correo electrónico en una base de datos? .

Me gustan las soluciones simples, por lo que recomiendo clasificar la dirección de correo electrónico en un nombre de usuario que cumpla con las restricciones para los nombres de usuario en Django. Según la autenticación de usuario en Django , un nombre de usuario debe tener como máximo 30 caracteres, que consisten en caracteres alfanuméricos y _, @, +,. y - Por lo tanto, si usamos la codificación de base 64 con una sustitución cuidadosa de los caracteres especiales, tenemos hasta 180 bits. Entonces podemos usar una función hash de 160 bits como SHA-1 de la siguiente manera:

import hashlib import base64 def hash_user(email_address): """Create a username from an email address""" hash = hashlib.sha1(email_address).digest() return base64.b64encode(hash, ''_.'').replace(''='', '''')

En resumen, esta función asocia un nombre de usuario para cualquier dirección de correo electrónico. Soy consciente de que hay una pequeña probabilidad de una colisión en la función hash, pero esto no debería ser un problema en la mayoría de las aplicaciones.


Hay una manera de lograr eso sin tocar el modelo principal, y sin herencia, pero definitivamente es un hack y lo usaría con mucho cuidado.

Si miras el documento de Django sobre las señales , verás que hay una llamada class_prepared , que básicamente se envía una vez que la metaclass haya creado cualquier clase de modelo real. Ese momento es su última oportunidad de modificar cualquier modelo antes de que ModelForm cualquier magia (es decir: ModelForm , ModelAdmin , syncdb , etc.).

Entonces, el plan es simple, solo registra esa señal con un controlador que detectará cuándo se llama para el modelo de User y luego cambiará la propiedad max_length del campo de username de username .

Ahora la pregunta es, ¿dónde debería vivir este código? Tiene que ejecutarse antes User que se cargue el modelo de User , por lo que a menudo significa muy temprano . Desafortunadamente, no se puede (django 1.1.1 , no se ha verificado con otra versión) poner eso en la settings porque la importación de signals allí romperá las cosas.

Una mejor opción sería ponerlo en el módulo de modelos de una aplicación ficticia y poner esa aplicación encima de la lista INSTALLED_APPS / tuple (para que se importe antes que cualquier otra cosa). Aquí hay un ejemplo de lo que puede tener en myhackishfix_app/models.py :

from django.db.models.signals import class_prepared def longer_username(sender, *args, **kwargs): # You can''t just do `if sender == django.contrib.auth.models.User` # because you would have to import the model # You have to test using __name__ and __module__ if sender.__name__ == "User" and sender.__module__ == "django.contrib.auth.models": sender._meta.get_field("username").max_length = 75 class_prepared.connect(longer_username)

Eso hará el truco.

Algunas notas sin embargo:

  • Es posible que desee cambiar también help_text del campo, para reflejar la nueva longitud máxima
  • Si desea utilizar el administrador automático, deberá subclasificar UserChangeForm , UserCreationForm y AuthenticationForm ya que la longitud máxima no se deduce del campo del modelo, sino directamente en la declaración del campo de formulario.

Si está utilizando South , puede crear la siguiente migración para cambiar la columna en la base de datos subyacente:

import datetime from south.db import db from south.v2 import SchemaMigration from django.db import models class Migration(SchemaMigration): def forwards(self, orm): # Changing field ''User.username'' db.alter_column(''auth_user'', ''username'', models.CharField(max_length=75)) def backwards(self, orm): # Changing field ''User.username'' db.alter_column(''auth_user'', ''username'', models.CharField(max_length=35)) models = { # ... Copy the remainder of the file from the previous migration, being sure # to change the value for auth.user / usename / maxlength


La mejor solución es usar el campo de correo electrónico para el correo electrónico y el nombre de usuario para el nombre de usuario.

En la validación del formulario de inicio de sesión de entrada, busque si los datos son el nombre de usuario o el correo electrónico y, si es un correo electrónico, consulte el campo de correo electrónico.

Esto solo requiere el parche de mono contrib.auth.forms.login_form que es unas pocas líneas en la vista correspondiente.

Y es mucho mejor que tratar de modificar los modelos y las tablas de la base de datos.


Las soluciones anteriores parecen actualizar la longitud del modelo. Sin embargo, para reflejar su longitud personalizada en administración, también debe anular los formularios de administración (frustrantemente, no heredan simplemente la longitud del modelo).

from django.contrib.auth.forms import UserChangeForm, UserCreationForm UserChangeForm.base_fields[''username''].max_length = NEW_USERNAME_LENGTH UserChangeForm.base_fields[''username''].widget.attrs[''maxlength''] = NEW_USERNAME_LENGTH UserChangeForm.base_fields[''username''].validators[0].limit_value = NEW_USERNAME_LENGTH UserChangeForm.base_fields[''username''].help_text = UserChangeForm.base_fields[''username''].help_text.replace(''30'', str(NEW_USERNAME_LENGTH)) UserCreationForm.base_fields[''username''].max_length = NEW_USERNAME_LENGTH UserCreationForm.base_fields[''username''].widget.attrs[''maxlength''] = NEW_USERNAME_LENGTH UserCreationForm.base_fields[''username''].validators[0].limit_value = NEW_USERNAME_LENGTH UserCreationForm.base_fields[''username''].help_text = UserChangeForm.base_fields[''username''].help_text.replace(''30'', str(NEW_USERNAME_LENGTH))



Sí, se puede hacer. Al menos creo que esto debería funcionar; Terminé reemplazando todo el modelo de autenticación, por lo que estoy listo para ser corregido si esto no funciona ...

Si no tiene registros de usuario que le interesan:

  1. soltar la tabla auth_user
  2. cambiar el nombre de usuario a max_length = 75 en el modelo
  3. syncdb

Si tiene registros de usuarios que necesita retener, es más complicado ya que necesita migrarlos de alguna manera. Lo más fácil es realizar copias de seguridad y restaurar los datos de la tabla antigua a la nueva, algo así como:

  1. respaldar los datos de la tabla de usuario
  2. deja caer la mesa
  3. syncdb
  4. reimportar datos de usuario a la nueva tabla; teniendo cuidado de restaurar los valores de identificación originales

Alternativamente, usando su habilidad loca python-django, copie las instancias de modelo de usuario de antiguas a nuevas y reemplace:

  1. crea tu modelo personalizado y páralo temporalmente junto con el modelo predeterminado
  2. escriba un script que copie las instancias del modelo predeterminado al nuevo modelo
  3. reemplace el modelo predeterminado con el personalizado

Este último no es tan difícil como parece, pero obviamente implica un poco más de trabajo.


Si está utilizando venv (entorno virtual), la solución más simple probablemente sea simplemente actualizar el código central directamente, es decir, abrir los siguientes dos archivos: - - venv / lib / python2.7 / sites-packages / django / contrib / auth / model .py - venv / lib / python2.7 / sites-packages / django / contrib / auth / forms.py Busca todo el campo de nombre de usuario y cambia max_length de 30 a 100. Es seguro ya que estás usando venv así que ganó '' t afectar cualquier otro proyecto de Django.


Si simplemente modifica la tabla de la base de datos, igual tendrá que lidiar con la validación de Django, por lo que no le permitirá crear más de 30 caracteres de todos modos. Además, el nombre de usuario valida para que no pueda tener caracteres especiales como @ por lo que simplemente modificar la longitud del campo no funcionaría de todos modos. Mi mal, parece que maneja eso. Aquí está el campo de nombre de usuario de models.py en django.contrib.auth:

username = models.CharField(_(''username''), max_length=30, unique=True, help_text=_("Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters"))

Crear autenticación de correo electrónico no es difícil. Aquí hay un backend de autenticación de correo electrónico muy sencillo que puede usar. Todo lo que debe hacer después de eso es agregar algo de validación para asegurarse de que la dirección de correo electrónico sea única y listo. Así de fácil.



Solo agregue el código siguiente en la parte inferior de settings.py

from django.contrib.auth.models import User User._meta.get_field("username").max_length = 75


Solución actualizada para la versión Django 1.3 (sin modificar manage.py):

Crear nueva aplicación django:

monkey_patch/ __init__.py models.py

Instálelo primero: (settings.py)

INSTALLED_APPS = ( ''monkey_patch'', #... )

Aquí está models.py:

from django.contrib.auth.models import User from django.core.validators import MaxLengthValidator NEW_USERNAME_LENGTH = 300 def monkey_patch_username(): username = User._meta.get_field("username") username.max_length = NEW_USERNAME_LENGTH for v in username.validators: if isinstance(v, MaxLengthValidator): v.limit_value = NEW_USERNAME_LENGTH monkey_patch_username()