BACKWARDS-INCOMPATIBLE CHANGE -- Moved flatpages and redirects to standalone apps in django.contrib that are NOT installed by default. See http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges for full migration information.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@1166 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty 2005-11-11 04:45:05 +00:00
parent a11a1d5e16
commit 1b035c35d9
21 changed files with 310 additions and 123 deletions

View File

@ -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')

View File

View File

@ -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

View File

@ -0,0 +1 @@
__all__ = ['flatpages']

View File

@ -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

View File

@ -1,5 +1,5 @@
from django.conf.urls.defaults import *
urlpatterns = patterns('django.views',
(r'^(?P<url>.*)$', 'core.flatfiles.flat_file'),
(r'^(?P<url>.*)$', 'django.contrib.flatpages.views.flatpage'),
)

View File

@ -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))

View File

View File

@ -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

View File

@ -0,0 +1 @@
__all__ = ['redirects']

View File

@ -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)

View File

@ -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.

View File

@ -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'))

View File

@ -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)
@ -16,8 +16,8 @@ def shortcut(request, content_type_id, object_id):
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://'):
@ -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()))

114
docs/flatpages.txt Normal file
View File

@ -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::
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>{{ flatpage.title }}</title>
</head>
<body>
{{ flatpage.content }}
</body>
</html>

View File

@ -69,10 +69,7 @@ following names:
* ``sites``
* ``packages``
* ``content_types``
* ``redirects``
* ``flatfiles``
* ``core_sessions``
* ``flatfiles_sites``
* ``auth_permissions``
* ``auth_groups``
* ``auth_users``

View File

@ -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
-------------------------------------

View File

@ -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, {

72
docs/redirects.txt Normal file
View File

@ -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/

View File

@ -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/

View File

@ -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