I want to use django's default password reset view "PasswordResetView" which let's the user reset his password when he forgets it in a template that already has a view that i built on my own, after looking at the tutorials and the questions i found how to use it only on a different template that is made only for the password reset, but i don't want the user to go to a different page just to change his password when he forgets it, i want to make it in a bootstrap modal in the home page.
here is my home view that i want to add PasswordResetView functionality to it:
def home(request):
user = request.user
signin_form = SigninForm()
signup_form = SignupForm()
if request.method == "POST":
if 'signin_form' in request.POST:
signin_form = SigninForm(request.POST)
if signin_form.is_valid():
email = request.POST['email']
password = request.POST['password']
user = authenticate(email=email, password=password)
if user:
login(request, user)
elif user is None:
messages.error(request, 'ُEmail or password is incorrect')
if 'signup_form' in request.POST:
signup_form = SignupForm(request.POST)
if signup_form.is_valid():
signup_form.save()
full_name = signup_form.cleaned_data.get('full_name')
email = signup_form.cleaned_data.get('email')
raw_password = signup_form.cleaned_data.get('password1')
account = authenticate(email=email, password=raw_password)
login(request, account)
context = {'signin_form': signin_form,'signup_form': signup_form}
return render(request, 'main/home.html', context)
PS: i tried copy pasting the source code of that view (PasswordResetView) from django's source code in my view but i found some errors because it's a class based view, so if you find this the proper way, guide me to do it
or if i can't merge them somehow how to create a custom one
this is what i found in the other answers which lets you use it in a certain template that has only that view (PasswordResetView) which is not what i want:
from django.contrib.auth import views as auth_views
path('password_reset/', auth_views.PasswordResetView.as_view(template_name="myapp/mytemplate.html",form_class=mypasswordresetform),name="reset_password"),
I'll give you a simple approach to having a password reset feature on your django application. Before having any code, let me give a brief exlanation of the process. What you want to do is get a user to input their email, check if there is any user with that email, then if there is one, send an email to that address with a uniquely generated link.
From this link, you should be able to extract the user object which you need to change password. An example would be to use django's signing module. This link will simply need to redirect the user to a template where there is a form with 2 fields i.e. New Password and Verify Password.
Django's generic views come with this functionality out-of-the-box if you are using Django's authentication module, but you aren't forced to use it, but its best to do so.
Here I'll only show you how to collect the email address on the same view as you said you wanted.
def home(request):
# ...your other code
if request.method == 'post':
if 'reset_password' in request.POST:
email = request.POST.get("email", "")
user_qs = User.objects.filter(email=email)
if not user_qs.exists():
# send error message to user here
else:
user = user_qs.get()
# send email with uniquely generated url here.
The other aspects of generating a URL and sending the mail, I believe you can research these separately. But I hope you now have an idea of where and what to search.
Related
I am working on a basic login form for a hybrid React/Django web app. I would like to use the built in data-cleaning and validating methods of the Django Form models, but our frontend is pure React. Everything works as far as logging in, but I am feeding the raw body data into the authenticate function as shown here.
def login_view(request):
if request.method == "POST":
form_data = json.loads(request.body.decode('utf-8'))
user = authenticate(request, email=form_data["username"], password=form_data["password"])
if user == None:
request.session["invalid_user"] = 1
logging.warning("Login form contains no user")
login(request, user)
My question is, is there any way to feed this form_data into the Django native LoginForm when I instantiate it? I would prefer to not recode all of the input validation that Django does already.
I've tried instantiating a LoginForm like so:
form = LoginForm(data=form_data)
And then tried running form.full_clean(), but it doesn't seem to work. Any help would be greatly appreciated, thank you!
The issue was actually a difference in the variable names between the rendered React form and the Django LoginForm I had defined. One was username and password, the other email and password. With that in mind the usual way of working with forms works great!
if request.method == "POST":
form_data = json.loads(request.body.decode('utf-8'))
form = LoginForm(data=form_data)
if form.is_valid():
email = form.cleaned_data["email"]
password = form.cleaned_data["password"]
user = authenticate(request, email=email, password=password)
if user is not None:
login(request, user)
Django's authenticate function seems to always be returning none, ive already checked out this thread and updated the authentication backends in the settigns.py file.
This is the code that i am using to save the accounts being created:
if request.method == 'POST':
# Getting the information from the filled in UserCreationForm
user_form = UserCreationForm(data=request.POST)
# If the the form is valid then save the users data to the database
# hash the password using set_password and save the user again
# set registered to True
if user_form.is_valid():
user = user_form.save()
user.set_password(user.password)
user.save()
registered = True
# Invalid form or forms - mistakes or something else?
# Print problems to the terminal.
# They'll also be shown to the user.
else:
print user_form.errors
# Not a HTTP POST, so these forms will be blank, ready for user input.
else:
user_form = UserCreationForm()
# Render the template depending on the context.
return render_to_response(
'contracts/register.html',
{'user_form': user_form, 'registered': registered}, context)
This seems to be working, since after i create a new user on the site, the access database its linked to updates with that username and the encrypted password.
The user_from is created from UserCreationForm which is:
class UserCreationForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username','password','first_name','last_name','email','is_staff','is_active')
Here is the code in my user_login method which should be grabbing the username and password from the request and authenticating the combo
def user_login(request):
# context for the user's request.
context = RequestContext(request)
# form = AuthenticationForm()
# If the request is a HTTP POST
if request.method == 'POST':
# Gather the username and password provided by the user.
# This information is obtained from the login form.
user = request.user
userSubmit = user.username
passSubmit = user.password
#username = request.POST.get['username']
#password = request.POST.get['password']
user = authenticate(username = userSubmit, password=passSubmit)
#try:
# user = authenticate(username=userSubmit, password=passSubmit)
#except LockedOut:
# messages.error(request, 'You have been locked out because of too many login attempts. Please try again in 10 minutes.')
# If we have a User object, the details are correct.
# If None (Python's way of representing the absence of a value), no user
# with matching credentials was found.
else:
if user:
# Is the account active? It could have been disabled.
if user.is_active:
# If the account is valid and active, we can log the user in.
# We'll send the user back to the homepage.
login(request, user)
return redirect('home')
else:
# An inactive account was used - no logging in!
messages.error(request, 'Your account is disabled.')
else:
messages.error(request, 'The credentials you entered are invalid.')
# Bad login details were provided. So we can't log the user in.
# The request is not a HTTP POST, so display the login form.
# This scenario would most likely be a HTTP GET.
# No context variables to pass to the template system, hence the
# blank dictionary object...
return render_to_response('administrative/login.html', {'form': form}, context)
I created a profile page with django to let users change their information that I gave in sing up form . (such as name, email, password)
I have two problem on password field :
1 - when user insert a password in text field, it's submitted in raw format, and I need django user's table format
<algorithm>$<iterations>$<salt>$<hash>
my view for profile page :
def user_profile(request):
current_user = request.user
form = UserProfileForm(request.POST or None, instance=current_user)
if request.POST:
if form.is_valid():
# pwd = form.cleaned_data['password']
# form_obj = form.save(commit=False)
# form_obj.password = make_password(pwd)
form.save()
message = "saved successfully"
return render(request, 'Profile.html', {'form':form, 'message':message}, context_instance=RequestContext(request))
return render_to_response('Profile.html', {
'form': form,
}, context_instance=RequestContext(request))
as you can see in comments, I used make_password function to hash password and it works fine BUT after submitting page, user can't go to other pages and need re-login ... why ?!
2 - when the profile page shows to user, it's filled with current informations in database, and password is also in the above format (hash)
and if user submit the form, without any change in password field, it's password changed (it sends hash one and hash it again !)
how can I solve this problems and make a simple working profile page in django ? (I really don't like it's own admin panel ! it doesn't look nice !)
From the documentation:
Changing a user’s password will log out all their sessions if the SessionAuthenticationMiddleware is enabled.
So you have to use update_session_auth_hash(request, user)
For more info, see https://docs.djangoproject.com/en/1.9/topics/auth/default/#session-invalidation-on-password-change
Regarding the password field being pre-populated: you should set the field as a passwordInput which, by default, is not pre-populated, see https://docs.djangoproject.com/en/1.9/ref/forms/widgets/#django.forms.PasswordInput
So I'm currently trying to implement an already existing application for payment processing via Braintree (https://github.com/Tivix/django-braintree for reference). It seems like all the meat of this application is placed at the /payments-billing/ directory but I can't seem to get into it to check it out. It seems like what's stopping me is a #login_required decorator placed just before the view since whenever I access the directory it sends me back to the defined LOGIN_URL. However I have set up a login feature at the LOGIN_URL that authenticates the user and then sends them to /payments-billing/ but it just redirects back again. Here is my code:
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(username=username, password=password)
if user is not None:
# Password verified for user
if user.is_active:
return redirect(self.success_url)
else:
return redirect('/')
else:
return redirect('/')
Clearly the user is being authenticated and is active since it passes both tests when you try it, but it always just sends the user back to the LOGIN_URL rather than /payments-billing/. Anyone know what's the deal here?
The authenticate function doesn't log a user in, it just checks their username/password. You also have to call django.contrib.auth.login() to do the actual logging in. See the example in the documentation.
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(username=username, password=password)
login(request, user)
### Now it should get redirected to /payments-billing/
if user is not None:
# Password verified for user
if user.is_active:
return redirect(self.success_url)
else:
return redirect('/')
else:
return redirect('/')
How can I log-in the user programmatically in Django? I have the username and password of the User. Is there a method that let's me log him in?
There is no other way than "programmatically". Of course, this is documented.
from django.contrib.auth import authenticate, login
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
Alsways be careful when programmatically logging users in, you might get the error ´user has no attribute "backend". You have to set the backend too if that has no happened previously. Project that uses this and some sample code:
def splash_register(request):
if request.session.get('beta'):
if request.method=='POST':
userform=MyUserCreationForm(request.POST)
if userform.is_valid():
#username of <30 char is required by Django User model. I'm storing username as a hash of user email
user=userform.save(commit=False)
user.username=hash(user.email)
user.backend='django.contrib.auth.backends.ModelBackend'
user.save()
username=user.username
password=str(userform.cleaned_data['password'])
auth.login(request, user)
request.session['first_visit']=True
return HttpResponseRedirect("/")
else:
userform=MyUserCreationForm(request.POST)
return render_to_response("website/splash_register.html", {'userform':userform}, context_instance=RequestContext(request))
return render_to_response("website/splash_register.html", context_instance=RequestContext(request))
else:
return HttpResponseRedirect('/splash/')
The accepted answer definitely works but, I prefer to use the Django built in auth forms, like django.contrib.auth.forms.AuthenticationForm
Here is a snippet that shows the important part
form = AuthenticationForm(request, data=request.POST)
if form.is_valid():
try:
form.clean()
except ValidationError:
# handle error
login(request, form.get_user())
The major difference in this approach is that AuthenticationForm.clean method calls authentication function for you and checks User.is_active for you as well.