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 toNewUserView
, 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.