Django: невозможно сохранить нового пользователя

Я пытаюсь построить представление, которое показывает форму для создания нового пользователя.
Далее следуют шаблон, который я использую, urls.py и попытки кода в views.py и 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'),
    ...
]

Первая попытка:

views.py

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

Этот не вернул ошибок, но не смог сохранить новые данные пользователя.

Во второй попытке была создана форма для этого случая:

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')

Этот вернул ошибку: TypeError at /newuser/ BaseForm.__init__() got an unexpected keyword argument 'instance'

Третья:

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')

Также не удается сохранить новый экземпляр User. Я также заметил, что строка model = User в этой последней попытке может быть удалена.

Я использую запрос User.objects.all() в терминале и на странице администратора для проверки новых пользователей.

Что я не делаю?

когда вы используете CreateView на модели, он вызывает метод create.

Но модель User отличается. Модель пользователя не имеет create, вместо этого есть create_user. и CreateView не знает об этом. Я предлагаю вам использовать класс View следующим образом:

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})

этот сниппет полностью работает.

Вы должны сделать POST-запрос к представлению newuser, так:

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

Однако вы не можете использовать простой ModelForm: пароли в Django хэшируются, и ModelForm будет не делать этого, или, по крайней мере, не автоматически.

Вы можете использовать UserCreationForm [Django-doc] для правильного хэширования, это поле также использует два поля пароля, которые будут проверены.

Если вы хотите реализовать пользовательский ModelForm, то вам необходимо реализовать функциональность хеширования пароля в форме модели:

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

и затем подключите это к CreateView с:

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

Примечание: В Django представления, основанные на классах (CBV), часто имеют суффикс …View, чтобы избежать столкновения с именами моделей. Поэтому вы можете переименовать класс представления в NewUserView, вместо NewUser.

Вернуться на верх