I feel like this is an easy question and I'm just missing 1 small step.
I want to do any number of the following (as the term in the next parameter):
[not signed in] -> profile -> login?next=/accounts/profile/ -> auth -> profile.
[not signed in] -> newsfeed -> login?next=/newsfeed/` -> auth -> newsfeed.
Whereas I am currently going:
[not signed in] -> profile -> login?next=/accounts/profile/ -> auth -> loggedin
[not signed in] -> newsfeed -> login?next=/newsfeed/ -> auth -> loggedin
I am looking to somehow pass the next
parameter from a form on login
to auth
and have auth
redirect to this parameter
Currently I am trying in my login.html
:
<input type='text' name="next" value="{{ next }}">
however this is not getting the next value. I can see from the debug tool bar:
GET data
Variable Value
u'next' [u'/accounts/profile/']
views
:
def auth_view(request):
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = auth.authenticate(username=username, password=password)
if user is not None:
auth.login(request, user)
print request.POST
return HttpResponseRedirect(request.POST.get('next'),'/accounts/loggedin')
else:
return HttpResponseRedirect('/accounts/invalid')
login.html
:
{% extends "base.html" %}
{% block content %}
{% if form.errors %}
<p class="error"> Sorry, you have entered an incorrect username or password</p>
{% endif %}
<form action="/accounts/auth/" method="post">{% csrf_token %}
<label for="username">User name:</label>
<input type="text" name="username" value="" id="username">
<label for="password">Password:</label>
<input type="password" name="password" value="" id="password">
<input type='text' name="next" value="{{ request.GET.next }}">
<input type="submit" value="login">
</form>
{% endblock %}
settings
:
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Examples:
url(r'^admin/', include(admin.site.urls)),
('^accounts/', include('userprofile.urls')),
url(r'^accounts/login/$', 'django_yunite.views.login'),
url(r'^accounts/auth/$', 'django_yunite.views.auth_view'),
url(r'^accounts/logout/$', 'django_yunite.views.logout'),
url(r'^accounts/loggedin/$', 'django_yunite.views.loggedin'),
url(r'^accounts/invalid/$', 'django_yunite.views.invalid_login'),
)
settings
:
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
TEMPLATE_DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'debug_toolbar',
'userprofile',
)
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
ROOT_URLCONF = 'django_yunite.urls'
WSGI_APPLICATION = 'django_yunite.wsgi.application'
# Internationalization
# https://docs.djangoproject.com/en/1.6/topics/i18n/
LANGUAGE_CODE = 'en-ca'
TIME_ZONE = 'EST'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.6/howto/static-files/
STATIC_URL = '/static/'
STATICFILES_DIRS = (
('assets', '/home/user/GitHub/venv_yunite/django_yunite/static/'),
)
TEMPLATE_DIRS = (
'./templates',
'/article/templates',
)
STATIC_ROOT = "/home/user/Documents/static/"
AUTH_PROFILE_MODULE = 'userprofile.UserProfile'
the print statment shows an empty u'next'
What I have ended up doing is the following. To me this seems like a bit of a hack job. Is there any better way to use login with a csrf?
views
:
def login(request):
c={}
c.update(csrf(request))
if 'next' in request.GET:
c['next'] = request.GET.get('next')
return render_to_response('login.html', c)
def auth_view(request):
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = auth.authenticate(username=username, password=password)
if user is not None:
auth.login(request, user)
if request.POST.get('next') != '':
return HttpResponseRedirect(request.POST.get('next'))
else:
return HttpResponseRedirect('/accounts/loggedin')
else:
return HttpResponseRedirect('/accounts/invalid')
login.html
:
<input type="hidden" name="next" value="{{ next }}"/>
The query string is implicitly passed to any view, without you having to write any special code.
All you have to do is make sure that the next
key is passed from the actual login form (in your case, this is the form that is rendered in /accounts/login/
), to the /accounts/auth
view.
To do that, you need to make sure you have the request template context processor (django.core.context_processors.request
) enabled in your settings. To do this, first you need to import the default value for TEMPLATE_CONTEXT_PROCESSORS
, then add the request processor to it in your settings.py
, like this:
from django.conf import global_settings
TEMPLATE_CONTEXT_PROCESSORS = global_settings.TEMPLATE_CONTEXT_PROCESSORS + (
"django.core.context_processors.request",
)
Then in the form:
<form method="POST" action="/accounts/auth">
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.GET.next }}" />
{{ login_form }}
<input type="submit">
</form>
Now, in your /accounts/auth
view:
def foo(request):
if request.method == 'POST':
# .. authenticate your user
# redirect to the value of next if it is entered, otherwise
# to /accounts/profile/
return redirect(request.POST.get('next','/accounts/profile/'))
Faced similar situation sometime back. To solve this I wrote my own decorator -
def validate_request_for_login(f):
def wrap(request):
if not request.user.is_authenticated():
return redirect("/login?next=" + request.path)
return f(request)
return wrap
Above decorator checks for user authentication. If user is not authenticated then redirect the user to login page by passing the url
from request object.
What you are looking for is a login decorator.
In your views.py
from django.contrib.auth.decorators import login_required
@login_required(login_url="/accounts/login/")
def profile( request ):
"""your view code here"""
return HttpResponse("boo ya", "text/html")
Then in your urls.py add the authentication url
(r'^accounts/login/$', 'django.contrib.auth.views.login'),
Finally: Make sure you have django.contrib.auth in your installed apps, and AuthenticationMiddleware installed.
settings.py
INSTALLED_APPS = (
-- snip --,
'django.contrib.auth',
)
MIDDLEWARE_CLASSES = (
-- snip --,
'django.contrib.auth.middleware.AuthenticationMiddleware',
)
your templates/registration/login.html
<form method="POST" action="/accounts/login/">
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}" />
{{ login_form }}
<input type="submit">
</form>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With