Может ли имя dhango auth_user.username быть varchar(75)? Как это могло быть сделано?
Что-то не так с запуском alter table на auth_user
делать username
быть varchar(75)
так что это может соответствовать электронной почте? Что это сломает, если что-нибудь?
Если бы вы должны были изменить auth_user.username
быть varchar(75)
где бы вам нужно было изменить django? Это просто вопрос изменения 30 на 75 в исходном коде?
username = models.CharField(_('username'), max_length=30, unique=True, help_text=_("Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters"))
Или есть другие проверки в этой области, которые должны быть изменены, или какие-либо другие последствия для этого?
Смотрите обсуждение комментариев с Bartek ниже относительно причины для этого.
Изменить: оглядываясь на это после многих месяцев. Для тех, кто не знает предпосылок: у некоторых приложений нет требования или желания использовать имя пользователя, они используют только электронную почту для регистрации и авторизации. К сожалению, в django auth.contrib требуется имя пользователя. Вы можете начать помещать электронные письма в поле имени пользователя, но поле имеет только 30 символов, и в реальном времени электронные письма могут быть длинными. Потенциально даже дольше, чем 75 символов, предложенных здесь, но 75 символов соответствуют большинству вменяемых адресов электронной почты. Вопрос нацелен на эту ситуацию, с которой сталкиваются приложения, основанные на аутентификации электронной почты.
13 ответов
Есть способ достичь этого, не затрагивая основную модель и не наследуя, но он определенно хакерский, и я бы использовал его с особой осторожностью.
Если вы посмотрите на документ Django по сигналам, вы увидите, что один называется class_prepared
, который в основном отправляется после создания метаклассом любого фактического класса модели. Этот момент - ваш последний шанс изменить любую модель, прежде чем произойдет какое-либо волшебство (то есть: ModelForm
, ModelAdmin
, syncdb
, так далее...).
Таким образом, план прост, вы просто регистрируете этот сигнал с помощью обработчика, который обнаружит, когда он вызывается для User
модель, а затем изменить max_length
собственность username
поле.
Теперь вопрос, где этот код должен жить? Это должно быть выполнено до User
модель загружается, так что это часто означает очень рано. К сожалению, вы не можете (django 1.1.1, не проверять с другой версией) поместить это в settings
потому что импорт signals
там все сломается.
Лучше было бы поместить его в модуль моделей фиктивного приложения и поместить это приложение поверх INSTALLED_APPS
list / tuple (поэтому он импортируется раньше всего). Вот пример того, что вы можете иметь в 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)
Это сделает свое дело.
Несколько заметок, хотя:
- Вы можете изменить также
help_text
поля, чтобы отразить новую максимальную длину - Если вы хотите использовать автоматический администратор, вам придется подкласс
UserChangeForm
,UserCreationForm
а такжеAuthenticationForm
максимальная длина выводится не из поля модели, а непосредственно в объявлении поля формы.
Если вы используете Юг, вы можете создать следующую миграцию, чтобы изменить столбец в базовой базе данных:
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
Основываясь на великолепном комбинированном ответе Клемента и Мэтта Миллера, я собрал быстрое приложение, которое его реализует. Pip установить, мигрировать и идти. Поставил бы это как комментарий, но еще не получил кредит!
https://github.com/GoodCloud/django-longer-username
РЕДАКТИРОВАТЬ 2014-12-08
Вышеупомянутый модуль устарел в пользу https://github.com/madssj/django-longer-username-and-email
Обновленное решение для версии Django 1.3 (без изменения manage.py):
Создайте новое django-приложение:
monkey_patch/
__init__.py
models.py
Установите его как первый: (settings.py)
INSTALLED_APPS = (
'monkey_patch',
#...
)
Вот 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()
Представленные выше решения, похоже, обновляют длину модели. Однако, чтобы отразить вашу пользовательскую длину в admin, вам также необходимо переопределить формы администратора (к сожалению, они не просто наследуют длину от модели).
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))
Насколько я знаю, с Django 1.5 можно переопределить пользовательскую модель, которая решит проблему. Простой пример здесь
Если вы просто измените таблицу базы данных, вам все равно придется иметь дело с проверкой Django, так что в любом случае она не позволит вам создать более 30 символов. Кроме того, имя пользователя проверяется таким образом, что оно не может содержать специальные символы, такие как @
так что простое изменение длины поля не сработало бы в любом случае. Мой плохой, похоже, он справляется с этим. Вот поле имени пользователя из models.py в django.contrib.auth:
username = models.CharField(_('username'), max_length=30, unique=True, help_text=_("Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters"))
Создание аутентификации электронной почты не сложно. Вот супер простой почтовый сервер, который вы можете использовать. После этого вам нужно будет добавить проверку, чтобы убедиться, что адрес электронной почты уникален, и все готово. Это просто.
По сути, проблема в том, что некоторые люди хотят использовать адрес электронной почты в качестве уникального идентификатора, в то время как система аутентификации пользователей в Django требует уникального имени пользователя не более 30 символов. Возможно, это изменится в будущем, но это касается Django 1.3, как я пишу.
Мы знаем, что 30 символов слишком мало для многих адресов электронной почты; даже 75 символов недостаточно для представления некоторых адресов электронной почты, как описано в разделе Какова оптимальная длина адреса электронной почты в базе данных?,
Мне нравятся простые решения, поэтому я рекомендую хешировать адрес электронной почты в имя пользователя, которое соответствует ограничениям для имен пользователей в Django. Согласно аутентификации пользователя в Django, имя пользователя должно содержать не более 30 символов, состоящих из буквенно-цифровых символов и _, @, +, . а также -. Таким образом, если мы используем кодировку base-64 с осторожной заменой специальных символов, у нас будет до 180 бит. Таким образом, мы можем использовать 160-битную хеш-функцию, такую как SHA-1, следующим образом:
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('=', '')
Короче говоря, эта функция связывает имя пользователя для любого адреса электронной почты. Я знаю, что в хеш-функции есть небольшая вероятность коллизии, но это не должно быть проблемой в большинстве приложений.
Да, это может быть сделано. По крайней мере, я думаю, что это должно работать; Я закончил замену всей модели аутентификации, так что я готов исправить ее, если это не сработает...
Если у вас нет записей о пользователях, которые вас интересуют:
- удалить таблицу auth_user
- изменить имя пользователя на max_length=75 в модели
- SyncDB
Если у вас есть пользовательские записи, которые вам нужно сохранить, то это сложнее, так как вам нужно как-то их перенести. Самым простым является резервное копирование и восстановление данных из старой таблицы в новую, что-то вроде:
- резервное копирование данных таблицы пользователя
- бросить стол
- SyncDB
- повторно импортировать данные пользователя в новую таблицу; заботиться о восстановлении первоначальных значений идентификаторов
В качестве альтернативы, используя ваш сумасшедший навык python-django, скопируйте экземпляры модели пользователя из старого в новое и замените:
- создайте свою модель и временно поместите ее рядом с моделью по умолчанию
- написать скрипт, который копирует экземпляры из модели по умолчанию в новую модель
- замените модель по умолчанию своей
Последнее не так сложно, как кажется, но, очевидно, требует немного больше работы.
Просто добавьте приведенный ниже код внизу settings.py
from django.contrib.auth.models import User
User._meta.get_field("username").max_length = 75
C:...\venv\Lib\ сайт-пакеты \ Джанго \ вно \ Auth \ models.py
first_name = models.CharField(_('имя'), max_length=30, пробел =True)
изменить на
first_name = models.CharField(_('имя'), max_length=75, пробел =True)
спасти
и изменить в базе данных
Я использую django 1.4.3, что делает его довольно простым, и мне не пришлось ничего менять в своем коде после того, как я понял, что хочу использовать длинные адреса электронной почты в качестве имен пользователей.
Если у вас есть прямой доступ к базе данных, измените ее там на количество символов, которое вы хотели бы, в моем случае 100 символов.
В вашей модели приложения (myapp/models.py) добавьте следующее
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)
Затем в вашем settings.py вы указываете модель:
AUTH_USER_MODEL = 'myapp.UserProfile'
Лучшее решение - использовать поле электронной почты для электронной почты и имя пользователя для имени пользователя.
В проверке формы входа для входа определите, являются ли данные именем пользователя или адресом электронной почты, и, если адрес электронной почты, запросите поле электронной почты.
Это требует только обезьяны исправления contrib.auth.forms.login_form
что несколько строк в соответствующем представлении.
И это гораздо лучше, чем пытаться модифицировать модели и таблицы базы данных.
Если вы используете venv (виртуальную среду), простейшим решением, вероятно, будет просто обновить основной код напрямую, то есть открыть следующие два файла: - - venv/lib/python2.7/sites-packages/django/contrib/auth/model.py - venv/lib/python2.7/sites-packages/django/contrib/auth/forms.py Поиск по всему полю имени пользователя и изменение max_length от 30 до 100. Это безопасно, поскольку вы уже используете venv, поэтому он выиграл ' не влияет на любой другой проект Django.