Home > Software design >  django: unable to save new user
django: unable to save new user

Time:02-13

I'm trying to build a view that shows a form for creating a new user.
Next are the template I'm using, urls.py and the code attempts at views.py and forms.py.

user_form.html

    <form action="{% url 'app:register' %}" method="post">
        {% csrf_token %}
        {{form.as_p}}
    <input type="submit" value="Register">
    </form>
urls.py

urlpatterns = [
    ...
    path('newuser/',views.NewUser.as_view(), name='newuser'),
    ...
]

First attempt:

views.py

class NewUser(generic.CreateView):
    model = User
    fields = ['username','email','password']
    template_name = 'app/user_form.html'
    success_url = reverse_lazy('register')

This one didn't return errors, but was unable to save the new user data.

Second try involved creating a form for the occasion:

forms.py

class NewUserForm(forms.Form):
    username = forms.CharField(max_length=100)
    email = forms.EmailField()
    password = forms.PasswordInput()

views.py

class NewUser(generic.CreateView):
    model = User
    form_class = NewUserForm
    template_name = 'app/user_form.html'
    success_url = reverse_lazy('register')

This one returned an error: TypeError at /newuser/ BaseForm.__init__() got an unexpected keyword argument 'instance'

Third:

forms.py

class NewUserForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ['username','email','password']

views.py

class NewUser(generic.CreateView):
    model = User
    form_class = NewUserForm
    template_name = 'app/user_form.html'
    success_url = reverse_lazy('cadastro')

Can't save a new User instance either. I've also noticed that the model = User line in this last try can be removed.

I'm using the User.objects.all() query in the terminal and the admin page to check for new users.

What am I not doing?

CodePudding user response:

You should make the POST request to the newuser view, so:

<form action="{% url 'app:newuser' %}" method="post">
    {% csrf_token %}
    {{form.as_p}}
    <input type="submit" value="Register">
</form>

You can however not use a simple ModelForm: passwords in Django are hashed and the ModelForm will not do that, or at least not automatically.

You can make use of the UserCreationForm [Django-doc] to do the hashing properly, this field also uses two password fields which will be validated.

If you want to implement a custom ModelForm, then you will need to implement the password hashing functionality in the model form:

class NewUserForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ['username','email','password']

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

and then plug this into the CreateView with:

class NewUserView(generic.CreateView):
    model = User
    form_class = NewUserForm
    template_name = 'app/user_form.html'
    success_url = reverse_lazy('cadastro')

Note: In Django, class-based views (CBV) often have a …View suffix, to avoid a clash with the model names. Therefore you might consider renaming the view class to NewUserView, instead of NewUser.

CodePudding user response:

when you use CreateView on a model, it calls create method.

but User model is different. User model doesn't have create, instead have create_user. and CreateView doesn't know about it. i suggest that you use View class like this:

class UserRegisterView(View):
    form_class = UserRegistrationForm
    template_name = 'account/register.html'

    def dispatch(self, request, *args, **kwargs):
        if request.user.is_authenticated:
            return redirect('home:home')
        return super().dispatch(request, *args, **kwargs)

    def get(self, request):
        form = self.form_class()
        return render(request, self.template_name, {'form':form})

    def post(self, request):
        form = self.form_class(request.POST)
        if form.is_valid():
            cd = form.cleaned_data
            User.objects.create_user(cd['username'], cd['email'], cd['password1'])
            messages.success(request, 'you registered successfully', 'success')
            return redirect('home:home')
        return render(request, self.template_name, {'form':form})

this snippet totally works.

  • Related