Fixed #6932 -- Added a template tag that gives a list of available flatpages for a given user. Thanks to Dmitri Fedortchenko for the suggestion, and to Mnewman, faldridge and Simon Meers for their work on the patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@13654 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
c00f35ae0d
commit
e1e2726957
|
@ -17,6 +17,22 @@
|
|||
{
|
||||
"pk": 2,
|
||||
"model": "flatpages.flatpage",
|
||||
"fields": {
|
||||
"registration_required": false,
|
||||
"title": "A Nested Flatpage",
|
||||
"url": "/location/flatpage/",
|
||||
"template_name": "",
|
||||
"sites": [
|
||||
1
|
||||
],
|
||||
"content": "Isn't it flat and deep!",
|
||||
"enable_comments": false
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"pk": 101,
|
||||
"model": "flatpages.flatpage",
|
||||
"fields": {
|
||||
"registration_required": true,
|
||||
"title": "Sekrit Flatpage",
|
||||
|
@ -28,5 +44,20 @@
|
|||
"content": "Isn't it sekrit!",
|
||||
"enable_comments": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 102,
|
||||
"model": "flatpages.flatpage",
|
||||
"fields": {
|
||||
"registration_required": true,
|
||||
"title": "Sekrit Nested Flatpage",
|
||||
"url": "/location/sekrit/",
|
||||
"template_name": "",
|
||||
"sites": [
|
||||
1
|
||||
],
|
||||
"content": "Isn't it sekrit and deep!",
|
||||
"enable_comments": false
|
||||
}
|
||||
}
|
||||
]
|
|
@ -0,0 +1,99 @@
|
|||
from django import template
|
||||
from django.contrib.flatpages.models import FlatPage
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
class FlatpageNode(template.Node):
|
||||
def __init__(self, context_name, starts_with=None, user=None):
|
||||
self.context_name = context_name
|
||||
if starts_with:
|
||||
self.starts_with = template.Variable(starts_with)
|
||||
else:
|
||||
self.starts_with = None
|
||||
if user:
|
||||
self.user = template.Variable(user)
|
||||
else:
|
||||
self.user = None
|
||||
|
||||
def render(self, context):
|
||||
flatpages = FlatPage.objects.filter(sites__id=settings.SITE_ID)
|
||||
# If a prefix was specified, add a filter
|
||||
if self.starts_with:
|
||||
flatpages = flatpages.filter(
|
||||
url__startswith=self.starts_with.resolve(context))
|
||||
|
||||
# If the provided user is not authenticated, or no user
|
||||
# was provided, filter the list to only public flatpages.
|
||||
if self.user:
|
||||
user = self.user.resolve(context)
|
||||
if not user.is_authenticated():
|
||||
flatpages = flatpages.filter(registration_required=False)
|
||||
else:
|
||||
flatpages = flatpages.filter(registration_required=False)
|
||||
|
||||
context[self.context_name] = flatpages
|
||||
return ''
|
||||
|
||||
|
||||
def get_flatpages(parser, token):
|
||||
"""
|
||||
Retrieves all flatpage objects available for the current site and
|
||||
visible to the specific user (or visible to all users if no user is
|
||||
specified). Populates the template context with them in a variable
|
||||
whose name is defined by the ``as`` clause.
|
||||
|
||||
An optional ``for`` clause can be used to control the user whose
|
||||
permissions are to be used in determining which flatpages are visible.
|
||||
|
||||
An optional argument, ``starts_with``, can be applied to limit the
|
||||
returned flatpages to those beginning with a particular base URL.
|
||||
This argument can be passed as a variable or a string, as it resolves
|
||||
from the template context.
|
||||
|
||||
Syntax::
|
||||
|
||||
{% get_flatpages ['url_starts_with'] [for user] as context_name %}
|
||||
|
||||
Example usage::
|
||||
|
||||
{% get_flatpages as flatpages %}
|
||||
{% get_flatpages for someuser as flatpages %}
|
||||
{% get_flatpages '/about/' as about_pages %}
|
||||
{% get_flatpages prefix as about_pages %}
|
||||
{% get_flatpages '/about/' for someuser as about_pages %}
|
||||
"""
|
||||
bits = token.split_contents()
|
||||
syntax_message = _("%(tag_name)s expects a syntax of %(tag_name)s "
|
||||
"['url_starts_with'] [for user] as context_name" %
|
||||
dict(tag_name=bits[0]))
|
||||
# Must have at 3-6 bits in the tag
|
||||
if len(bits) >= 3 and len(bits) <= 6:
|
||||
|
||||
# If there's an even number of bits, there's no prefix
|
||||
if len(bits) % 2 == 0:
|
||||
prefix = bits[1]
|
||||
else:
|
||||
prefix = None
|
||||
|
||||
# The very last bit must be the context name
|
||||
if bits[-2] != 'as':
|
||||
raise template.TemplateSyntaxError(syntax_message)
|
||||
context_name = bits[-1]
|
||||
|
||||
# If there are 5 or 6 bits, there is a user defined
|
||||
if len(bits) >= 5:
|
||||
if bits[-4] != 'for':
|
||||
raise template.TemplateSyntaxError(syntax_message)
|
||||
user = bits[-3]
|
||||
else:
|
||||
user = None
|
||||
|
||||
return FlatpageNode(context_name, starts_with=prefix, user=user)
|
||||
else:
|
||||
raise template.TemplateSyntaxError(syntax_message)
|
||||
|
||||
register.tag('get_flatpages', get_flatpages)
|
|
@ -1,3 +1,4 @@
|
|||
from django.contrib.flatpages.tests.csrf import *
|
||||
from django.contrib.flatpages.tests.middleware import *
|
||||
from django.contrib.flatpages.tests.templatetags import *
|
||||
from django.contrib.flatpages.tests.views import *
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import os
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.test import TestCase, Client
|
||||
|
||||
class FlatpageCSRFTests(TestCase):
|
||||
|
@ -42,6 +43,11 @@ class FlatpageCSRFTests(TestCase):
|
|||
"A flatpage served through a view can require authentication"
|
||||
response = self.client.get('/flatpage_root/sekrit/')
|
||||
self.assertRedirects(response, '/accounts/login/?next=/flatpage_root/sekrit/')
|
||||
User.objects.create_user('testuser', 'test@example.com', 's3krit')
|
||||
self.client.login(username='testuser',password='s3krit')
|
||||
response = self.client.get('/flatpage_root/sekrit/')
|
||||
self.assertEquals(response.status_code, 200)
|
||||
self.assertContains(response, "<p>Isn't it sekrit!</p>")
|
||||
|
||||
def test_fallback_flatpage(self):
|
||||
"A flatpage can be served by the fallback middlware"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import os
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.test import TestCase
|
||||
|
||||
class FlatpageMiddlewareTests(TestCase):
|
||||
|
@ -38,6 +39,11 @@ class FlatpageMiddlewareTests(TestCase):
|
|||
"A flatpage served through a view can require authentication"
|
||||
response = self.client.get('/flatpage_root/sekrit/')
|
||||
self.assertRedirects(response, '/accounts/login/?next=/flatpage_root/sekrit/')
|
||||
User.objects.create_user('testuser', 'test@example.com', 's3krit')
|
||||
self.client.login(username='testuser',password='s3krit')
|
||||
response = self.client.get('/flatpage_root/sekrit/')
|
||||
self.assertEquals(response.status_code, 200)
|
||||
self.assertContains(response, "<p>Isn't it sekrit!</p>")
|
||||
|
||||
def test_fallback_flatpage(self):
|
||||
"A flatpage can be served by the fallback middlware"
|
||||
|
@ -54,3 +60,8 @@ class FlatpageMiddlewareTests(TestCase):
|
|||
"A flatpage served by the middleware can require authentication"
|
||||
response = self.client.get('/sekrit/')
|
||||
self.assertRedirects(response, '/accounts/login/?next=/sekrit/')
|
||||
User.objects.create_user('testuser', 'test@example.com', 's3krit')
|
||||
self.client.login(username='testuser',password='s3krit')
|
||||
response = self.client.get('/sekrit/')
|
||||
self.assertEquals(response.status_code, 200)
|
||||
self.assertContains(response, "<p>Isn't it sekrit!</p>")
|
||||
|
|
|
@ -1,2 +1,10 @@
|
|||
<h1>{{ flatpage.title }}</h1>
|
||||
<p>{{ flatpage.content }}</p>
|
||||
<!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>
|
||||
<p>{{ flatpage.content }}</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
import os
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import AnonymousUser, User
|
||||
from django.template import Template, Context, TemplateSyntaxError
|
||||
from django.test import TestCase
|
||||
|
||||
class FlatpageTemplateTagTests(TestCase):
|
||||
fixtures = ['sample_flatpages']
|
||||
urls = 'django.contrib.flatpages.tests.urls'
|
||||
|
||||
def setUp(self):
|
||||
self.old_MIDDLEWARE_CLASSES = settings.MIDDLEWARE_CLASSES
|
||||
flatpage_middleware_class = 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'
|
||||
if flatpage_middleware_class not in settings.MIDDLEWARE_CLASSES:
|
||||
settings.MIDDLEWARE_CLASSES += (flatpage_middleware_class,)
|
||||
self.old_TEMPLATE_DIRS = settings.TEMPLATE_DIRS
|
||||
settings.TEMPLATE_DIRS = (
|
||||
os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
'templates'
|
||||
),
|
||||
)
|
||||
self.me = User.objects.create_user('testuser', 'test@example.com', 's3krit')
|
||||
|
||||
def tearDown(self):
|
||||
settings.MIDDLEWARE_CLASSES = self.old_MIDDLEWARE_CLASSES
|
||||
settings.TEMPLATE_DIRS = self.old_TEMPLATE_DIRS
|
||||
|
||||
def test_get_flatpages_tag(self):
|
||||
"The flatpage template tag retrives unregistered prefixed flatpages by default"
|
||||
out = Template(
|
||||
"{% load flatpages %}"
|
||||
"{% get_flatpages as flatpages %}"
|
||||
"{% for page in flatpages %}"
|
||||
"{{ page.title }},"
|
||||
"{% endfor %}"
|
||||
).render(Context())
|
||||
self.assertEquals(out, "A Flatpage,A Nested Flatpage,")
|
||||
|
||||
def test_get_flatpages_tag_for_anon_user(self):
|
||||
"The flatpage template tag retrives unregistered flatpages for an anonymous user"
|
||||
out = Template(
|
||||
"{% load flatpages %}"
|
||||
"{% get_flatpages for anonuser as flatpages %}"
|
||||
"{% for page in flatpages %}"
|
||||
"{{ page.title }},"
|
||||
"{% endfor %}"
|
||||
).render(Context({
|
||||
'anonuser': AnonymousUser()
|
||||
}))
|
||||
self.assertEquals(out, "A Flatpage,A Nested Flatpage,")
|
||||
|
||||
def test_get_flatpages_tag_for_user(self):
|
||||
"The flatpage template tag retrives all flatpages for an authenticated user"
|
||||
out = Template(
|
||||
"{% load flatpages %}"
|
||||
"{% get_flatpages for me as flatpages %}"
|
||||
"{% for page in flatpages %}"
|
||||
"{{ page.title }},"
|
||||
"{% endfor %}"
|
||||
).render(Context({
|
||||
'me': self.me
|
||||
}))
|
||||
self.assertEquals(out, "A Flatpage,A Nested Flatpage,Sekrit Nested Flatpage,Sekrit Flatpage,")
|
||||
|
||||
def test_get_flatpages_with_prefix(self):
|
||||
"The flatpage template tag retrives unregistered prefixed flatpages by default"
|
||||
out = Template(
|
||||
"{% load flatpages %}"
|
||||
"{% get_flatpages '/location/' as location_flatpages %}"
|
||||
"{% for page in location_flatpages %}"
|
||||
"{{ page.title }},"
|
||||
"{% endfor %}"
|
||||
).render(Context())
|
||||
self.assertEquals(out, "A Nested Flatpage,")
|
||||
|
||||
def test_get_flatpages_with_prefix_for_anon_user(self):
|
||||
"The flatpage template tag retrives unregistered prefixed flatpages for an anonymous user"
|
||||
out = Template(
|
||||
"{% load flatpages %}"
|
||||
"{% get_flatpages '/location/' for anonuser as location_flatpages %}"
|
||||
"{% for page in location_flatpages %}"
|
||||
"{{ page.title }},"
|
||||
"{% endfor %}"
|
||||
).render(Context({
|
||||
'anonuser': AnonymousUser()
|
||||
}))
|
||||
self.assertEquals(out, "A Nested Flatpage,")
|
||||
|
||||
def test_get_flatpages_with_prefix_for_user(self):
|
||||
"The flatpage template tag retrive prefixed flatpages for an authenticated user"
|
||||
out = Template(
|
||||
"{% load flatpages %}"
|
||||
"{% get_flatpages '/location/' for me as location_flatpages %}"
|
||||
"{% for page in location_flatpages %}"
|
||||
"{{ page.title }},"
|
||||
"{% endfor %}"
|
||||
).render(Context({
|
||||
'me': self.me
|
||||
}))
|
||||
self.assertEquals(out, "A Nested Flatpage,Sekrit Nested Flatpage,")
|
||||
|
||||
def test_get_flatpages_with_variable_prefix(self):
|
||||
"The prefix for the flatpage template tag can be a template variable"
|
||||
out = Template(
|
||||
"{% load flatpages %}"
|
||||
"{% get_flatpages location_prefix as location_flatpages %}"
|
||||
"{% for page in location_flatpages %}"
|
||||
"{{ page.title }},"
|
||||
"{% endfor %}"
|
||||
).render(Context({
|
||||
'location_prefix': '/location/'
|
||||
}))
|
||||
self.assertEquals(out, "A Nested Flatpage,")
|
||||
|
||||
def test_parsing_errors(self):
|
||||
"There are various ways that the flatpages template tag won't parse"
|
||||
render = lambda t: Template(t).render(Context())
|
||||
|
||||
self.assertRaises(TemplateSyntaxError, render,
|
||||
"{% load flatpages %}{% get_flatpages %}")
|
||||
self.assertRaises(TemplateSyntaxError, render,
|
||||
"{% load flatpages %}{% get_flatpages as %}")
|
||||
self.assertRaises(TemplateSyntaxError, render,
|
||||
"{% load flatpages %}{% get_flatpages cheesecake flatpages %}")
|
||||
self.assertRaises(TemplateSyntaxError, render,
|
||||
"{% load flatpages %}{% get_flatpages as flatpages asdf%}")
|
||||
self.assertRaises(TemplateSyntaxError, render,
|
||||
"{% load flatpages %}{% get_flatpages cheesecake user as flatpages %}")
|
||||
self.assertRaises(TemplateSyntaxError, render,
|
||||
"{% load flatpages %}{% get_flatpages for user as flatpages asdf%}")
|
||||
self.assertRaises(TemplateSyntaxError, render,
|
||||
"{% load flatpages %}{% get_flatpages prefix for user as flatpages asdf%}")
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import os
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.test import TestCase
|
||||
|
||||
class FlatpageViewTests(TestCase):
|
||||
|
@ -38,6 +39,11 @@ class FlatpageViewTests(TestCase):
|
|||
"A flatpage served through a view can require authentication"
|
||||
response = self.client.get('/flatpage_root/sekrit/')
|
||||
self.assertRedirects(response, '/accounts/login/?next=/flatpage_root/sekrit/')
|
||||
User.objects.create_user('testuser', 'test@example.com', 's3krit')
|
||||
self.client.login(username='testuser',password='s3krit')
|
||||
response = self.client.get('/flatpage_root/sekrit/')
|
||||
self.assertEquals(response.status_code, 200)
|
||||
self.assertContains(response, "<p>Isn't it sekrit!</p>")
|
||||
|
||||
def test_fallback_flatpage(self):
|
||||
"A fallback flatpage won't be served if the middleware is disabled"
|
||||
|
|
|
@ -19,7 +19,7 @@ template. It can be associated with one, or multiple, sites.
|
|||
|
||||
.. versionadded:: 1.0
|
||||
|
||||
The content field may optionally be left blank if you prefer to put your
|
||||
The content field may optionally be left blank if you prefer to put your
|
||||
content in a custom template.
|
||||
|
||||
Here are some examples of flatpages on Django-powered sites:
|
||||
|
@ -35,20 +35,20 @@ To install the flatpages app, follow these steps:
|
|||
1. Install the :mod:`sites framework <django.contrib.sites>` by adding
|
||||
``'django.contrib.sites'`` to your :setting:`INSTALLED_APPS` setting,
|
||||
if it's not already in there.
|
||||
|
||||
|
||||
Also make sure you've correctly set :setting:`SITE_ID` to the ID of the
|
||||
site the settings file represents. This will usually be ``1`` (i.e.
|
||||
``SITE_ID = 1``, but if you're using the sites framework to manage
|
||||
multiple sites, it could be the ID of a different site.
|
||||
|
||||
|
||||
2. Add ``'django.contrib.flatpages'`` to your :setting:`INSTALLED_APPS`
|
||||
setting.
|
||||
|
||||
|
||||
3. Add ``'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'``
|
||||
to your :setting:`MIDDLEWARE_CLASSES` setting.
|
||||
|
||||
|
||||
4. Run the command :djadmin:`manage.py syncdb <syncdb>`.
|
||||
|
||||
|
||||
How it works
|
||||
============
|
||||
|
||||
|
@ -67,7 +67,7 @@ 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 :file:`flatpages/default.html`.
|
||||
|
||||
|
||||
* It passes that template a single context variable, :data:`flatpage`, which
|
||||
is the flatpage object. It uses
|
||||
:class:`~django.template.context.RequestContext` in rendering the
|
||||
|
@ -94,7 +94,7 @@ For more on middleware, read the :doc:`middleware docs
|
|||
</topics/http/middleware>`.
|
||||
|
||||
.. admonition:: Ensure that your 404 template works
|
||||
|
||||
|
||||
Note that the
|
||||
:class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware`
|
||||
only steps in once another view has successfully produced a 404 response.
|
||||
|
@ -165,3 +165,64 @@ Since you're already entering raw HTML into the admin page for a flatpage,
|
|||
both ``flatpage.title`` and ``flatpage.content`` are marked as **not**
|
||||
requiring :ref:`automatic HTML escaping <automatic-html-escaping>` in the
|
||||
template.
|
||||
|
||||
Getting a list of :class:`~django.contrib.flatpages.models.Flatpage` objects in your templates
|
||||
==============================================================================================
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
The flatpages app provides a template tag that allows you to iterate
|
||||
over all of the available flatpages on the :ref:`current site
|
||||
<hooking-into-current-site-from-views>`.
|
||||
|
||||
Like all custom template tags, you'll need to :ref:`load its custom
|
||||
tag library <loading-custom-template-libraries>` before you can use
|
||||
it. After loading the library, you can retrieve all current flatpages
|
||||
via the :ttag:`get_flatpages` tag:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% load flatpages %}
|
||||
{% get_flatpages as flatpages %}
|
||||
<ul>
|
||||
{% for page in flatpages %}
|
||||
<li><a href="{{ page.url }}">{{ page.title }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
.. templatetag:: get_flatpages
|
||||
|
||||
Displaying ``registration_required`` flatpages
|
||||
----------------------------------------------
|
||||
|
||||
By default, the :ttag:`get_flatpages` templatetag will only show
|
||||
flatpages that are marked :attr:`registration_required`\=False. If you
|
||||
want to display registration-protected flatpages, you need to specify
|
||||
an authenticated user using a``for`` clause.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% get_flatpages for someuser as about_pages %}
|
||||
|
||||
If you provide an anonymous user, :ttag:`get_flatpages` will behave
|
||||
the same as if you hadn't provided a user -- i.e., it will only show you
|
||||
public flatpages.
|
||||
|
||||
Limiting flatpages by base URL
|
||||
------------------------------
|
||||
|
||||
An optional argument, ``starts_with``, can be applied to limit the
|
||||
returned pages to those beginning with a particular base URL. This
|
||||
argument may be passed as a string, or as a variable to be resolved
|
||||
from the context.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% get_flatpages '/about/' as about_pages %}
|
||||
{% get_flatpages about_prefix as about_pages %}
|
||||
{% get_flatpages '/about/' for someuser as about_pages %}
|
||||
|
||||
|
|
|
@ -102,6 +102,8 @@ like this::
|
|||
|
||||
This has the same benefits as described in the last section.
|
||||
|
||||
.. _hooking-into-current-site-from-views:
|
||||
|
||||
Hooking into the current site from views
|
||||
----------------------------------------
|
||||
|
||||
|
|
Loading…
Reference in New Issue