Proper use of PasswordResetForm in Django - django

I'm trying to use django's supposed PasswordResetForm functionality to create a password reset form for my django application.
I created a form, in forms.py
class UserForgotPasswordForm(PasswordResetForm):
email = forms.EmailField(required=True,max_length=254)
class Meta:
model = User
fields = ("email")
I'm having trouble setting up the view in views.py to utilize this form, I currently have:
def UserResetPassword(request):
form = UserForgotPasswordForm(None, request.POST)
if request.method == 'POST':
if form.is_valid():
email = request.POST.get('email', '')
user =
my urls.py
urlpatterns = patterns('',
(r'^ForgotPassword/$',UserResetPassword),
)
I'm at a bit of a loss of how to use this further as the documentation I've found is scarce and often not directly using PasswordResetForm django functionality.
Can someone lend a hand?
Thank you.

I believe all you need to do is call form.save() and the PasswordResetForm will generate a onetime use link and email it to the user for you. It looks up the user matching the e-mail entered into the form.
So it would be something like:
def UserResetPassword(request):
form = UserForgotPasswordForm(None, request.POST)
if request.method == 'POST':
if form.is_valid():
form.save(from_email='blah#blah.com', email_template_name='path/to/your/email_template.html')
If you don't specify an email template name, django will just use the default one.

Related

Reset Password Form Page not found

I have built a custom password reset in Django, however, after putting the information in 'PasswordResetForm' I get a 404 page not found error.
This is my code for reset_password:
def reset_password(request,username):
if request.method == 'POST':
form = PasswordResetForm(data=request.POST, user=request.user)
if form.is_valid():
form.save()
update_session_auth_hash(request, form.user)
#added this to redirect user to custom url
username = request.user.username
return redirect(reverse('main:home', kwargs={'username': username}))
#return redirect(reverse('main:home'))
else:
return redirect(reverse('main:reset_password'))
else:
form = PasswordResetForm(user=request.user)
args = {'form': form}
return render(request, 'reset_password.html', args)
My urls at myapp/urls.py
urlpatterns=[
path('signup/',views.signup,name='signup'),
path('login',views.user_login,name='user_login'),
path('',views.main_page,name='main_page'),
path('<str:username>', views.home, name='home'),
#replace home/edit with below
path('<str:username>/edit', views.edit_profile, name='edit_profile'),
path('<str:username>/password-reset', views.reset_password, name='reset_password'),
]
and my form for password reset:
class PasswordResetForm(PasswordChangeForm):
class Meta:
model = Profile
fields = ('old_password','new_password1','new_password2')
What seems to be the problem here? I do not know why I am getting this error:
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/main/test3-b/login.html?next=/main/test3-b/password-reset
This is my AbstractUser model in models.py (I do not have any other code in my models.py
class Profile(AbstractUser):
bio = models.TextField()
university = models.CharField(max_length=30)
def __str__(self):
return self.username
Your urls.py is not using the same path as the URL you are accessing. The URL example you have given is http://127.0.0.1:8000/main/test3-b/login.html but your password reset url is something like http://127.0.0.1:8000/example-user/password-reset where example-user is the username that you are trying to match inside your path.
Out of interest do you have the URL structure include a username? This is normally not wanted as you would be using request.user to access the current user. You also have the risk a users username could break your patterns as you are using str rather than slug which is safer in URL patterns as otherwise id a user was created with the username of "example/edit" then they would never be able to get to your homepage as it would match the edit_profile entry instead.
I saw that by the form rendered in HTML it does not reset the admin user password, however the others works. In my case, I just extended the user class and inserted the email field.

Does django logs user in when register without authenticate() and login() function?

I am practicing django user registration using UserCreationForm() and User() class.
My froms.py code is.
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django import forms
class user(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')
My views.py code for this is.
def register(request):
if request.method == 'POST':
form = forms.user(request.POST)
if form.is_valid():
form.save(commit=False)
form.email = form.cleaned_data.get('email')
form.save()
#context = {'form':form, 'er':form.errors}
return redirect('register')
else:
form = forms.user()
context = {'form':form, 'er':form.errors}
return render(request, 'register/register.html', context)
I did not use authenticate() or login() in the registration system.
I have three questions. **In case of using same browser.
When I register does the user automatically log in and create a session number or does not?
If does log in and generate a session value, what happens if registers again with a new value from same browser? Does system delete previous session and generate new session or something else happens.
If I have used authenticate() and login(), what would happen if I try to register again?
It depends on your implementation. As long as you only save a user the user is only written to your DB. https://docs.djangoproject.com/en/2.2/topics/auth/default/#how-to-log-a-user-in
If you successfully created a user, you can't create a user with the same username again as the username is a unique identifier in the Django User Model.
To see if something is written to your session you can look into your DB.
Besides you might consider using an activation mail.

Django Custom Login - Form is valid but no error

I'm currently trying to figure out how to customize the base Django user login functionality to add e.g. simple-captcha.
I have subclassed "AuthenticationForm" from django.contrib.auth.forms
which first looks great, but if I try to login I'm simply not able to.
I have already debugged the code and currently i only get:
response = wrapped_callback(request, *callback_args,
**callback_kwargs) TypeError: init() takes 1 positional argument but 2 were given
accounts/views.py:
...
login form of django.contrib.auth.forms subclassed (copied) to accounts/forms.py:
...
urls.py:
...
when I used vorujack's way made mistake,finally I found a solution
in url
from django.contrib.auth import views as auth_views
path('login/',auth_views.LoginView.as_view(form_class=forms.new_login_form,
template_name='login.html'), name='login'),
in forms
from django.contrib.auth.forms import AuthenticationForm
class new_login_form(AuthenticationForm):
captcha = CaptchaField(label='验证码', error_messages={"invalid": "验证码错误"})
class Meta:
model = User
fields = ('username', 'password',)
There are a few things wrong here.
The main one is that you've overridden the class init signature so that the first positional argument is request, but you pass the POST data in that position; therefore, the form will never be bound and never valid.
Secondly if the form is invalid you re-instantiate it for some reason, so the template will never show any validation errors. Unless you have a really good reason you should stick to the standard form handling structure shown in the docs.
Putting those together:
def login (request):
if request.method == 'POST':
form = LoginForm(request, data=request.POST)
if form.is_valid():
form.save()
messages.add_message(request, messages.INFO, "You are now logged-In, welcome")
return redirect(reverse('post_list'))
else:
form = LoginForm(request)
args = {'form': form}
return render(request, 'registration/login.html', args)
Note, you don't need the second else block; the single one here is aligned with the first if, and the final return is hit in both cases.
as Daniel said you update init method of form. so you must pass request as first argument.
second is when you validate user info you must authenticate user with authentication backend. but you saved form data.
if you only want to change authentication form you can use login view like this
see below:
urls.py
....
url(r'^accounts/login/$', auth.login, {'authentication_form': LoginForm}, name='login'),
....
if you use django2 and above you can change it like this. first of all create a class based view extended from django.contrib.auth.views.LoginView in this class set form_class to it like this.
from django.conrtib.auth.views import LoginView
...
class NewLoginView(LoginView):
form_class = LoginForm
then you must update your urls like this:
...
url(r'^accounts/login/$', NewLoginView.as_view, name='login'),
...
you must extend your form from django.contrib.auth.forms.AuthenticationForm or you must implement all needed function of this form class.
I finally found a solution, puuh :D
views.py:
...
from django.contrib.auth import update_session_auth_hash, authenticate, login as customlogin
...
def login(request):
if request.method == 'POST':
form = LoginForm(request.POST, request.POST)
if form.is_valid():
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
customlogin(request, user)
# Redirect to a success page.
return redirect(reverse('post_list'))
return render(request, 'registration/login.html', {'form': form})
else:
return render(request, 'registration/login.html', {'form': LoginForm()})
simply extend the form (Thanks to vorujack)
...
from django.contrib.auth.forms import AuthenticationForm
...
class LoginForm (AuthenticationForm):
captcha = CaptchaField()
urls.py:
url(r'^accounts/login/$', views_accounts.login, name='login'),
the really stupid part is at the login function "form = LoginForm(request.POST, request.POST)"
You really need to pass this for the password and user and beside that and secondary request.POST for the captcha form... Oookay. Anyways, now it works.
Thanks anybody for your help, i really appreciate this community

Django-registration: Why is it so hard to save a user form, and is my simple solution OK?

I have a Client model with a OneToOne relationship to User, to extend the User model.
I need to be able to register a user (with a form that includes both the User and Client fields), and for that I used django-registration. Here is the view for registration, based on some snippets I found:
def register_client(request):
if request.method == 'POST':
userform = UserForm(request.POST, prefix='user')
clientform = ClientForm(request.POST, prefix='client')
if userform.is_valid() and clientform.is_valid():
user = userform.save()
client = clientform.save(commit=False)
client.user = user
client.save()
login(request, user)
return HttpResponseRedirect('/webapp/')
else:
return HttpResponse('error!')
else:
userform = UserForm(prefix='user')
clientform = ClientForm(prefix='client')
t = loader.get_template('register.html')
c = RequestContext(request, {
'userform':userform,
'clientform':clientform,
})
return HttpResponse(t.render(c))
And here are my Forms:
from registration.forms import RegistrationForm
class UserForm(RegistrationForm):
def save(self):
new_user = User.objects.create_user(
username=self.cleaned_data['username'],
email = self.cleaned_data['email'],
password=self.cleaned_data['password1'])
new_user.backend='django.contrib.auth.backends.ModelBackend'
new_user.save()
return new_user
class ClientForm(forms.ModelForm):
class Meta:
model = Client
exclude = ['user']
I implemented the save() method for UserForm, since RegistrationForm doesn't implement one like any typical form.
Why does one have to go through all the trouble to implement some backend in order to just save a form?
Is there any problem with this simple way? It does work.
(I also added the new_user.backend='django.contrib.auth.backends.ModelBackend' so I could login the user automatically after registration.)
I'm not sure how to answer your question. If your code works then I don't see a problem. But as zaphod said, django-registration does the saving and activating of the user for you.. If you want to add extra data to your user then use django-profiles like zaphod suggested too.
I myself use django-userena. It is like django-registration and django-profiles in one.
Why do you need to save the User model? django-registration does it for you, unless you need some different functionality.
If you want to store some extra information per user, it might be better to use User profiles.

How to pass parameters retrieved from form submit as arguments to a function in django

I have just started learning django. I created a form from django models. On the click of submit button the data is getting stored in database. Now what i want is something like the one given below :
#view.py
def contact(request):
if request.method == 'POST':
form = UserForm(request.POST)
if form.is_valid():
user = form.save()
return HttpResponseRedirect("/contact/create_db")
#urls.py
(r'^contact/$', views.contact),
(r'^contact/create_db$', views.do_create),
Now when i define do_create function in views.py i want to pass the arguments(user data of user form) like this:
def do_create(request, password, dbname, admin_password, confirm_password, demo_data=False, language=None, **kw):
Is this possible using django. How can this be achieved.
All you're asking here is how to get the value of the saved user in a subsequent view.
Well, this is easy. Once the user is saved, it (like any model instance) gets a pk value. You can use this in the URL for the subsequent view.
url(r'^contact/create_db/(?P<user_id>\d+)/$', views.do_create, 'do_create'),
In contact:
from django.shortcuts import redirect
...
user = form.save()
return redirect('do_create', kwargs={'user_id': user.pk})
And in do_create:
def do_create(request, user_id):
user = User.objects.get(pk=user_id)
Note the way I've passed in the URL name and arguments into redirect, rather than hard-coding the URL.
You don't need to pass them into a view. You want to pass them into a form. And you are already doing this:
form = UserForm(request.POST)
You pass your POST data into the form. If you want to do something with this data, use form.cleaned_data dictionary after form validation. Reading docs is also a good idea.