What would be the best implementation to redirect a user who is not signed in? Is there a better way then to use a #is_autenticated type decerator in every single view?
The alternative I have thought of is to have a base.html which checks for is_authenticated and every html will extend base. Ex:
base.html
{% if request.user.is_authenticated %}
{% block content %}
content here
{% endblock content %}
{% else %}
redirect
I feel though this way puts view logic into the template which really doesn't sit well but it would avoid a decorator on every function.
You could use some middleware. Personally, I think having the redirect in the template (I'm assuming in javascript code) is very ugly. Django-stronghold (https://github.com/mgrouchy/django-stronghold) is nice if most views require authentication.
Django has an in-built authentication model.Authentication logic should always be in the views and including view logic in the template is a bad practice.Once the user is authenticated, you can render a homepage from the views along with a welcome message.You can do the following:
from django.contrib.auth import authenticate
# login to home page -
def home(request):
try:
username = password = ''
if request.POST:
username = request.POST['username']
password = request.POST['password']
print username
print password
user = authenticate(username=username, password=password)
print "User value is",user
if user is not None:
if user.is_active:
login(request, user)
request.session['username'] = username
return render_to_response('home.html',{"message": "Welcome"})
# Redirect to a success page.
else:
return render_to_response('login.html',{"message": "User is Inactive"})
# Return a 'disabled account' error message
else:
return render_to_response('login.html',{"message": "Invalid Credential"})
else:
return render_to_response('home.html',{"user" : request.session['username']})
except:
return render_to_response('error.html',{"message": sys.exc_info()[0]})
Related
I am using #login required decorator in my most of views so what I want is to use message in my login page telling user if you want to open that page you have to login first so how I can achieve that I know I cannot achieve that on my views so anyone does that and know how to do please tell me how to achieve that if a user redirected to login because of #login required I want to show message please login to continue
I also looked on some of the same question I am looking for answer which got implemented on all the login required decorator so I don't have to change code everywhere it already got implemented in all of the login required decorator in my whole app
my login view
def my_login(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data["username"]
password = form.cleaned_data["password"]
remember_me = form.cleaned_data['remember_me']
user = authenticate(username=username, password=password)
if user:
login(request, user)
if not remember_me:
request.session.set_expiry(0)
return redirect('accounts:home')
else:
request.session.set_expiry(1209600)
return redirect('accounts:home')
else:
return redirect('accounts:login')
else:
return redirect('accounts:register')
else:
form = LoginForm()
return render(request, "login.html", {'form': form})
Solution 1:
In your view, check the query parameter "next", as if the user is redirected to the login view, it would come with the ?next=/whatever in the URL. You can do
if 'next' in request.GET:
messages.add_message(request, messages.INFO, 'Hello world.')
Solution 2 (not recommended, this makes it confusing to debug for others):
Python being a dynamic language, you can hijack the behaviour of login_required with your version.
in your manage.py and wsgi.py and maybe asgi.py you would need to "monkey patch" the login_required decorator.
from django.contrib.auth import decorators
def my_login_required(...):
# you can look at the implementation in the answer by LvanderRee mentioned in the comments
decorators.login_required = my_login_required
Now, because these files will be the first code to execute before Django even starts, this will replace the built-in login_required with your version.
Based on this Stack Overflow post, using multiple answers, to redirect to another page, either:
Set LOGIN_URL in settings.py. This is the URL that Django will redirect to if a user that's not yet logged in attempts to log in.
or Inline:
from django.contrib.auth.decorators import login_required
#login_required(login_url='/example url you want redirect/') #redirect when user is not logged in
def myview(request):
do something
return something #returns when user is logged in
Of course, you still need to have the login view setup.
If you want to check if the user is authenticated in the HTML, you can use the templating system: (For clarity this is something I just whipped up right now, it's not from the Stack Overflow post mentioned above)
{% if user.is_authenticated %}
// Display something if authenticated maybe
{% else %}
// Display something like "You are not logged in etc"
{% endif %}
I'm trying to build a login module in django that works independently from the page you are on.
I'm defining the login module in a base.html template that contains the header (the login module sits in the header) all other pages extend this base template.
My plan was to pass the error through the context dictionary, the problem is that I don't know how to make the function render() render the template from which the user attempted to login.
this is my view code:
def login(request):
context_dict = {}
if request.POST:
username = request.POST.get('login_username')
password = request.POST.get('login_password')
user = authenticate(username=username, password=password)
if not user:
context_dict['error'] = 'שם משתמש או סיסמא אין נכונים'
elif not user.is_active:
context_dict['error'] = 'חשבונך נחסם, אם הינך חושב שזאת טעות צור קשר עם מנהל בהקדם.'
else:
login(request,user)
redirect(request.META.get('HTTP_REFERER'))
render(request, ', context_dict)
Finally figured it out, the trick is using the Django messages framework.
here is the code and explanation for anyone who wants to implement something similar:
simple url routing in urls.py file
url(r'^login/$', views.login, name='login'),
url(r'^logout/$', views.logout, name='logout'),
two views, one for login one for logout
def login(request):
if request.POST:
username = request.POST.get('login_username')
password = request.POST.get('login_password')
user = authenticate(username=username, password=password)
if not user:
messages.add_message(request, messages.INFO, 'wrong username or password')
elif not user.is_active:
messages.add_message(request, messages.INFO, 'your account is disabled')
else:
django_login(request,user)
return redirect(request.META.get('HTTP_REFERER'))
return redirect(request.META.get('HTTP_REFERER'))
def logout(request):
django_logout(request)
return redirect(request.META.get('HTTP_REFERER'))
modified import to avoid a recursion error (in views.py)
from django.contrib.auth import authenticate, login as django_login, logout as django_logout
and finally displaying message in template
{% if messages %}
{% for message in messages %}
<div class='login_error'>
{{ message }}
</div>
{% endfor %}
{% endif %}
I am trying to use django-email-as-username and I can't find a way to return to the login page with a message for the user in case the data provided by the user is wrong.
this my urls.py
url(r'^login$', 'django.contrib.auth.views.login', {'authentication_form': EmailAuthenticationForm}, name='login'),
this is my views.py
def login_user(request):
if request.method == 'POST':
email = request.POST.get('email')
password = request.POST.get('password')
if email and password:
user = authenticate(email=email, password=password)
if user:
return HttpResponseRedirect('/')
else:
message = 'No such user'
else:
message = 'both email and password are required!'
else:
message = 'wrong method!'
I think you've made an error in that you're providing your own login_user view in your views.py module, but linking to Django's django.contrib.auth.views.login in your URL conf.
You should probably just use django.contrib.auth.views.login as the login view.
You'll also need to provide a registration/login.html template. You'll be able to get at the error information, as the form is passed through to the context. You can use the admin's login template as an example.
In case of authentication failure, you have to render/redirect your own login page with {{ message }}
Let me modify this question
I have a my own login view as below and am implementing the #login_required decorator.
def do_login(request):
form = LoginForm()# create an instance of a login form
logged_in =request.user.is_authenticated() # get login status
if logged_in:
message='You are logged in '
return render_to_response('login.html',locals())# return
if request.method == 'POST':
usr=request.POST['username'] #get username
passwrd=request.POST['password']# get password
form=LoginForm(request.POST) # create instance of loginform
user=authenticate(username=usr,password=passwrd)# authenticate user
if user is not None:
if user.is_active:
login(request,user) #log user in
return HttpResponseRedirect("/login_success/")
else:
pass
else:
return render_to_response('login.html',locals())
else:
return render_to_response('login.html',locals())
This works, as anytime I try to visit a url (for example to change password)am taken to the loggin page to log in first. While at the login page the url that appears in the address bar is http://myapp.com/login/?next=/change_password/
Now when I login am taken to http://myapp.com/login/login_success/ instead of http://myapp.com/login/change_password/. Upon loggin in I want to be automatically redirected to the intended http://myapp.com/login/change_password/ I tried to get to before asked to login. How do I solve this please
Perhaps something like this
Template:
{% if user.is_authenticated %}
click me
{% else %}
click me
{% endif %}
View:
return HttpResponseRedirect(request.GET.get('next', '/'))
I found out what the problem was. I had to access the url in the next parameter like {{request.GET.next}} instead of {{next}}
So my code changed to :
In templates I added a hidden input to my login form and set its value to {{request.GET.next}}
<input type="hidden" name="next" value="{{ request.GET.next }}" />
So in my login view, I could now access the hidden field's value and use it that value to do my redirection after login
def do_login(request):
form = LoginForm()# create an instance of a login form
logged_in =request.user.is_authenticated() # get login status
if logged_in:
message='You are logged in '
return render_to_response('reg/login.html',locals())# return
if request.method == 'POST':
usr=request.POST['username'] #get username
passwrd=request.POST['password']# get password
form=LoginForm(request.POST) # create instance of loginform
user=authenticate(username=usr,password=passwrd)# authenticate user
if user is not None:
if user.is_active:
login(request,user) #log user in
return HttpResponseRedirect(request.POST['next'])
else:
pass
else:
return render_to_response('reg/login.html',locals())
else:
return render_to_response('reg/login.html',locals())
I want to allow the users to go to their user page by default (like: mywebsite.com/userpage) when they use the login form.
Also if they go to some other password protected page on the web site redirect them to the login page first and once authenticated get them back to the original page they were trying to access.
This is what I have so far for the login function:
views.py
def user_login(request):
if request.method == 'POST':
form = AuthenticationForm(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)
# Redirect to a successpage
if request.POST['next']:
return HttpResponseRedirect(request.POST['next'])
else:
return HttpResponseRedirect("/" + username + "/")
else:
errors = 'This account has been disabeled.'
else:
# Return an 'invalid login' error message.
errors = 'There is a problem with the user name and/or the password. Please try again.'
else:
form = AuthenticationForm()
return render_to_response("registration/my_login.html", locals(), context_instance=RequestContext(request))
urls.py
urlpatterns = patterns('',
url(r'^login/$', user_login,),
my_login.html
<form action="." method="post" >{% csrf_token %}
{{errors}}
{{ form.as_p }}
<p class="submit"><button type="submit" name="login_user_button" value="Login">Log in</button></p>
<input type="hidden" name="next" value="{{ next }}">
</form>
My problem is that I don't know how to get the values of the "next" variable so I can use it in my user_login function for the redirect.
As you can see I tried to get it with request.POST['next'] but comes with an empty string so for some reason no value gets signed to the "next" variable.
Any ideas?
My recommendation - don't bother screwing around with the login function. You're just reinventing the wheel. Instead, use the login view that comes with the django.auth module, and have that send users to an interstitial page (with a URL defined in settings.LOGIN_REDIRECT_URL) that redirects them where they need to go.
This interstitial view could be something as simple as the following:
#login_required
def index(request):
return redirect('user-page', request.user.username)
Note that I've changed that redirect to use a named view. You don't want weird stuff to happen if a user gives himself a username that coincides with a site url!
Also note the login_required decorator. This automatically gives you the login page redirect you require.