Может ли имя dhango auth_user.username быть varchar (75)? Как это могло быть сделано? - PullRequest
64 голосов
/ 09 апреля 2010

Что-то не так с запуском 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 ]

78 голосов
/ 10 апреля 2010

Есть способ достичь этого, не затрагивая основную модель и не наследуя, но он определенно хакерский, и я бы использовал его с особой осторожностью.

Если вы посмотрите на документ 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
25 голосов
/ 28 июля 2011

Основываясь на великолепном комбинированном ответе Клемента и Мэтта Миллера выше, я собрал быстрое приложение, которое его реализует. Pip установить, мигрировать и идти. Поместил бы это как комментарий, но еще не получил кредит!

https://github.com/GoodCloud/django-longer-username

РЕДАКТИРОВАТЬ 2014-12-08

Вышеупомянутый модуль устарел в пользу https://github.com/madssj/django-longer-username-and-email

21 голосов
/ 23 июня 2011

Обновленное решение для версии Django 1.3 (без изменения manage.py):

Создание нового django-приложения:

monkey_patch/
    __init__.py
    models.py

Установите его как первый: (settings.py)

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

Вот модели.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()
5 голосов
/ 13 октября 2012

Решения, приведенные выше, обновляют длину модели. Однако, чтобы отразить пользовательскую длину в 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))
2 голосов
/ 25 марта 2013

Насколько я знаю, можно переопределить модель пользователя начиная с Django 1.5, что решит проблему. Простой пример здесь

1 голос
/ 09 марта 2012

По сути, проблема в том, что некоторые люди хотят использовать адрес электронной почты в качестве уникального идентификатора, в то время как система аутентификации пользователей в 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('=', '')

Короче говоря, эта функция связывает имя пользователя для любого адреса электронной почты. Мне известно, что в хэш-функции есть небольшая вероятность столкновения, но это не должно вызывать проблем в большинстве приложений.

1 голос
/ 10 апреля 2010

Да, это можно сделать. По крайней мере, я думаю, что это должно работать; Я закончил замену всей модели аутентификации, так что я готов исправить ее, если это не сработает ...

Если у вас нет записей, которые вас интересуют:

  1. удалить таблицу auth_user
  2. изменить имя пользователя на max_length = 75 в модели
  3. SyncDB

Если у вас есть пользовательские записи, которые вам нужно сохранить, тогда это сложнее, так как вам нужно как-то их перенести. Самым простым является резервное копирование и восстановление данных из старой таблицы в новую, например:

  1. резервное копирование данных таблицы пользователя
  2. бросить стол
  3. SyncDB
  4. повторно импортировать данные пользователя в новую таблицу; заботясь восстановить исходные значения идентификатора

В качестве альтернативы, используя ваш сумасшедший навык python-django, скопируйте экземпляры пользовательских моделей из старого в новое и замените:

  1. создайте собственную модель и временно поставьте ее рядом с моделью по умолчанию
  2. написать скрипт, который копирует экземпляры из модели по умолчанию в новую модель
  3. заменить модель по умолчанию вашей собственной

Последнее не так сложно, как кажется, но, очевидно, требует немного больше работы.

1 голос
/ 09 апреля 2010

Если вы просто измените таблицу базы данных, вам все равно придется иметь дело с проверкой 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"))

Создание аутентификации электронной почты не сложно. Вот супер простой почтовый сервер , который вы можете использовать. После этого вам нужно добавить подтверждение, чтобы убедиться, что адрес электронной почты уникален, и все готово. Это просто.

0 голосов
/ 30 июля 2018

C: ... \ venv \ Lib \ сайт-пакеты \ Джанго \ вно \ Auth \ models.py

first_name = models.CharField (_ ('имя'), max_length = 30, пробел = True)

изменить на

first_name = models.CharField (_ ('имя'), max_length = 75, пробел = True)

сохранение

и изменения в базе данных

0 голосов
/ 13 мая 2014

Я использую 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'
...