Django auth: increasing max username length

AFAIK, you need to subclass auth.user if you want exactly that. A simpler and less adventurous solution might be implementing a user profile model with a longer username field. To avoid redundancy you may for example populate the actual username field with randomly-generated numbers and quit using it.


This answer here is an interesting approach: Can django's auth_user.username be varchar(75)? How could that be done?

A small app that overrides the max_length attribute on the User model, but note your DB column needs to be modified if the tables are not being syncdbed

I personally use a trimmed hash as my username which would notify me if there was ever a super unlikely collision, with the subject "You just won the lottery!"


for future needs this is the best way i found out:

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


I encountered this need in our existing infrastructure.

Our whole backend was relying on the Django default user model, but we had the need to change this max_len to make it match the email max_len.

From most StackOverflow posts I have seen, people mostly recommend creating a custom User model. This was definitely something we needed to avoid in our case. Changing from the default User model to a custom one is a serious and complex operation when performed on hundreds of thousands of Users in production.

So, instead, we just wanted to directly apply the change to the database schema itself. To do it properly, the best way is to perform the change from a migration. However, I could not see a way to directly generate a migration for the User model.

One way I could see was to generate an empty migration, then to use raw SQL to perform the migration.

Generate empty migration:

python manage.py makemigrations YOUR_APP --empty

Edit migration:

# -*- coding: utf-8 -*-
# Generated by Django 1.10.6 on 2019-02-11 09:39
from __future__ import unicode_literals

from django.db import migrations, models
from django.db.models import F
from django.db.models.functions import Length

from pittsburgh.models import User

#
# This function fixes thee existing user records by applying setting their username to be their email
#
def forwards_func_username(apps, schema_editor):
    User.objects.annotate(email_len=Length('email')).filter(email_len__gte=30).update(username=F('email'))

#
# This function reverts back to the original state
# Users with email > 30 chars have their username being a truncated email
#
def reverse_func_username(apps, schema_editor):
    users = User.objects.annotate(email_len=Length('email')).filter(email_len__gte=30)

    for user in users:
        user.username = user.email[:30]
        user.save()

class Migration(migrations.Migration):

    dependencies = [
        ('pittsburgh', '0076_auto_20190205_1623'),
    ]

    operations = [
        # change username max_length from 30 to 75 to match email max max_length
        migrations.RunSQL(sql="ALTER TABLE auth_user MODIFY COLUMN username VARCHAR(75) NOT NULL;",
                          reverse_sql="ALTER TABLE auth_user MODIFY COLUMN username VARCHAR(30) NOT NULL;"),
        # update username to match email
        migrations.RunPython(forwards_func_username, reverse_func_username),
    ]

The forwards_func_username and reverse_func_username of the RunPython are optional, depends on what you are willing to do.

Note that the RunSQL requires the sqlparse dependency, so don't forget to add that to your requirements.txt file.

sqlparse==0.2.4 # used implicitly by Django Migrations engine when using RunSQL operation

Hopes that help, I spent a couple hour browsing the web for some good solution, but this part is seriously poorly designed by Django (really misses the clean and easy design available on Ruby on Rails for example).