Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I have Django user registration single step (instead of two step)process with email compulsory?

I want Django to send an email to user email-address with Login details once admin adds a new user to admin site.So I tried using Django signals for that but just becoz django user registration is a two step process signals get notified in first step only and called email function without email address(which comes in second step). My signal code:

def email_new_user(sender, **kwargs):
    if kwargs["created"]:  # only for new users
        new_user = kwargs["instance"]
       send_mail('Subject here', 'Here is the message.', '[email protected]',['[email protected]'], fail_silently=False)


post_save.connect(email_new_user, sender=User)

So what i tried to overcome this problem.I use this code in admin.py

class UserAdmin(admin.ModelAdmin):
    list_display = ('username', 'email', 'first_name', 'last_name', 'date_joined', 'last_login')
    search_fields = ['username', 'email']
    filter_horizontal = ('user_permissions',)

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

This makes all registration process a single step process and my signals start working and sending mail to user_id on new user addition.But the problem came after this were:

1. User password is not converted into hash and is visible while entering into form,that makes user not able to login into admin site.

2.Email field in form is not compulsory which I want to be compulsory.

Please help me :(

[EDIT]

I tried your code But I m still at same place where i was before posting this question.
the code i used in my admin.py is:
from django.contrib import admin
from mysite.naturefarms.models import *
from django.contrib.auth.models import User,Group
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django import forms
from django.contrib.admin.views.main import *

class MyUserCreationForm(UserCreationForm):
    class Meta:
        model = User
        fields = ('username', 'email',)
class UserAdmin(admin.ModelAdmin):
    add_form = MyUserCreationForm

admin.site.unregister(User)

class MyUserAdmin(UserAdmin):
    add_form = MyUserCreationForm
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('username', 'email', 'password1', 'password2')}
        ),
    )




admin.site.register(User, MyUserAdmin)

This is the output I m getting using this code which is even not converting password field into hash.

like image 881
Anshul Avatar asked Dec 27 '22 17:12

Anshul


2 Answers

If you look in django.contrib.auth admin.py, you'll see that the UserAdmin class specifies the add_form as UserCreationForm.

UserCreationForm only includes the 'username' field from the User model.

Since you're providing your own UserAdmin, you can just override the add_form to a custom UserCreationForm that includes the fields you need to make your signal work properly.

Hope that helps you out.

[Edit]

Here's the UserCreationForm from contrib.auth forms.py:

class UserCreationForm(forms.ModelForm):
    """
    A form that creates a user, with no privileges, from the given username and password.
    """
    username = forms.RegexField(label=_("Username"), max_length=30, regex=r'^[\w.@+-]+$',
        help_text = _("Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only."),
        error_messages = {'invalid': _("This value may contain only letters, numbers and @/./+/-/_ characters.")})
    password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
    password2 = forms.CharField(label=_("Password confirmation"), widget=forms.PasswordInput,
        help_text = _("Enter the same password as above, for verification."))

    class Meta:
        model = User
        fields = ("username",)

    def clean_username(self):
        username = self.cleaned_data["username"]
        try:
            User.objects.get(username=username)
        except User.DoesNotExist:
            return username
        raise forms.ValidationError(_("A user with that username already exists."))

    def clean_password2(self):
        password1 = self.cleaned_data.get("password1", "")
        password2 = self.cleaned_data["password2"]
        if password1 != password2:
            raise forms.ValidationError(_("The two password fields didn't match."))
        return password2

    def save(self, commit=True):
        user = super(UserCreationForm, self).save(commit=False)
        user.set_password(self.cleaned_data["password1"])
        if commit:
            user.save()
        return user

Notice the fields = ("username",) tuple which excludes all other fields on the User model. You need something like:

class MyUserCreationForm(UserCreationForm):
    class Meta:
        model = User
        fields = ('username', 'email',)

then you can use that as the add_form in your custom UserAdmin:

class UserAdmin(admin.ModelAdmin):
    add_form = MyUserCreationForm

It's pretty late in my part of the world, but I'll see if I can get a working sample for you tomorrow.

[Edit]

Ok, here's the necessary changes you'll need to make to make this work. I've tested it using Django 1.3:

from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from django import forms

admin.site.unregister(User)

class MyUserAdmin(UserAdmin):
    add_form = MyUserCreationForm
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('username', 'email', 'password1', 'password2')}
        ),
    )

admin.site.register(User, MyUserAdmin)

I didn't see that the UserAdmin had an add_fieldset property initially. That's why the email field wasn't displaying in the add form.

like image 183
Brandon Avatar answered Jan 31 '23 01:01

Brandon


From this example try defining email in your custom UserCreationForm as required=True:

class MyUserCreationForm(UserCreationForm):
    email = forms.EmailField(required=True)

    class Meta:
        model = User
        fields = ('username', 'email',)
like image 29
Hellefire Avatar answered Jan 30 '23 23:01

Hellefire