"""
URL Middleware
Stefano J. Attardi (attardi.org)
$Id$
$URL$
Cleans up urls by adding/removing trailing slashes, adding/removing
the www. prefix, and allowing the language to be set from the url.
If APPEND_SLASH is set to False, trailing slashes are removed from the
urls, except for urls which have an explicit trailing slash in
urls.py, in which case a trailing slash is added.
If REMOVE_WWW is set to True, the www. prefix is removed.
Finally, ?lang=xx can be appended to any url to override the default
language setting. This override is remembered for the following
requests. For example, /article?lang=it would show the article in
Italian regardless of brower settings or cookies, and any following
request to the site would be shown in Italian by default.
Changelog
1.3.2
Fixed an indentation issue. Added a check for those backends
which set an empty path (e.g. runfcgi).
1.3.1
Added support for running in a test
suite (doesn't assume that HTTP_HOST is set)
1.3
Only use sessions for the language preference if the session
cookie has already been set (regardless of whether session middleware
is active). Otherwise use the plain django_language cookie.
Only import the FlatPages module if it is active.
1.2
Added support for FlatPages.
Switched to Django's resolve function (with workaround for when it
returns None).
1.1
Various bugfixes.
1.0
First release.
"""
__version__ = "1.3.2"
__license__ = "Python"
__copyright__ = "Copyright (C) 2006-2007, Stefano J. Attardi"
__author__ = "Stefano J. Attardi "
__contributors__ = ["Antonio Cavedoni "]
from django.conf import settings
from django.http import HttpResponseRedirect, Http404
from django.core.urlresolvers import resolve
from django.utils.translation import check_for_language
import os
class UrlMiddleware:
def process_request(self, request):
# Change the language setting for the current page
if "lang" in request.GET and check_for_language(request.GET["lang"]):
if hasattr(request, "session"):
request.session["django_language"] = request.GET["lang"]
else:
request.COOKIES["django_language"] = request.GET["lang"]
# work-around for runfcgi
if request.path == "": request.path = "/"
request.path = '/'+request.path.lstrip('/')
# Check for a redirect based on settings.APPEND_SLASH and settings.PREPEND_WWW
old_url = [request.META.get("HTTP_HOST", "localhost"), request.path]
new_url = old_url[:]
# if REMOVE_WWW is True, remove the www. from the urls if necessary
if hasattr(settings, "REMOVE_WWW") and settings.REMOVE_WWW and old_url[0].startswith("www."):
new_url[0] = old_url[0][4:]
if hasattr(settings, "APPEND_SLASH") and not settings.APPEND_SLASH:
# if the url is not found, try with(out) the trailing slash
if old_url[1] != "/" and not self._urlExists(old_url[1]):
if old_url[1][-1] == "/":
other = old_url[1][:-1]
else:
other = old_url[1] + "/"
if self._urlExists(other):
new_url[1] = other
if new_url != old_url:
# Redirect
newurl = "%s://%s%s" % (os.environ.get("HTTPS") == "on" and "https" or "http", new_url[0], new_url[1])
if request.GET:
newurl += "?" + request.GET.urlencode()
return HttpResponseRedirect(newurl)
return None
def process_response(self, request, response):
# Change the language setting for future pages
if "lang" in request.GET and check_for_language(request.GET["lang"]):
if "sessionid" in request.COOKIES:
request.session["django_language"] = request.GET["lang"]
else:
response.set_cookie("django_language", request.GET["lang"])
return response
def _urlExists(self, path):
try:
if resolve(path) is None: raise Http404 # None?!? You mean 404...
return True
except Http404:
# check for flatpages
if "django.contrib.flatpages.middleware.FlatpageFallbackMiddleware" in settings.MIDDLEWARE_CLASSES:
from django.contrib.flatpages.models import FlatPage
return FlatPage.objects.filter(url=path, sites__id=settings.SITE_ID).count() == 1