0

EDIT: If you want to skip the background story and just check the error message and code dump it's all at the bottom :)


I've been trying to implement a user-registration form for half a day now and feel that I'm sooo close but not quite there yet.

So I started out by implementing Django's built in UserCreationForm. And for my view I cunstructed this piece of code inspired by a response to this question:

from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import login 

def create_user(request):
    if request.method == "POST":
        form = UserCreationForm(request.POST)
        if form.is_valid():
            new_user = User.objects.create_user(**form.cleaned_data)
            login(new_user)
            return redirect('post_list')
    else:
        form = UserCreationForm()

    return render(request, 'blog/create_user.html', {'form': form}) 

Problem was: I wanted the users to be able to store their email as well. So I decided to use a piece of code from this blog to extend the UserCreationForm() in the forms.py file:

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

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

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

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

It still refused to include the email-part when I checked the actual web-page (even after I switched out: from django.contrib.auth.forms import UserCreationForm to from .forms import UserCreationForm). Finally I switched names in my forms.py file to UserForm in both the views.py and the forms.py files. So in the forms.py file it now said:

class UserForm(UserCreationForm):

Solution inspired by this question.

So now it said 'password1' is an invalid keyword argument for this function, I thought "of course, I'm passing a dictionary from my form into create_user and now that I've tampered with UserCreationForm it doesn't run as smoothly any more: create_user wants to have a username, email and password right? But now I'm sending username, email, password1 and password2.

So I added the following to the code in views.py:

if form.is_valid():
    username = form.cleaned_data["username"]
    email = form.cleaned_data["email"]
    password = form.cleaned_data["password1"]
    new_user = User.objects.create_user(username, email, password)
    login(new_user)

So now I get TypeError at /create_user/: login() takes exactly 2 arguments (1 given) and what really grinds my gears is how this wasn't an issue before I tampered with UserCreationForm (to the best of my recollection). But alright, alright, I'll google it, read through the documentation and some examples, looks like most people call the login-function with login(request, user) so I change my code again to:

new_user = User.objects.create_user(username, email, password)
login(request, new_user)

And here, I'm finally at an impasse as I get:

'User' object has no attribute 'backend'

I google it and either I don't find anything that correlates with my situation or I'm to slow witted to see that it does. If there's anyone out there who can explain what's wrong I would greatly appreciate it.

Code dump of current code:
Omitted other views and unrelated imports for readability

views.py

from django.shortcuts import render
from .forms import UserForm
from django.shortcuts import redirect
from django.contrib.auth.models import User
from django.contrib.auth import login

def create_user(request):
    if request.method == "POST":
        form = UserForm(request.POST)
        if form.is_valid():
            username = form.cleaned_data["username"]
            email = form.cleaned_data["email"]
            password = form.cleaned_data["password1"]
            new_user = User.objects.create_user(username, email, password)
            login(new_user)
            return redirect('post_list')
    else:
        form = UserForm()

    return render(request, 'blog/create_user.html', {'form': form})

forms.py

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

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

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

    def save(self, commit=True):
        user = super(UserForm, self).save(commit=False)
        user.email = self.cleaned_data["email"]
        if commit:
            user.save()
        return user
Community
  • 1
  • 1
MrJalapeno
  • 1,532
  • 3
  • 18
  • 37

2 Answers2

4

From the docs:

Calling authenticate() first

When you’re manually logging a user in, you must successfully authenticate the user with authenticate() before you call login(). authenticate() sets an attribute on the User noting which authentication backend successfully authenticated that user (see the backends documentation for details), and this information is needed later during the login process. An error will be raised if you try to login a user object retrieved from the database directly.

So, in order to log in a user, you must first call authenticate() and check if a user is returned:

new_user = User.objects.create_user(username, email, password)
new_user = authenticate(username=username, password=password)
if new_user:
    login(request, new_user)
MichielB
  • 4,181
  • 1
  • 30
  • 39
knbk
  • 52,111
  • 9
  • 124
  • 122
0

You will have to call authenticate() on the user before you call login(). This will check if a user is returned and won't allow you to call the user from the database directly. The code snippet should work on your cleaned data.

from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import login 

def create_user(request):
    if request.method == "POST":
        form = UserCreationForm(request.POST)
        if form.is_valid():
            new_user = User.objects.create_user(**form.cleaned_data)
            new_user = authenticate(**form.cleaned_data)
            login(request, new_user)
            return redirect('post_list')
    else:
        form = UserCreationForm()

    return render(request, 'blog/create_user.html', {'form': form}) 
Codefarmer
  • 684
  • 4
  • 8