Last active
August 29, 2015 14:05
-
-
Save mikofski/249279b7380cded60a82 to your computer and use it in GitHub Desktop.
Django view utilities to add GET parameters to context and to use a Bootstrap navbar login template
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from functools import wraps | |
from django.contrib.auth.views import login as auth_login | |
from django.contrib.auth.decorators import login_required | |
from django.http import HttpResponse, HttpResponseRedirect, QueryDict | |
from django.core.urlresolvers import reverse, resolve | |
from django.template.response import TemplateResponse | |
def add_GET_to_context(*keys): | |
""" | |
Check view's URL GET query string for keys and add values to context data | |
if view response is ``TemplateResponse``. | |
""" | |
def outer_wrapper(view): | |
@wraps(view) | |
def inner_wrapper(request, *args, **kwargs): | |
response = view(request, *args, **kwargs) | |
try: | |
for k in keys: | |
response.context_data[k] = request.GET.get(k) | |
finally: | |
return response | |
return inner_wrapper | |
return outer_wrapper | |
# For example to check any url for a GET query string ?error=whatever | |
# use @add_GET_to_context('error') and make sure the view returns a | |
# TemplateResponse, then it will add the error's value to the context | |
# to use in the template. | |
# | |
# Example template.html | |
# {% if error == 'login' %} | |
# <do> stuff </do> | |
# {% endif %} | |
@add_GET_to_context('error') | |
def home(request): | |
""" | |
Home page | |
""" | |
context = {'path': request.path, 'user': request.user} | |
return TemplateResponse(request, 'index.html', context) | |
# Use Case: Bootstrap navbar login | |
# Django by default opens registration/login.html when it receives a GET | |
# to login. To redirect all login attempts to a Bootstrap navbar the following | |
# function wraps the Django login view in a custom view that edits the response. | |
# If there is an error it adds it a GET query string. If login was called by a | |
# GET url pattern then check if it is in the LOGIN_REDIRECTS dictionary, and | |
# then redirect to a different url with the args listed in the dictionary. This | |
# is useful if using @login_required(login_url='/somwhere/') which will add | |
# `next` as a GET query string. But if the original url pattern was called with | |
# a POST method, this url will fail, so redirect it to a url that won't. | |
# if auth succeeds then login was called by a POST method, so let it return the | |
# response without doing anything. | |
LOGIN_REDIRECTS = {'POST_view_url_1': {'redirect_url': 'GET_view_url_1', | |
'kwargs': ['key1', 'key2']}, | |
'POST_view_url_1': {'redirect_url': 'GET_view_url_1', | |
'kwargs': ['key1', 'key2']}} | |
def login(request): | |
""" | |
Replaces ``django.contrib.auth.views.login`` to redirect back to same url | |
that called | |
""" | |
response = auth_login(request) | |
query_str = QueryDict('', mutable=True) # empty mutable QueryDict | |
# ducktype response for TemplateResponse to catch login called as GET | |
# or if auth failed, otherwise it's HttpResponseRedirect when auth succeeds | |
try: | |
form = response.context_data['form'] | |
url = response.context_data['next'] | |
match = resolve(url) | |
if form.errors: | |
query_str['error'] = 'login' | |
response = HttpResponseRedirect(url + '?' + query_str.urlencode()) | |
elif match.url_name in LOGIN_REDIRECTS: | |
kwargs = {k: match.kwargs[k] for k in LOGIN_REDIRECTS['kwargs']} | |
response = HttpResponseRedirect(reverse(LOGIN_REDIRECTS['redirect_url'], | |
kwargs=kwargs)) | |
finally: | |
return response |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment