diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index afb2953742..03609ffee6 100644 --- a/django/conf/global_settings.py +++ b/django/conf/global_settings.py @@ -135,9 +135,6 @@ ALLOWED_INCLUDE_ROOTS = () # is an admin. ADMIN_FOR = () -# Whether to check the flat-pages table as a last resort for all 404 errors. -USE_FLAT_PAGES = True - # 404s that may be ignored. IGNORABLE_404_STARTS = ('/cgi-bin/', '/_vti_bin', '/_vti_inf') IGNORABLE_404_ENDS = ('mail.pl', 'mailform.pl', 'mail.cgi', 'mailform.cgi', 'favicon.ico', '.php') diff --git a/django/contrib/flatpages/__init__.py b/django/contrib/flatpages/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/django/contrib/flatpages/middleware.py b/django/contrib/flatpages/middleware.py new file mode 100644 index 0000000000..9c4e0bb44e --- /dev/null +++ b/django/contrib/flatpages/middleware.py @@ -0,0 +1,15 @@ +from django.contrib.flatpages.views import flatpage +from django.conf.settings import DEBUG + +class FlatpageFallbackMiddleware: + def process_response(self, request, response): + if response.status_code != 404: + return response # No need to check for a flatpage for non-404 responses. + try: + return flatpage(request, request.path) + # Return the original response if any errors happened. Because this + # is a middleware, we can't assume the errors will be caught elsewhere. + except: + if DEBUG: + raise + return response diff --git a/django/contrib/flatpages/models/__init__.py b/django/contrib/flatpages/models/__init__.py new file mode 100644 index 0000000000..bb46349b5a --- /dev/null +++ b/django/contrib/flatpages/models/__init__.py @@ -0,0 +1 @@ +__all__ = ['flatpages'] diff --git a/django/contrib/flatpages/models/flatpages.py b/django/contrib/flatpages/models/flatpages.py new file mode 100644 index 0000000000..cfb2741d34 --- /dev/null +++ b/django/contrib/flatpages/models/flatpages.py @@ -0,0 +1,33 @@ +from django.core import meta, validators +from django.models.core import Site +from django.utils.translation import gettext_lazy as _ + +class FlatPage(meta.Model): + url = meta.CharField(_('URL'), maxlength=100, validator_list=[validators.isAlphaNumericURL], + help_text=_("Example: '/about/contact/'. Make sure to have leading and trailing slashes.")) + title = meta.CharField(_('title'), maxlength=200) + content = meta.TextField(_('content')) + enable_comments = meta.BooleanField(_('enable comments')) + template_name = meta.CharField(_('template name'), maxlength=70, blank=True, + help_text=_("Example: 'flatpages/contact_page'. If this isn't provided, the system will use 'flatpages/default'.")) + registration_required = meta.BooleanField(_('registration required'), help_text=_("If this is checked, only logged-in users will be able to view the page.")) + sites = meta.ManyToManyField(Site) + class META: + db_table = 'django_flatpages' + verbose_name = _('flat page') + verbose_name_plural = _('flat pages') + ordering = ('url',) + admin = meta.Admin( + fields = ( + (None, {'fields': ('url', 'title', 'content', 'sites')}), + ('Advanced options', {'classes': 'collapse', 'fields': ('enable_comments', 'registration_required', 'template_name')}), + ), + list_filter = ('sites',), + search_fields = ('url', 'title'), + ) + + def __repr__(self): + return "%s -- %s" % (self.url, self.title) + + def get_absolute_url(self): + return self.url diff --git a/django/conf/urls/flatfiles.py b/django/contrib/flatpages/urls.py similarity index 55% rename from django/conf/urls/flatfiles.py rename to django/contrib/flatpages/urls.py index 1d29463319..c78022c4e4 100644 --- a/django/conf/urls/flatfiles.py +++ b/django/contrib/flatpages/urls.py @@ -1,5 +1,5 @@ from django.conf.urls.defaults import * urlpatterns = patterns('django.views', - (r'^(?P.*)$', 'core.flatfiles.flat_file'), + (r'^(?P.*)$', 'django.contrib.flatpages.views.flatpage'), ) diff --git a/django/views/core/flatfiles.py b/django/contrib/flatpages/views.py similarity index 66% rename from django/views/core/flatfiles.py rename to django/contrib/flatpages/views.py index ded33d4cdd..48cd4526ab 100644 --- a/django/views/core/flatfiles.py +++ b/django/contrib/flatpages/views.py @@ -1,28 +1,28 @@ from django.core import template_loader from django.core.extensions import get_object_or_404, DjangoContext -from django.models.core import flatfiles +from django.models.flatpages import flatpages from django.utils.httpwrappers import HttpResponse from django.conf.settings import SITE_ID -DEFAULT_TEMPLATE = 'flatfiles/default' +DEFAULT_TEMPLATE = 'flatpages/default' -def flat_file(request, url): +def flatpage(request, url): """ - Flat file view + Flat page view. - Models: `core.flatfiles` + Models: `flatpages.flatpages` Templates: Uses the template defined by the ``template_name`` field, - or `flatfiles/default` if template_name is not defined. + or `flatpages/default` if template_name is not defined. Context: - flatfile - `flatfiles.flatfiles` object + flatpage + `flatpages.flatpages` object """ if not url.startswith('/'): url = "/" + url - f = get_object_or_404(flatfiles, url__exact=url, sites__id__exact=SITE_ID) + f = get_object_or_404(flatpages, url__exact=url, sites__id__exact=SITE_ID) # If registration is required for accessing this page, and the user isn't # logged in, redirect to the login page. - if request.user.is_anonymous() and f.registration_required: + if f.registration_required and request.user.is_anonymous(): from django.views.auth.login import redirect_to_login return redirect_to_login(request.path) if f.template_name: @@ -30,6 +30,6 @@ def flat_file(request, url): else: t = template_loader.get_template(DEFAULT_TEMPLATE) c = DjangoContext(request, { - 'flatfile': f, + 'flatpage': f, }) return HttpResponse(t.render(c)) diff --git a/django/contrib/redirects/__init__.py b/django/contrib/redirects/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/django/contrib/redirects/middleware.py b/django/contrib/redirects/middleware.py new file mode 100644 index 0000000000..c8f09ada8e --- /dev/null +++ b/django/contrib/redirects/middleware.py @@ -0,0 +1,27 @@ +from django.models.redirects import redirects +from django.utils import httpwrappers +from django.conf.settings import APPEND_SLASH, SITE_ID + +class RedirectFallbackMiddleware: + def process_response(self, request, response): + if response.status_code != 404: + return response # No need to check for a redirect for non-404 responses. + path = request.get_full_path() + try: + r = redirects.get_object(site__id__exact=SITE_ID, old_path__exact=path) + except redirects.RedirectDoesNotExist: + r = None + if r is None and APPEND_SLASH: + # Try removing the trailing slash. + try: + r = redirects.get_object(site__id__exact=SITE_ID, + old_path__exact=path[:path.rfind('/')]+path[path.rfind('/')+1:]) + except redirects.RedirectDoesNotExist: + pass + if r is not None: + if r == '': + return httpwrappers.HttpResponseGone() + return httpwrappers.HttpResponseRedirect(r.new_path) + + # No redirect was found. Return the response. + return response diff --git a/django/contrib/redirects/models/__init__.py b/django/contrib/redirects/models/__init__.py new file mode 100644 index 0000000000..05063b2146 --- /dev/null +++ b/django/contrib/redirects/models/__init__.py @@ -0,0 +1 @@ +__all__ = ['redirects'] diff --git a/django/contrib/redirects/models/redirects.py b/django/contrib/redirects/models/redirects.py new file mode 100644 index 0000000000..06dcdb38ac --- /dev/null +++ b/django/contrib/redirects/models/redirects.py @@ -0,0 +1,23 @@ +from django.core import meta +from django.models.core import Site +from django.utils.translation import gettext_lazy as _ + +class Redirect(meta.Model): + site = meta.ForeignKey(Site, radio_admin=meta.VERTICAL) + old_path = meta.CharField(_('redirect from'), maxlength=200, db_index=True, + help_text=_("This should be an absolute path, excluding the domain name. Example: '/events/search/'.")) + new_path = meta.CharField(_('redirect to'), maxlength=200, blank=True, + help_text=_("This can be either an absolute path (as above) or a full URL starting with 'http://'.")) + class META: + verbose_name = _('redirect') + verbose_name_plural = _('redirects') + db_table = 'django_redirects' + unique_together=(('site', 'old_path'),) + ordering = ('old_path',) + admin = meta.Admin( + list_filter = ('site',), + search_fields = ('old_path', 'new_path'), + ) + + def __repr__(self): + return "%s ---> %s" % (self.old_path, self.new_path) diff --git a/django/middleware/common.py b/django/middleware/common.py index fb37f653c1..1e437170e3 100644 --- a/django/middleware/common.py +++ b/django/middleware/common.py @@ -1,8 +1,6 @@ from django.conf import settings -from django.core import exceptions from django.utils import httpwrappers from django.core.mail import mail_managers -from django.views.core.flatfiles import flat_file import md5, os class CommonMiddleware: @@ -17,9 +15,6 @@ class CommonMiddleware: - ETags: If the USE_ETAGS setting is set, ETags will be calculated from the entire page content and Not Modified responses will be returned appropriately. - - - Flat files: For 404 responses, a flat file matching the given path - will be looked up and used if found. """ def process_request(self, request): @@ -55,12 +50,6 @@ class CommonMiddleware: def process_response(self, request, response): "Check for a flat page (for 404s) and calculate the Etag, if needed." if response.status_code == 404: - if settings.USE_FLAT_PAGES: - try: - return flat_file(request, request.path) - except exceptions.Http404: - pass - if settings.SEND_BROKEN_LINK_EMAILS: # If the referrer was from an internal link or a non-search-engine site, # send a note to the managers. diff --git a/django/models/core.py b/django/models/core.py index 1c52affdfd..17519b53d8 100644 --- a/django/models/core.py +++ b/django/models/core.py @@ -1,6 +1,6 @@ import base64, md5, random, sys import cPickle as pickle -from django.core import meta, validators +from django.core import meta from django.utils.translation import gettext_lazy as _ class Site(meta.Model): @@ -63,56 +63,6 @@ class ContentType(meta.Model): """ return self.get_model_module().get_object(**kwargs) -class Redirect(meta.Model): - site = meta.ForeignKey(Site, radio_admin=meta.VERTICAL) - old_path = meta.CharField(_('redirect from'), maxlength=200, db_index=True, - help_text=_("This should be an absolute path, excluding the domain name. Example: '/events/search/'.")) - new_path = meta.CharField(_('redirect to'), maxlength=200, blank=True, - help_text=_("This can be either an absolute path (as above) or a full URL starting with 'http://'.")) - class META: - verbose_name = _('redirect') - verbose_name_plural = _('redirects') - db_table = 'redirects' - unique_together=(('site', 'old_path'),) - ordering = ('old_path',) - admin = meta.Admin( - list_filter = ('site',), - search_fields = ('old_path', 'new_path'), - ) - - def __repr__(self): - return "%s ---> %s" % (self.old_path, self.new_path) - -class FlatFile(meta.Model): - url = meta.CharField(_('URL'), maxlength=100, validator_list=[validators.isAlphaNumericURL], - help_text=_("Example: '/about/contact/'. Make sure to have leading and trailing slashes.")) - title = meta.CharField(_('title'), maxlength=200) - content = meta.TextField(_('content')) - enable_comments = meta.BooleanField(_('enable comments')) - template_name = meta.CharField(_('template name'), maxlength=70, blank=True, - help_text=_("Example: 'flatfiles/contact_page'. If this isn't provided, the system will use 'flatfiles/default'.")) - registration_required = meta.BooleanField(_('registration required'), help_text=_("If this is checked, only logged-in users will be able to view the page.")) - sites = meta.ManyToManyField(Site) - class META: - db_table = 'flatfiles' - verbose_name = _('flat page') - verbose_name_plural = _('flat pages') - ordering = ('url',) - admin = meta.Admin( - fields = ( - (None, {'fields': ('url', 'title', 'content', 'sites')}), - ('Advanced options', {'classes': 'collapse', 'fields': ('enable_comments', 'registration_required', 'template_name')}), - ), - list_filter = ('sites',), - search_fields = ('url', 'title'), - ) - - def __repr__(self): - return "%s -- %s" % (self.url, self.title) - - def get_absolute_url(self): - return self.url - class Session(meta.Model): session_key = meta.CharField(_('session key'), maxlength=40, primary_key=True) session_data = meta.TextField(_('session data')) diff --git a/django/views/defaults.py b/django/views/defaults.py index 45e5636c5a..062f1a8cf5 100644 --- a/django/views/defaults.py +++ b/django/views/defaults.py @@ -4,7 +4,7 @@ from django.models.core import sites, contenttypes from django.utils import httpwrappers def shortcut(request, content_type_id, object_id): - """Redirect to an object's page based on a content-type ID and an object ID""" + "Redirect to an object's page based on a content-type ID and an object ID." # Look up the object, making sure it's got a get_absolute_url() function. try: content_type = contenttypes.get_object(pk=content_type_id) @@ -15,23 +15,23 @@ def shortcut(request, content_type_id, object_id): absurl = obj.get_absolute_url() except AttributeError: raise Http404, "%s objects don't have get_absolute_url() methods" % content_type.name - - # Try to figure out the object's domain so we can do a cross-site redirect - # if necessary + + # Try to figure out the object's domain, so we can do a cross-site redirect + # if necessary. # If the object actually defines a domain, we're done. if absurl.startswith('http://'): return httpwrappers.HttpResponseRedirect(absurl) object_domain = None - + # Next, look for an many-to-many relationship to sites if hasattr(obj, 'get_site_list'): site_list = obj.get_site_list() if site_list: object_domain = site_list[0].domain - - # Next, look for a many-to-one relationship to sites + + # Next, look for a many-to-one relationship to sites elif hasattr(obj, 'get_site'): try: object_domain = obj.get_site().domain @@ -55,34 +55,15 @@ def page_not_found(request): Templates: `404` Context: None """ - from django.models.core import redirects - from django.conf.settings import APPEND_SLASH, SITE_ID - path = request.get_full_path() - try: - r = redirects.get_object(site__id__exact=SITE_ID, old_path__exact=path) - except redirects.RedirectDoesNotExist: - r = None - if r is None and APPEND_SLASH: - # Try removing the trailing slash. - try: - r = redirects.get_object(site__id__exact=SITE_ID, old_path__exact=path[:path.rfind('/')]+path[path.rfind('/')+1:]) - except redirects.RedirectDoesNotExist: - pass - if r is not None: - if r == '': - return httpwrappers.HttpResponseGone() - return httpwrappers.HttpResponseRedirect(r.new_path) t = loader.get_template('404') - c = Context() - return httpwrappers.HttpResponseNotFound(t.render(c)) + return httpwrappers.HttpResponseNotFound(t.render(Context())) def server_error(request): """ - 500 Error handler + 500 error handler. Templates: `500` Context: None """ t = loader.get_template('500') - c = Context() - return httpwrappers.HttpResponseServerError(t.render(c)) + return httpwrappers.HttpResponseServerError(t.render(Context())) diff --git a/docs/flatpages.txt b/docs/flatpages.txt new file mode 100644 index 0000000000..5c0520dae0 --- /dev/null +++ b/docs/flatpages.txt @@ -0,0 +1,114 @@ +================= +The flatpages app +================= + +Django comes with an optional "flatpages" application. It lets you store simple +"flat" HTML content in a database and handles the management for you. + +A flatpage is a simple object with a URL, title and content. Use it for +one-off, special-case pages, such as "About" or "Privacy Policy" pages, that +you want to store in a database but for which you don't want to develop a +custom Django application. + +A flatpage can use a custom template or a default, systemwide flatpage +template. It can be associated with one, or multiple, sites. + +Here are some examples of flatpages on Django-powered sites: + + * http://www.chicagocrime.org/about/ + * http://www.lawrence.com/about/contact/ + +Installation +============ + +To install the flatpages app, follow these two steps: + + 1. Add ``"django.contrib.flatpages"`` to your INSTALLED_APPS_ setting. + 2. Add ``"django.contrib.flatpages.middleware.FlatpageFallbackMiddleware"`` + to your MIDDLEWARE_CLASSES_ setting. + 3. Run the command ``django-admin.py install flatpages``. + +.. _INSTALLED_APPS: http://www.djangoproject.com/documentation/settings/#installed-apps +.. _MIDDLEWARE_CLASSES: http://www.djangoproject.com/documentation/settings/#middleware-classes + +How it works +============ + +``django-admin.py install flatpages`` creates two tables in your database: +``django_flatpages`` and ``django_flatpages_sites``. ``django_flatpages`` is a +simple lookup table that essentially maps a URL to a title and bunch of text +content. ``django_flatpages_sites`` associates a flatpage with a site. + +The ``FlatpageFallbackMiddleware`` does all of the work. Each time any Django +application raises a 404 error, this middleware checks the flatpages database +for the requested URL as a last resort. Specifically, it checks for a flatpage +with the given URL with a site ID that corresponds to the SITE_ID_ setting. + +If it finds a match, it follows this algorithm: + + * If the flatpage has a custom template, it loads that template. Otherwise, + it loads the template ``flatpages/default``. + * It passes that template a single context variable, ``flatpage``, which is + the flatpage object. It uses DjangoContext_ in rendering the template. + +If it doesn't find a match, the request continues to be processed as usual. + +The middleware only gets activated for 404s -- not for 500s or responses of any +other status code. + +Note that the order of ``MIDDLEWARE_CLASSES`` matters. Generally, you can put +``FlatpageFallbackMiddleware`` at the end of the list, because it's a last +resort. + +For more on middleware, read the `middleware docs`_. + +.. _SITE_ID: http://www.djangoproject.com/documentation/settings/#site-id +.. _DjangoContext: http://www.djangoproject.com/documentation/templates_python/#subclassing-context-djangocontext +.. _middleware docs: http://www.djangoproject.com/documentation/middleware/ + +How to add, change and delete flatpages +======================================= + +Via the admin interface +----------------------- + +If you've activated the automatic Django admin interface, you should see a +"Flatpages" section on the admin index page. Edit flatpages as you edit any +other object in the system. + +Via the Python API +------------------ + +Flatpages are represented by a standard `Django model`_, which lives in +`django/contrib/flatpages/models/flatpages.py`_. You can access flatpage +objects via the `Django database API`_. + +.. _Django model: http://www.djangoproject.com/documentation/model_api/ +.. _django/contrib/flatpages/models/flatpages.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/flatpages/models/flatpages.py +.. _Django database API: http://www.djangoproject.com/documentation/db_api/ + +Flatpage templates +================== + +By default, flatpages are rendered via the template ``flatpages/default``, but +you can override that for a particular flatpage. + +Creating the ``flatpages/default`` template is your responsibility; in your +template directory, just create a ``flatpages`` directory containing a file +``default.html``. + +Flatpage templates are passed a single context variable, ``flatpage``, which is +the flatpage object. + +Here's a sample ``flatpages/default`` template:: + + + + + {{ flatpage.title }} + + + {{ flatpage.content }} + + diff --git a/docs/legacy_databases.txt b/docs/legacy_databases.txt index beddc74134..f1b8f85970 100644 --- a/docs/legacy_databases.txt +++ b/docs/legacy_databases.txt @@ -69,10 +69,7 @@ following names: * ``sites`` * ``packages`` * ``content_types`` - * ``redirects`` - * ``flatfiles`` * ``core_sessions`` - * ``flatfiles_sites`` * ``auth_permissions`` * ``auth_groups`` * ``auth_users`` diff --git a/docs/middleware.txt b/docs/middleware.txt index a7a5474d84..5a01f728d4 100644 --- a/docs/middleware.txt +++ b/docs/middleware.txt @@ -72,10 +72,6 @@ Adds a few conveniences for perfectionists: MD5-hashing the page content, and it'll take care of sending ``Not Modified`` responses, if appropriate. -* Handles flat pages. Every time Django encounters a 404 -- either within - a view or as a result of no URLconfs matching -- it will check the - database of flat pages based on the current URL. - django.middleware.doc.XViewMiddleware ------------------------------------- diff --git a/docs/model-api.txt b/docs/model-api.txt index a9190c78fe..51086e426e 100644 --- a/docs/model-api.txt +++ b/docs/model-api.txt @@ -831,7 +831,7 @@ object, which takes the following parameters. All are optional. "click to expand" link. Fieldsets with the ``wide`` style will be given extra horizontal space. - For example (taken from the ``core.flatfiles`` model):: + For example (taken from the ``django.contrib.flatpages`` model):: fields = ( (None, { diff --git a/docs/redirects.txt b/docs/redirects.txt new file mode 100644 index 0000000000..08fae8a8dc --- /dev/null +++ b/docs/redirects.txt @@ -0,0 +1,72 @@ +================= +The redirects app +================= + +Django comes with an optional redirects application. It lets you store simple +redirects in a database and handles the redirecting for you. + +Installation +============ + +To install the redirects app, follow these two steps: + + 1. Add ``"django.contrib.redirects"`` to your INSTALLED_APPS_ setting. + 2. Add ``"django.contrib.redirects.middleware.RedirectFallbackMiddleware"`` + to your MIDDLEWARE_CLASSES_ setting. + 3. Run the command ``django-admin.py install redirects``. + +.. _INSTALLED_APPS: http://www.djangoproject.com/documentation/settings/#installed-apps +.. _MIDDLEWARE_CLASSES: http://www.djangoproject.com/documentation/settings/#middleware-classes + +How it works +============ + +``django-admin.py install redirects`` creates a ``django_redirects`` table in +your database. This is a simple lookup table with ``site_id``, ``old_path`` and +``new_path`` fields. + +The ``RedirectFallbackMiddleware`` does all of the work. Each time any Django +application raises a 404 error, this middleware checks the redirects database +for the requested URL as a last resort. Specifically, it checks for a redirect +with the given ``old_path`` with a site ID that corresponds to the SITE_ID_ +setting. + + * If it finds a match, and ``new_path`` is not empty, it redirects to + ``new_path``. + * If it finds a match, and ``new_path`` is empty, it sends a 410 ("Gone") + HTTP header and empty (content-less) response. + * If it doesn't find a match, the request continues to be processed as + usual. + +The middleware only gets activated for 404s -- not for 500s or responses of any +other status code. + +Note that the order of ``MIDDLEWARE_CLASSES`` matters. Generally, you can put +``RedirectFallbackMiddleware`` at the end of the list, because it's a last +resort. + +For more on middleware, read the `middleware docs`_. + +.. _SITE_ID: http://www.djangoproject.com/documentation/settings/#site-id +.. _middleware docs: http://www.djangoproject.com/documentation/middleware/ + +How to add, change and delete redirects +======================================= + +Via the admin interface +----------------------- + +If you've activated the automatic Django admin interface, you should see a +"Redirects" section on the admin index page. Edit redirects as you edit any +other object in the system. + +Via the Python API +------------------ + +Redirects are represented by a standard `Django model`_, which lives in +`django/contrib/redirects/models/redirects.py`_. You can access redirect +objects via the `Django database API`_. + +.. _Django model: http://www.djangoproject.com/documentation/model_api/ +.. _django/contrib/redirects/models/redirects.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/redirects/models/redirects.py +.. _Django database API: http://www.djangoproject.com/documentation/db_api/ diff --git a/docs/settings.txt b/docs/settings.txt index c4eeb2e636..b5287b26a2 100644 --- a/docs/settings.txt +++ b/docs/settings.txt @@ -562,14 +562,6 @@ A boolean that specifies whether to output the "Etag" header. This saves bandwidth but slows down performance. This is only used if ``CommonMiddleware`` is installed (see the `middleware docs`_). -USE_FLAT_PAGES --------------- - -Default: ``True`` - -Whether to check the flat-pages table as a last resort for all 404 errors. This -is only used if ``CommonMiddleware`` is installed (see the `middleware docs`_). - .. _cache docs: http://www.djangoproject.com/documentation/cache/ .. _middleware docs: http://www.djangoproject.com/documentation/middleware/ .. _session docs: http://www.djangoproject.com/documentation/sessions/ diff --git a/docs/url_dispatch.txt b/docs/url_dispatch.txt index 3a3feea8be..363d31174a 100644 --- a/docs/url_dispatch.txt +++ b/docs/url_dispatch.txt @@ -56,7 +56,6 @@ module that will be used for the entire site. Here's the URLconf for the (r'^documentation/', include('django_website.apps.docs.urls.docs')), (r'^comments/', include('django.contrib.comments.urls.comments')), (r'^rss/', include('django.conf.urls.rss')), - (r'', include('django.conf.urls.flatfiles')), ) Note that an included URLconf receives any captured parameters from parent