Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Auto-generating username when adding a user with django

Tags:

python

django

I am trying to save username as firstname while adding a user from django admin. Currently it saves None in the username field as I have excluded username in the custom model.

admin.py--

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from .models import UserProfile
from .forms import SignUpForm

class ProfileInline(admin.StackedInline):
    model = UserProfile
    can_delete = False
    verbose_name_plural = 'Profile'
    fk_name = 'user'


class CustomUserAdmin(UserAdmin):
    inlines = (ProfileInline, )
    list_display = ('email', 'first_name', 'last_name', 'is_staff')
    list_select_related = ( 'profile', )

    exclude = ('username',)

    fieldsets = (
        ('Personal information', {'fields': ('first_name', 'last_name', 'email', 'password')}),
        ('Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions')}),
        ('Important dates', {'fields': ('last_login', 'date_joined')}),
    )

    add_fieldsets = (
        ('None', {
            'classes': ('wide',),
            'fields': ('first_name','last_name', 'email', 'password1', 'password2')}
        ),
    )


    def get_inline_instances(self, request, obj=None):
        if not obj:
            return list()
        return super(CustomUserAdmin, self).get_inline_instances(request, obj)


admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)

forms.py

from django import forms
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Div, Field
from ajax_select.fields import AutoCompleteSelectField, AutoCompleteField
from phonenumber_field.formfields  import PhoneNumberField
from . import models
from captcha.fields import ReCaptchaField


class SignUpForm(forms.Form):
    first_name = forms.CharField(max_length=30)
    last_name = forms.CharField(max_length=30)
    phone_number = PhoneNumberField(label=_("Phone (Please state your country code eg. +44)"))
    organisation = forms.CharField(max_length=50)
    email = forms.EmailField()
    password1 = forms.CharField(max_length=20)
    password2 = forms.CharField(max_length=20)
    captcha = ReCaptchaField(attrs={'theme' : 'clean'})



    def signup(self, request, user):
        user.first_name = self.cleaned_data['first_name']
        user.last_name = self.cleaned_data['last_name']
        """
        profile, created = models.UserProfile.objects.get_or_create(user=user)
        profile.phone_number = self.cleaned_data['phone_number']
        profile.organisation = self.cleaned_data['organisation']
        profile.save()
        user.save()
        """
        up = user.profile
        up.phone_number = self.cleaned_data['phone_number']
        up.organisation = self.cleaned_data['organisation']
        user.save()
        up.save()

models.py --

from __future__ import unicode_literals
from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
from easy_thumbnails.fields import ThumbnailerImageField
from ciasroot.settings import THUMBNAILER_SIZES, UPLOAD_PATH
from ciasroot.constants import GENDERS, LANGUAGES
from ciasroot.util import HashedPk
from phonenumber_field.modelfields import PhoneNumberField
import math, decimal, datetime, os
import uuid

    def random_username(sender, instance, **kwargs):
        if not instance.username:
            instance.username = uuid.uuid4().hex[:30]
            models.signals.pre_save.connect(random_username, sender=User)

class UserProfile(models.Model, HashedPk):
    user = models.OneToOneField(User, unique=True, related_name ='profile')
    job_title = models.CharField(max_length=128, blank=True, null=False, default="")
    website = models.URLField(max_length=255, blank=True, null=True)
    organisation = models.CharField(max_length=50, blank=True, null=True, default="")
    phone_number = PhoneNumberField( blank=True, null=True)

    def __str__(self):
        return self.user.get_full_name()

    def save(self, *args, **kwargs):
        super(UserProfile, self).save(*args, **kwargs)
        LookupSuggest.add("job_title", self.job_title)

How can I insert username as firstname and make the custom field ie email 'required'. Now the password1 & password2 fields are mandatory.

Any help/link is highly appreciated.

like image 327
Prithviraj Mitra Avatar asked Aug 10 '17 18:08

Prithviraj Mitra


Video Answer


2 Answers

To automatically populate username with the user's first name, you should use a signal - add the following to the models.py where you've defined UserProfile:

def set_username(sender, instance, **kwargs):
    if not instance.username:
        instance.username = instance.first_name
models.signals.pre_save.connect(set_username, sender=User)

The problem with this is that if you have two users with the same first name, the username won't be unique, so you'll get an integrity error from the database. You could check for uniqueness and append a number until you get a unique value:

def set_username(sender, instance, **kwargs):
    if not instance.username:
        username = instance.first_name
        counter = 1
        while User.objects.filter(username=username):
            username = instance.first_name + str(counter)
            counter += 1
        instance.username = username
models.signals.pre_save.connect(set_username, sender=User)

Or, if you're not using the username at all, you could just set it to a random unique value using uuid:

import uuid

def random_username(sender, instance, **kwargs):
    if not instance.username:
        instance.username = uuid.uuid4().hex[:30]
models.signals.pre_save.connect(random_username, sender=User)

If you plan on using emails for login rather than username, you'll also need to enforce email uniqueness, add the email to the admin user creation form - this should do what you need: https://gist.github.com/gregplaysguitar/1184995

like image 154
Greg Avatar answered Sep 20 '22 14:09

Greg


You can define username as a readonly field.

def user_first_name(obj):
    return obj.first_name

user_firstname.short_description = 'Firstname'

class CustomUserAdmin(UserAdmin):
    readonly_fields = ('user_firstname')
    inlines = (ProfileInline, )
    list_display = ('email', 'user_first_name', 'last_name', 'is_staff')
    list_select_related = ( 'profile', )

    exclude = ('username',)
    ...

For your second question about validating email, define a form for CustomUserAdmin.

class CustomUserAdmin(UserAdmin):
    ...
    form = CustomUserAdminForm 

class CustomUserAdminForm(forms.ModelForm):
    def clean_email(self):
       if not self.cleaned_data['email']:
           raise forms.ValidationError("Email is required")

       return self.cleaned_data['email']

Or:

class CustomUserAdminForm(forms.ModelForm):
    email = forms.EmailField(required=True)
like image 44
Oluwafemi Sule Avatar answered Sep 23 '22 14:09

Oluwafemi Sule