"next" is not redirecting to expected position - django

I am making a wallet app so if someone goes to http://127.0.0.1:8000/add_money/ to add money and they are not logged in they will be redirected to the login page with next there after the user logs in it should be redirected back to add_money but it is being redirected to their profile.
//ADD MONEY VIEW
def add_money(request):
if not request.user.is_authenticated():
return render(request, 'registration/login.html', {"next": '/add_money/'})
else:
if request.POST:
username = request.user.username
add_amount = request.POST['amount']
wallet = Wallet.objects.filter(username=username).update(add_money(add_amount))
now = datetime.now()
trans = Transaction(from_name=username, wallet_id=wallet.id, date=now, amount=add_amount)
trans.save()
return render(request, 'user_profile.html', {'user': request.user})
return render(request, 'registration/login.html', {"next": '/add_money/'})
//Login View
def user_login(request):
if request.POST:
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
if request.POST['next']:
return render(request, '/add_money/')
return render(request, 'user_profile.html',{'user': user, 'wallet': user.userprofile.wallet_id})
else:
return render(request, 'registration/login.html', {'error': 'User is not active'})
else:
return render(request, 'registration/login.html', {'error': 'User does not exist'})
else:
return render(request,'registration/login.html')
//login template
{% if next %}
<form action="/login/?next={{next}}" method="post">
<input type="hidden" name="next" value={{ next }}>
{%else%}
<form action="/login/" method="post" >
{% endif %}
USERNAME <input type="text" name="username">
PASSWORD <input type="password" name="password">
<input type="submit">
<input type="hidden" name="next">
{% csrf_token %}
</form>
//add_money template
<form action="user_profile.html" method="post">
Amount:<input type="number" name="amount">
<input type="submit" value="Submit">
<button type="button" name="cancel">Cancel</button>
</form>

I'm not sure it how it even manages to get to the account page since you're using the render tag as a mixture of render and redirect.
return render(request, '/add_money/')
You should return a redirect response back to the next url instead
return HttpResponseRedirect(request.GET['next'])
Also, you're passing the next to the login template, not the url
if not request.user.is_authenticated():
return render(request, 'registration/login.html', {"next": '/add_money/'})
you should redirect to the login page here as well with next as a get parameter
return HttpResponseRedirect('/login/?next={}'.format('/add_money/')
You should also look into using the provided url reversing methods instead of hard coding urls
You also should remove the whole if next in the template and just let the login action be the default for the page
{% if next %}
<form action="/login/?next={{next}}" method="post">
<input type="hidden" name="next" value={{ next }}>
{%else%}
<form action="/login/" method="post" >
{% endif %}
should be
<form method="post" >

Related

Trying to render two different views in one template according to their specific url routing

Im trying to render login and register view in a single template using variable assignment and if-else. I'm sorry if its a rookie mistake, Im pretty new to this..
github repo- https://github.com/varundhand/DevSearch
my urls.py :-
urlpatterns = [
path('login/',views.loginUser,name='login'),
path('logout/',views.logoutUser,name='logout'),
path('register/',views.registerUser,name='register'),
path('',views.profiles,name='profiles'),
path('profile/<str:pk>/',views.userProfile,name='user-profile'),
]
my views.py :-
def loginUser(request):
page = "login"
if request.user.is_authenticated:
return redirect('profiles')
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
try:
user = User.objects.get(username=username)
except:
messages.error(request,'Username doesnt exist')
user = authenticate(request,username=username,password=password)
if user is not None:
login(request,user)
return redirect ('profiles')
else:
messages.error(request,'Username/Password incorrect')
context = {page:'page'}
return render(request, 'users/login_register.html', context)
def logoutUser(request):
logout(request)
messages.error(request,'User was logged out!')
return redirect('login')
def registerUser(request):
page = "register"
context= {page:'page'}
return render(request,'users/login_register.html', context)
my html template file :-
{% extends 'main.html' %}
{% block content %}
{% if page == "register" %}
<h1>Register User</h1>
<p>Already have an account? Login </p>
{% else %}
<form action="{% url 'login' %}" method="POST">
{% csrf_token %}
<input type="text" name="username" placeholder="Username">
<input type="pass`your text`word" name="password" placeholder="Enter Password">
<input type="submit" value="Login">
<p>Dont have an account? Sign Up</p>
</form>
{% endif %}
{% endblock content %}
My Approach
I gave variable assignment of page='login' and page='register' in loginUser and registerUser view respectively and then i gave an if-else in my common template but for some reason only loginUser view is working even when i go to the register url.
Ignore my silly question, I was passing the wrong context dictionary i.e. it shoulda been context = {'page':page}

why authenticate is not working for user objects despite having objects saved in admin panel in Django

here is my loginHtml code
<form method="post" action="handleLogin_url" enctype="multipart/form-data">
{{ tryAgain }}
<br>
{% csrf_token %}
<label for="username">Enter Username</label><input id="username" name="username" type="text">
<label for="password">Enter password</label><input id='password' name="password" type="password">
<input type="submit" value="Lets Go">
views.py
def handleLogin(HttpRequest):
if HttpRequest.method=='POST':
enteredname = HttpRequest.POST['username']
# user = User.objects.get(username=enteredname)
enteredpassword = HttpRequest.POST['password']
user = authenticate( HttpRequest, username=enteredname,password=enteredpassword)
# return render(HttpRequest, 'seeData.html',
# {'User': user, 'enteredname': enteredname, 'enteredpassword': enteredpassword})
if user is not None:
return render(HttpRequest, 'seeData.html', {'Users':user, 'enteredname':enteredname, 'enteredpassword':enteredpassword})
else :
tryAgain = "Invalid username or password try again"
return render(HttpRequest, 'LoginHtml.html', {'tryAgain':tryAgain})
else:
return render(HttpRequest,'LoginHtml.html')
seeDataHtml code
{{ User.username }},{{ User.password }}||{{ enteredname }} {{ enteredpassword }}
when I try using superuser credentials a superuser object is returned but when I use a user credential no object is returned but when I log into admin site I can see user objects
You doing here a lot of mistakes first thing your HTML should look like this:
<div class="container py-5">
<form method="POST" enctype="multipart/form-data">
<div class="mb-3">
{% csrf_token %}
{{login_form}}
</div>
<input type="submit" name="Log in" class="btn btn-primary"></input>
</form>
{% for message in messages %}
{% if message.tags %}
<span class="{{ message.tags }}"> </span>
{{ message }}
{% endif %}
{% endfor %}
<br>
Forgot Password
</div>
In views.py
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth import login as login_auth, authenticate
from django.contrib import messages
from django.shortcuts import redirect, render
def login(request):
if request.user.is_authenticated: #to check if user is authenticated
return redirect('home')
if request.method == "POST":
form = AuthenticationForm(request, data=request.POST)
if form.is_valid(): #If form is valid returns True
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if user is not None:
login_auth(request, user)
return redirect('home')
else:
messages.error(request,"Invalid username or password.")
else:
messages.error(request,"Invalid username or password.")
else:
form = AuthenticationForm()
return render(request, 'login.html', {'login_form': form})
Also, I saw that you create a new page to show a message error you can do that using Django messages from django.contrib import messages

In Django, how can we stop losing the details filled in the form, if it fails validation?

I am using the UserCreationForm for user registration in my Django web app. When the user fills in the detail (username, password, confirm_password) and submits, then if the form fails validation (maybe because username already exists or password don't match or password is too short) then the user is redirected back to the register page.
Now my problem is that when he is redirected back to the register page, the form is blank again, i.e. he has to start all over again, which is not a good user experience because his form might fail one or more times.
I want that if the form fails validation and when he is redirected to the registration form, he should see his previously filled in details so that he can just correct the field which is causing the error and move on. Is there any way the data can be retained?
Here is my code of the register function in views.py:
def register(request):
if request.method == 'POST':
form = UserCreationForm(request.POST or None)
if form.is_valid():
# some code
return redirect('login')
else:
messages.error(request, form.errors)
return HttpResponseRedirect(reverse("register"))
else:
return render(request, 'accounts/register.html')
my register.html:
<form method="POST" action="{% url 'register' %}">
{% csrf_token %}
<input name="username" type="text" class="..." style="...">
<input name="password1" type="password" class="..." style="...">
<input name="password2" type="password" class="..." style="...">
<button type="submit">Sign up</button>
</form>
Edit:
I have not passed the form in context to the template, so that I can control the CSS of my input fields, which I am not sure how to do otherwise without creating forms.py file separately.
If it's not possible to retain details in the form, then what should I do to at least improve the present situation?
Instead of return redirect just render the response with the form object again:
def register(request):
if request.method == 'POST':
form = UserCreationForm(request.POST or None)
if form.is_valid():
# some code
return redirect('login')
messages.error(request, form.errors)
else:
form = UserCreationForm()
return render(request, 'accounts/register.html', {'form': form})
In the template since you want to control css use django-widget-tweaks:
{% load widget_tweaks %}
<form method="POST" action="{% url 'register' %}">
{% csrf_token %}
{% render_field form.username class="..." style="..." %}
{% render_field form.password1 class="..." style="..." %}
{% render_field form.password2 class="..." style="..." %}
<button type="submit">Sign up</button>
</form>
The load widget tweaks must be at the top of the html file like all load tags.
def register(request):
context = {}
if request.method == 'POST':
form = UserCreationForm(request.POST or None)
if form.is_valid():
# some code
return redirect('login')
else:
context['form'] = form
messages.error(request, form.errors)
context['form'] = UserCreationForm()
return render(request, 'accounts/register.html', context)
it should work

Django 403 Forbidden CSRF

recently I am seeing a weird error in my Django application. When I try to sign in, Chrome is stuck on "Processing request". After I click on the login button again it gives me the 403 Forbidden CSRF verification failed error. However, when I click on the Back button and press login again with the same user credentials it logs in successfully. I do not know why this is happening. I have two Django applications which 'home' and 'main', after correct credentials it should take the user to the view of 'home' applications.
My main/user_login.html
<form method="POST" action="{%url 'main:user_login' %}" class="form-signin">
{% csrf_token %}
<div class="form-label-group">
<input type="text" name="username" id="inputText" class="form-control" placeholder="Username" required autofocus>
<br/>
</div>
<div class="form-label-group">
<input type="password" name="password" id="inputPassword" class="form-control" placeholder="Password" required>
</div>
<div class="custom-control custom-checkbox mb-3">
<input type="checkbox" class="custom-control-input" id="customCheck1">
<label class="custom-control-label" for="customCheck1">Remember password</label>
</div>
<input type="submit" class="form-control" name="" value="Login">
<hr class="my-4">
<p>Don't have account? Sign up here</p>
{% if message %}<p style="color: red;">{{ message }}</p>{% endif %}
Forgot Password
</form>
my main/views.py:
def user_login(request):
if request.method == 'POST':
form = AuthenticationForm(request, data=request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if user is not None:
login(request,user)
messages.info(request, "Successfully signed in")
return redirect(reverse('home:home'))
else:
message = 'Sorry, the username or password you entered is not valid please try again.'
return render(request, 'home/user_login.html', {'message':message})
else:
message = 'Sorry, the username or password you entered is not valid please try again.'
return render(request, 'home/user_login.html', {'message':message})
else:
form=AuthenticationForm()
return render(request, 'home/user_login.html', {"form":form})
my home/views.py:
#login_required
def home(request):
context = {
'posts': Post.objects.all()
}
return render(request, 'home/home.html', context)
I do not understand what is causing the issue which as I mentioned before after going back and clicking on login again the user can successfully login.
Thanks in advance!
Edit: I have realized what causes the error it is the else statement that throws the error message. I have changed my view right now it does not give me an error but I have to click on the login button twice else it would get stuck again. My view is now:
def user_login(request):
if request.method == 'POST':
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = authenticate(request, username=username, password=password)
if user is not None:
return redirect('home:home')
else:
messages.error(request,'Sorry, the username or password you entered is not valid please try again.')
return HttpResponseRedirect('/')
else:
form=AuthenticationForm()
return render(request, 'main/user_login.html', {"form":form})
And my user_login.html is now:
<form method="POST" action="{% url 'main:user_login' %}" class="form-signin">
{% csrf_token %}
<div class="form-label-group">
<input type="text" name="username" id="inputText" class="form-control" placeholder="Username" required autofocus>
<br/>
</div>
<div class="form-label-group">
<input type="password" name="password" id="inputPassword" class="form-control" placeholder="Password" required>
</div>
<div class="custom-control custom-checkbox mb-3">
<input type="checkbox" class="custom-control-input" id="customCheck1">
<label class="custom-control-label" for="customCheck1">Remember password</label>
</div>
<input type="submit" class="form-control" name="" value="Login">
<hr class="my-4">
<p>Don't have account? Sign up here</p>
{% for message in messages %}
<p style="color: red;">{{ message }}</p>
{% endfor %}
Forgot Password
</form>
This is causing the issue:
else:
messages.error(request,'Sorry, the username or password you entered is not valid please try again.')
return HttpResponseRedirect('/')
Try this one:
#login_required
def home(request):
post = Post.objects.all()
context = {'post':post}
return render(request, 'home/home.html', context)
I think the problem might be in else block.
Just try this one:
def user_login(request):
if request.method == 'POST':
form = AuthenticationForm(request, data=request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if user is not None:
login(request,user)
messages.info(request, "Successfully signed in")
return redirect(reverse('home:home'))
else:
message = 'Sorry, the username or password you entered is not valid please try again.'
return render(request, 'home/user_login.html', {'message':message})
else:
form=AuthenticationForm()
return render(request, 'home/user_login.html', {"form":form})
Django's built-in tags need spaces
fix this in your form: action="{% url 'main:user_login' %}"

Django why i still got CSRF verification failed?

my template is below:
<div id="divLogin">
{% block login %}
<form action="/login" method="post">
{% csrf_token %}
<label for="id_name"></label><input type="text" name="email" id="id_name" placeholder="Your Email">
<label for="id_pass"></label><input type="password" name="password" placeholder="Your Password">
<input type="submit" id="btnLogin" value="Log In" class="btn">
</form>
{% endblock %}
</div>
I have already add {% csrf_token %} in template, and my login view is
def login_view(request):
if request.method == 'POST':
useremail=request.POST['email']
password=request.POST['password']
try:
user=User.objects.get(email=useremail)
if user.check_password(password):
uAuth=authenticate(username=user.username,password=password)
login(request,uAuth)
return render_to_response("blog.html",{'loginuser':user},context_instance=RequestContext(request))
except User.DoesNotExist:
return redirect('/')
return redirect('/')
Even i used render_to_response and RequestContext i still got error.
there is one thing very wired, i put a breakpoint to login_view method, but csrf error point out before it go into login_view methond. so there is no response about this method?
Is there anything wrong about my code?
I have add django.middleware.csrf.CsrfViewMiddleware in MIDDLEWARE_CLASSES in my settings.py.
You must use redirect after post.
Redirect to a view that renders your template.
def login_view(request):
if request.method == 'POST':
useremail=request.POST['email']
password=request.POST['password']
try:
user=User.objects.get(email=useremail)
if user.check_password(password):
uAuth=authenticate(username=user.username,password=password)
login(request,uAuth)
return HttpResponseRedirect('/someurl')
except User.DoesNotExist:
return redirect('/')
else:
return render_to_response('login.html',context_instance=RequestContext(request))
def someurl(request):
if request.method == 'GET':
render_to_response("blog.html",
{'loginuser':user},context_instance=RequestContext(request))