I am creating alogin view in which when user is not none then logged in it should go to same page before login , then also go to other url , but it always goes to the other url though it should go to first redirect
views.py
def login_page(request):
form = LoginForm(request.POST or None)
context = {
"form": form
}
next_get_url= request.GET.get('next')
next_post_url= request.POST.get('next')
redirect_path = next_get_url or next_post_url or None
if form.is_valid():
print(form.cleaned_data)
username = form.cleaned_data.get("username")
password = form.cleaned_data.get("password")
user = authenticate(request, username=username, password=password)
print(user)
if user is not None:
login(request, user)
if is_safe_url(redirect_path, request.get_host()):
return(redirect(redirect_path))
else:
return (redirect('/'))
else:
print ("Error")
return render(request, "accounts/login.html",context)
forms.py:
class LoginForm(forms.Form):
username = forms.CharField()
password = forms.CharField(widget=forms.PasswordInput)
i mean it always go to this case:
else:
return (redirect('/'))
whenever this is the case:
if is_safe_url(redirect_path, request.get_host()):
return(redirect(redirect_path))
all tries and solutions found did not solve this any help! and thanks in advance
Firstly, Django comes with a LoginView that handles the redirect for you. it would be better to use that than write your own view.
If you do write your own view, then you need to include your redirect_path in your context dictionary here is where Django does is, and then you need to include it as a hidden field in the login form (see the example template in the docs for LoginView:
<form ...>
...
<input type="submit" value="login">
<input type="hidden" name="next" value="{{ next }}">
</form>
You should use
redirect_path = next_get_url or next_post_url or "/"
because if you pass None to is_safe_url, it will return False as it only takes valid urls.
try a render methodes li this
def my_view(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
# Redirect to a success page.
render(request , 'bootstrap/page_learn.html')
else:
# Return an 'invalid login' error message.
render(request , 'bootstrap/page_learn.html')
Related
I'm trying to create a login form for my website, but I cannot log into any existing account.
def loginPage(request):
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, 'User does not exist')
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect('home')
else:
messages.error(request, 'Invalid username/password')
context = {}
return render(request, 'base/login_register.html', context)
Even if I use the correct credentials, it will display:
User does not exist
Invalid username/password
I've also added this to my settings.py:
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
)
I've created those accounts manually from the Django admin account, not with a registration form, could this be the issue?
I found the problem. In the html login file, I was missing name="username" and name="password" in the corresponding inputs.
Here is the login method in the view:
def login(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = auth.authenticate(username=username, password=password)
if user is not None:
auth.login(request, user)
return redirect('forum')
else:
messages.info(request, 'Username or password is wrong!')
return render(request, 'login.html')
return render(request, 'login.html')
Here is how I wrote my codes:
In the views module: I've register method and login method which both work properly.
However, I've other methods who required login in order to access them, since I redirect only a page at a time, I can't get the same username across the pages that required login before to access them.
Now the problem is, how to create another page who treats data came from the forum by conserving the same username from the loggin.
PS: In the forum, I can get the username but how to maintain the same username, is the problem
Thanks :)
If I understood the issue, you want to use user after login.
def login(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = auth.authenticate(username=username, password=password)
if user is not None:
auth.login(request, user)
return redirect('forum')
else:
messages.info(request, 'Username or password is wrong!')
return render(request, 'login.html')
return render(request, 'login.html')
def another_page(request, *args, **kwargs):
user = request.user
...
In every template you can get username from user object:
{% if user.is_authenticated %}
{{ user.username }}
{% endif %}
user is an object that django shares to it's templates
My redirect for my login page is not working correctly when I submit a form.
def login_page(request):
form = LoginForm(request.POST or None)
context = {
'form': form,
}
print(request.user.is_authenticated)
if form.is_valid():
username = form.cleaned_data.get("username")
password = form.cleaned_data.get("password")
user = authenticate(request, username=username, password=password)
if user is not None:
print(request.user.is_authenticated)
login(request, user)
# Redirect to a success page.
return redirect("login")
else:
# Return an 'invalid login' error message.
print("Error")
return render(request, "content/login.html", context)
I am expecting it to redirect to same page and print an output that lets me know the authentication worked. But this is what actually happens..
Page not found(404)
Request Method: GET
Request URL:http://127.0.0.1:8000/login/POST?username=stone&password=pass
Any idea as to what is going on?
You haven't shown your template, but it looks like you have action="POST" instead of method="POST" in your form tag.
Be sure, that your template.html looks like this:
<form method="post">
{% csrf_token %}
{{ form }}
</form>
def login_user(request):
if request.user.is_authenticated():
return redirect(reverse('homepage'))
form = LoginForm(request.POST or None)
if request.method == "POST":
if form.is_valid():
user = authenticate(username=form.cleaned_data['email'], password=form.cleaned_data['password'])
if user is not None:
login(request, user)
return redirect(reverse('homepage'))
else:
error_message = "* Password you entered is incorrect."
return render(request, "account/login.html",{
"form": form,
"error_message": error_message,
})
else:
return render(request, "account/login.html", {
"form": form,
})
I want to create a landing page similar to linkedin's where it has the signup form and the login form at the navbar. I'm currently using a single form for both the signup and login in forms.py:
forms.py
class UserRegisterForm(UserCreationForm):
firstname = forms.CharField(max_length=200, label='')
lastname = forms.CharField(max_length=200, label='')
email = forms.EmailField(label='')
class Meta:
model = User
fields = ['username', 'firstname', 'lastname', 'email', 'password1']
My template includes 2 {{ form }}s and each has a submit button.
Button for the sign up {{ form }}:
name='signupbtn' type='submit'
Button for the login {{ form }}:
name='loginbtn' type='submit'
Now I have trouble trying to login or authenticate the user that I created (which is the super user). My signup/login view goes as follows:
def index(request):
if request.method == 'POST':
if 'signupbtn' in request.POST:
form = UserRegisterForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Your account has been created! You may now login.')
return redirect('index')
elif 'loginbtn' in request.POST:
username = request.POST['username']
password = request.POST['password1']
form = UserRegisterForm(request.POST)
if form.is_valid():
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
return redirect('home')
else:
form = UserRegisterForm()
return render(request, 'users/index.html', {'form': form})
Is it possible that I need to create 2 forms in my forms.py? When I try to login, it doesn't go past the form.is_valid() under elif 'loginbtn' in request.POST:. Also both forms have {% csrf_token %}.
I got everything to work by just simply REMOVING the form.is_valid() and adjusting the view after that.
When a user accesses a url which requires login. The view decorator redirects to the login page. after the user enters his username and password how can I redirect the user to the page he was trying to access ('next') ?
Views.py
def login_view(request):
template = 'pos/login.html'
form = LoginForm
if request.method == 'POST':
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
messages.success(request, "You have logged in!")
return redirect('home')
else:
messages.warning(request, "Your account is disabled!")
return redirect('/login')
else:
messages.warning(request, "The username or password are not valid!")
return redirect('/login')
context = {'form': form}
return render(request, template, context)
#login_required(redirect_field_name='next', login_url='/login')
def bar(request):
template = 'pos/bar.html'
drink = OrderItem.objects.filter(product__catgory__gt=1).order_by('-created')
context = {'drink': drink}
return render(request, template, context)
Login.html
<form action="/login" id="login_form" method="post" class="form-signin">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-lg btn-primary btn-block" type="submit" value="login">Sign in</button>
<input type="hidden" name="next" value="{{next}}" />
</form>
url.py
url(r'^login', views.login_view, name='login'),
forms.py
class LoginForm(AuthenticationForm):
username = forms.CharField(label="Username", required=True, max_length=30,
widget=forms.TextInput(attrs={
'class': 'form-control',
'name': 'username'}))
password = forms.CharField(label="Password", required=True, max_length=30,
widget=forms.PasswordInput(attrs={
'class': 'form-control',
'name': 'password'}))
You can try:
return redirect(self.request.GET.get('next'))
The accepted answer does not check for the next parameter redirecting to an external site. For many applications that would be a security issue. Django has that functionality inbuilt in form of the django.utils.http.is_safe_url function. It can be used like this:
from django.shortcuts import redirect
from django.utils.http import url_has_allowed_host_and_scheme
from django.conf import settings
def redirect_after_login(request):
nxt = request.GET.get("next", None)
if nxt is None:
return redirect(settings.LOGIN_REDIRECT_URL)
elif not url_has_allowed_host_and_scheme(
url=nxt,
allowed_hosts={request.get_host()},
require_https=request.is_secure()):
return redirect(settings.LOGIN_REDIRECT_URL)
else:
return redirect(nxt)
def my_login_view(request):
# TODO: Check if its ok to login.
# Then either safely redirect og go to default startpage.
return redirect_after_login(request)
You can try by simply add this input field before submit button in accounts/login.html template
<input type="hidden" name="next" value="{{ request.GET.next }}"/>
Passing next to the login form and then the form passing that value on to view in a hidden input can be a bit convoluted.
As an alternative, it's possible to use django.core.cache here.
This way there is no need to pass anything extra to the form or to give the form an extra input field.
def login_view(request):
if request.method == 'GET':
cache.set('next', request.GET.get('next', None))
if request.method == 'POST':
# do your checks here
login(request, user)
next_url = cache.get('next')
if next_url:
cache.delete('next')
return HttpResponseRedirect(next_url)
return render(request, 'account/login.html')
This actually works for me quite nice:
from django.shortcuts import redirect
def login(request):
nxt = request.GET.get("next", None)
url = '/admin/login/'
if nxt is not None:
url += '?next=' + nxt
return redirect(url)
If previous URL contained next - call "login" URL and append the previous "next" to it.
Then, when you logged in - you'll continue with the page that was previously intended to be next.
In my project I made the following helper which works for Swagger login/logout:
def _redirect(request, url):
nxt = request.GET.get("next", None)
if nxt is not None:
url += '?next=' + nxt
return redirect(url)
def login(request):
return _redirect(request, '/admin/login/')
def logout(request):
return _redirect(request, '/admin/logout/')
Yes Arun Ghosh option is better but it leads to an exception in cases where there is no next value is found.
Hence I used this approach.
try: return redirect(request.GET.get('next')) except TypeError: return HttpResponseRedirect(reverse("default_app:url_name"))
OR
except Exception as e: return HttpResponseRedirect(reverse("default_app:url_name"))
path_redirect = request.get_full_path().split('?next=',1)
if '?next=' in request.get_full_path():# Redirecting After Login
return redirect(path_redirect[1])
else:
return redirect('index')