Kan django’s auth_user.username varchar(75) zijn? Hoe zou dat kunnen?

Is er iets mis met het uitvoeren van de alter-tabel op auth_userom usernamevarchar(75)te maken zodat het in een e-mail past? Wat maakt dat kapot als er iets is?

Als u auth_user.usernamezou wijzigen in varchar(75), waar zou u dan django moeten wijzigen? Is het gewoon een kwestie van 30 in 75 veranderen in de broncode?

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

Of is er een andere validatie op dit veld die moet worden gewijzigd of heeft dit andere gevolgen?

Bekijk de commentaardiscussie met bartek hieronder over de reden om het te doen.

Bewerken: ik kijk hier na vele maanden op terug. Voor iedereen die het uitgangspunt niet kent: sommige apps hebben geen vereiste of wens om een ​​gebruikersnaam te gebruiken, ze gebruiken alleen e-mail voor registratie & auth. Helaas is in django auth.contrib een gebruikersnaam vereist. Je zou kunnen beginnen met het plaatsen van e-mails in het veld gebruikersnaam, maar het veld is slechts 30 tekens en e-mails kunnen lang zijn in de echte wereld. Mogelijk zelfs langer dan de 75 char die hier wordt voorgesteld, maar 75 char is geschikt voor de meeste normale e-mailadressen. De vraag is gericht op deze situatie, zoals die wordt aangetroffen bij op e-mail gebaseerde toepassingen.


Antwoord 1, autoriteit 100%

Er is een manier om dat te bereiken zonder het kernmodel aan te raken en zonder overerving, maar het is absoluut hackachtig en ik zou het met extra zorg gebruiken.

Als je Django’s document over signalenbekijkt, zie je er is er een genaamd class_prepared, die in principe wordt verzonden zodra een echte modelklasse is gemaakt door de metaklasse. Dat moment is uw laatste kans om een ​​model aan te passen voordat er magieplaatsvindt (dwz: ModelForm, ModelAdmin, syncdb, enz…).

Dus het plan is eenvoudig, u registreert dat signaal gewoon met een handler die detecteert wanneer het wordt aangeroepen voor het User-model, en wijzigt vervolgens de eigenschap max_lengthvan het veld username.

De vraag is nu, waar zou deze code moeten staan? Het moet worden uitgevoerd voordat het User-model wordt geladen, dus dat betekent vaak heel vroeg. Helaas kun je dat niet (django 1.1.1, heb geen andere versie gecontroleerd) dat in settingszetten omdat het importeren van signalser zal dingen kapot maken.

Een betere keuze zou zijn om het in de modellenmodule van een dummy-app te plaatsen en die app bovenaan de INSTALLED_APPSlijst/tuplete plaatsen (zodat het wordt geïmporteerd voor iets anders). Hier is een voorbeeld van wat je kunt hebben in 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)

Dat zal het lukken.

Een paar opmerkingen echter:

  • Misschien wilt u ook de help_textvan het veld wijzigen om de nieuwe maximale lengte weer te geven
  • Als u de automatische admin wilt gebruiken, moet u UserChangeForm, UserCreationFormen AuthenticationFormsubklassen aangezien de maximale lengte niet wordt afgeleid vanuit het modelveld, maar direct in de formuliervelddeclaratie.

Als u Zuidgebruikt, kunt u de volgende migratie maken om de kolom in de onderliggende database te wijzigen :

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

Antwoord 2, autoriteit 32%

Op basis van het geweldige gecombineerde antwoord van Clément en Matt Miller hierboven, heb ik een snelle app samengesteld die het implementeert. Pip installeren, migreren en gaan. Zou dit als een opmerking plaatsen, maar heb nog geen cred!

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

BEWERKEN 08-12-2014

De bovenstaande module is nu verouderd ten gunste van https://github.com /madssj/django-longer-username-and-email


Antwoord 3, autoriteit 27%

Bijgewerkte oplossing voor de Django 1.3-versie (zonder manage.py te wijzigen):

Nieuwe django-app maken:

monkey_patch/
    __init__.py
    models.py

Installeer het als eerste: (settings.py)

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

Hier is 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()

Antwoord 4, autoriteit 6%

De bovenstaande oplossingen lijken de modellengte bij te werken. Om uw aangepaste lengte in admin weer te geven, moet u echter ook de admin-formulieren overschrijven (frustrerend genoeg nemen ze niet gewoon de lengte over van het model).

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))

Antwoord 5, autoriteit 3%

Voor zover ik weet kan men gebruikersmodel overschrijvensinds Django 1.5, wat een probleem zal oplossen. Eenvoudig voorbeeld hier


Antwoord 6

Als je gewoon de databasetabel aanpast, heb je nog steeds te maken met Django’s validatie, dus je kunt er sowieso niet één van meer dan 30 tekens maken. Bovendien wordt de gebruikersnaam gevalideerd zodat deze geen speciale tekens zoals @kan hebben, dus het zou sowieso niet werken om de lengte van het veld aan te passen.Mijn fout, het lijkt erop dat het regelt dat. Dit is het gebruikersnaamveld van models.py in django.contrib.auth:

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

Het maken van e-mailverificatie is niet moeilijk. Hier is een supereenvoudige backend voor e-mailverificatiedie u kunt gebruiken. Het enige dat u daarna hoeft te doen, is een validatie toevoegen om ervoor te zorgen dat het e-mailadres uniek is en u bent klaar. Zo makkelijk.


Antwoord 7

Ja, het kan. Ik denk tenminste dat dit zou moeten werken; Ik heb uiteindelijk het hele auth-model vervangen, dus ik ben klaar om gecorrigeerd te worden als dit niet werkt…

Als u geen gebruikersrecords heeft waar u om geeft:

  1. laat de tabel auth_user vallen
  2. wijzig gebruikersnaam in max_length=75 in het model
  3. syncdb

Als u gebruikersrecords heeft die u moet bewaren, is het ingewikkelder omdat u ze op de een of andere manier moet migreren. Het gemakkelijkst is een back-up en herstel van de gegevens van de oude naar de nieuwe tabel, zoiets als:

  1. maak een back-up van de gebruikerstabelgegevens
  2. laat de tafel vallen
  3. syncdb
  4. importeer gebruikersgegevens opnieuw in de nieuwe tabel; zorg ervoor dat de oorspronkelijke id-waarden worden hersteld

Als alternatief kunt u met uw gekke python-django-skillz de gebruikersmodelinstanties van oud naar nieuw kopiëren en vervangen:

  1. maak je eigen model en plaats het tijdelijk naast het standaardmodel
  2. schrijf een script dat de instanties van het standaardmodel naar het nieuwe model kopieert
  3. vervang het standaardmodel door uw aangepaste

Dat laatste is niet zo moeilijk als het klinkt, maar brengt natuurlijk wat meer werk met zich mee.


Antwoord 8

Het probleem is in wezen dat sommige mensen een e-mailadres willen gebruiken als unieke identificatiecode, terwijl het gebruikersauthenticatiesysteem in Django een unieke gebruikersnaam van maximaal 30 tekens vereist. Misschien zal dat in de toekomst veranderen, maar dat is het geval met Django 1.3 terwijl ik dit schrijf.

We weten dat 30 tekens te kort is voor veel e-mailadressen; zelfs 75 tekens is niet genoeg om sommige e-mailadressen weer te geven, zoals uitgelegd in Wat is de optimale lengte voor een e-mailadres in een database?.

Ik hou van eenvoudige oplossingen, dus ik raad aan om het e-mailadres te hashen in een gebruikersnaam die past bij de beperkingen voor gebruikersnamen in Django. Volgens Gebruikersauthenticatie in Djangomag een gebruikersnaam maximaal 30 tekens, bestaande uit alfanumerieke tekens en _, @, +, . en -. Dus als we base-64-codering gebruiken met zorgvuldige vervanging van de speciale tekens, hebben we maximaal 180 bits. We kunnen dus een 160-bit hashfunctie zoals SHA-1 als volgt gebruiken:

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('=', '')

Kortom, deze functie koppelt een gebruikersnaam aan elk e-mailadres. Ik ben me ervan bewust dat er een kleine kans is op een botsing in de hash-functie, maar dit zou in de meeste toepassingen geen probleem moeten zijn.


Antwoord 9

Gewoon de onderstaande code toevoegen onderaan settings.py

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

Antwoord 10

C:…\venv\Lib\site-packages\django\contrib\auth\models.py

first_name = models.CharField(_(‘first name’), max_length=30, blank=True)

wijzig in

first_name = models.CharField(_(‘first name’), max_length=75, blank=True)

opslaan

en wijziging in de database


Antwoord 11

Ik gebruik django 1.4.3, wat het vrij eenvoudig maakt en ik hoefde niets anders in mijn code te veranderen nadat ik me realiseerde dat ik lange e-mailadressen als gebruikersnamen wilde gebruiken.

Als je directe toegang hebt tot de database, verander het daar dan in het aantal karakters dat je wilt, in mijn geval 100 karakters.

Voeg in uw app-model (myapp/models.py) het volgende toe

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)

Vervolgens specificeert u in uw settings.py het model:

AUTH_USER_MODEL = 'myapp.UserProfile'

Antwoord 12

De beste oplossing is om het e-mailveld te gebruiken voor e-mail en de gebruikersnaam voor gebruikersnaam.

Zoek in de validatie van het invoeraanmeldingsformulier of de gegevens de gebruikersnaam of het e-mailadres zijn en als het e-mailadres is, zoek dan in het e-mailveld.

Hiervoor is alleen het patchen van de contrib.auth.forms.login_formvereist, wat een paar regels in de bijbehorende weergave is.

En het is veel beter dan proberen de modellen en de databasetabellen aan te passen.


Antwoord 13

Als u venv (virtuele omgeving) gebruikt, is de eenvoudigste oplossing waarschijnlijk om de kerncode rechtstreeks bij te werken, d.w.z. door de volgende twee bestanden te openen:
– – venv/lib/python2.7/sites-packages/django/contrib/auth/model.py
– venv/lib/python2.7/sites-packages/django/contrib/auth/forms.py
Zoek naar alle gebruikersnaamvelden en verander max_length van 30 in 100. Het is veilig omdat je venv al gebruikt, dus het heeft geen invloed op andere Django-projecten.

Other episodes