2

I am doing a basic user creation using the built-in UserCreationForm in Django.

Here is my views.py:

def user_register(request):
    if request.method == "POST":
        form = UserCreationForm(request.POST)
        if form.is_valid():
            form.save()
            username = form.cleaned_data['username']
            raw_password = form.cleaned_data['password1']
            user = User.objects.create_user(username=username)
            if raw_password:
              user.set_password(raw_password)
            else:
              user.set_unusable_password()
            user.save()
            return redirect('home')
    else:
        form = UserCreationForm()
        return render(request, 'registration/register.html', {'form':  form})

However, after registering a user and being redirected to home, the number of Users seen in my Admin page has not changed; no User has been created. Any idea what I am doing wrong here?

SkillaPop
  • 79
  • 1
  • 11
  • The indentation in your question is wrong. Fix it, as it could be causing the problem. – Paulo Almeida Sep 05 '17 at 00:14
  • Ok, that was the obvious indentation, but I don't see a way of `redirect` happening without `User.objects.create_user` happening, and I think that should always either create a user or raise an exception. Oh, and you don't need to call `set_unusable_password`, it's called when the password is empty in `create_user`. Also, the indentation in the final `return` should be a level up, for when the form is invalid. Finally, you don't need to call `user.save()`, `create_user` saves the user. – Paulo Almeida Sep 05 '17 at 00:46
  • Actually, I don't think you need anything other than `form.save()` and `redirect`, because [you're not doing anything that the form doesn't do](https://github.com/django/django/blob/a96b981d84367fd41b1df40adf3ac9ca71a741dd/django/contrib/auth/forms.py#L64). Regardless, that doesn't explain your problem, it should be raising an exception rather than redirecting home. – Paulo Almeida Sep 05 '17 at 00:59

4 Answers4

0

don't know why you can redirected to home with no use create,but you should deal with the situation form is not vaild and remove form.save() from form.is_valid() block like:

form = UserCreationForm(request.POST)
if form.is_valid():
    # remove form.save()
    ....
else:
    print(form.errors.as_text())
    return render(request, 'registration/register.html', {'form':  form})

or override save method for UserCreationForm like i do:

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

the full demo is:

from django.views.generic import *
class RegisterView(FormView):
    template_name = 'registration/register.html'
    form_class = UserCreationForm
    success_url = reverse_lazy('home')

    def form_valid(self, form):
        form.save()
        return HttpResponseRedirect(self.get_success_url())

forms.py

class UserCreationForm(forms.ModelForm):
    error_messages = {
        'duplicate_username': u"duplicate username",
        'password_mismatch': u"password_mismatch",
        'duplicate_email': u'duplicate email'
    }

    username = forms.RegexField(
        max_length=30,
        regex=r'^[\w.@+-]+$',
        error_messages={
            'invalid': u"onlay can contaions symbol @/./+/-/_",
            'required': u"required"
        },
        label='username'
    )
    email = forms.EmailField(
        error_messages={
            'invalid': u"email invalid",
            'required': u'required'},
        label='email'
    )
    password1 = forms.CharField(
        widget=forms.PasswordInput,
        error_messages={
            'required': u"required"
        },
        label='password1 '
    )
    password2 = forms.CharField(
        widget=forms.PasswordInput,
        error_messages={
            'required': u"required"
        },
        label='password2'
    )

    def __init__(self, *args, **kwargs):
        super(UserCreationForm, self).__init__(*args, **kwargs)
        self.fields['username'].widget.attrs.update({'class': 'form-control'})
        self.fields['email'].widget.attrs.update({'class': 'form-control'})
        self.fields['password1'].widget.attrs.update({'class': 'form-control'})
        self.fields['password2'].widget.attrs.update({'class': 'form-control'})

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

    def clean_username(self):
        # Since User.username is unique, this check is redundant,
        # but it sets a nicer error message than the ORM. See #13147.
        username = self.cleaned_data["username"]
        try:
            User.objects.get(username=username)
        except User.DoesNotExist:
            return username
        raise forms.ValidationError(
            self.error_messages["duplicate_username"]
        )

    def clean_password2(self):
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError(
                self.error_messages["password_mismatch"]
            )
        password_validation.validate_password(password2)
        return password2

    def clean_email(self):
        email = self.cleaned_data["email"]
        try:
            User.objects.get(email=email)
        except User.DoesNotExist:
            return email
        raise forms.ValidationError(
            self.error_messages["duplicate_email"]
        )

    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
Ykh
  • 7,567
  • 1
  • 22
  • 31
  • Is there any way I wouldn't have to add this into my own forms.py? Im just using the built in form – SkillaPop Sep 05 '17 at 00:26
  • yes, you can do this staff in form.is_vaild() block like you do now,but you need to handle form invaild – Ykh Sep 05 '17 at 00:29
0

Try:

from django.contrib.auth import login, authenticate
from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import render, redirect
from django.contrib.auth.models import User

def user_register(request):
    if request.method == 'POST':
        form = UserCreationForm(request.POST)
        if form.is_valid():
            username = form.cleaned_data['username']
            password = form.cleaned_data['password1']
            user=User.objects.create_user(username=username, password=password)
            user.save()
            #Below 2 lines, if you want user to get logged in
            user = authenticate(username=username, password=password)
            login(request, user)
            return redirect('home')
    else:
        form = UserCreationForm()
    return render(request, 'registration/register.html', {'form':  form})
Astik Anand
  • 12,757
  • 9
  • 41
  • 51
  • Tried this.. still no new User created when I view the User model in the admin page – SkillaPop Sep 05 '17 at 00:08
  • @SkillaPop, Have a check now I have updated my answer – Astik Anand Sep 05 '17 at 00:19
  • @SkillaPop You keep saying "when I view the User model in the admin page". Are you sure the user isn't being created? Could it be a filter in the Admin hiding it? Check in the console with `User.objects.count()`. – Paulo Almeida Sep 05 '17 at 00:22
  • I just checked `User.objects.count()` and it remains the same number before I complete the Registration form – SkillaPop Sep 05 '17 at 00:32
  • Yes, just did.. Same thing, no objects are created in the User model. – SkillaPop Sep 05 '17 at 00:44
  • Check it using console. If user can be created from there using [user createion from shell link](https://stackoverflow.com/questions/46010177/create-user-from-the-command-line-in-django/46010380#46010380) – Astik Anand Sep 05 '17 at 00:52
0

I don't know why you are saving the object so many times. As documented here, when calling form.save() in a UserCreationForm instance, Django will create the user, set the password (which comes from the password1 field), save the instance in the database and return the user for you. So User.objects.create_user and user.save() will only save the object again.

Parhaps it's not the solution for your problem but have you tried just like this:

def user_register(request):
   form = UserCreationForm() 
   if request.method == 'POST':
       form = UserCreationForm(request.POST)
       if form.is_valid():
          user = form.save()
          # if you want to authenticate your user or log any info, do it here
          return redirect('home')
   # I wouldn't use the else statement here, so if there are errors in the form you probably want the same template to be rendered, in order to show the form errors to your user.
   return render(request, 'registration/register.html', {'form':  form})
0

Thanks for everybody that helped me think this through. It seems, of course, the answer was much simpler than I thought. My new user_register view is:

from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import render, redirect

def user_register(request):
   form = UserCreationForm(request.POST)
   if form.is_valid():
       form.save()
       return redirect('home')
   else:
       return render(request, 'registration/register.html', {'form':   form})
SkillaPop
  • 79
  • 1
  • 11