Merge pull request #249 from kaedroho/medusa-integration

Django-medusa
pull/223/merge
Matt Westcott 2014-05-20 14:39:02 +01:00
commit 725a79f593
9 zmienionych plików z 202 dodań i 2 usunięć

Wyświetl plik

@ -5,6 +5,7 @@ Changelog
~~~~~~~~~~~~~~~~
* Added toolbar to allow logged-in users to add and edit pages from the site front-end
* Support for alternative image processing backends such as Wand, via the WAGTAILIMAGES_BACKENDS setting
* Added support for generating static sites using django-medusa
* Added custom Query set for Pages with some handy methods for querying pages
* Editor's guide documentation
* Editor interface now outputs form media CSS / JS, to support custom widgets with assets

Wyświetl plik

@ -0,0 +1,83 @@
Generating a static site
========================
This document describes how to render your Wagtail site into static HTML files using `django medusa`_ and the 'wagtail.contrib.wagtailmedusa' module.
Installing django-medusa
~~~~~~~~~~~~~~~~~~~~~~~~
Firstly, install django medusa from pip:
.. code::
pip install django-medusa
Then add 'django_medusa' and 'wagtail.contrib.wagtailmedusa' to INSTALLED_APPS:
.. code:: python
INSTALLED_APPS = [
...
'django_medusa',
'wagtail.contrib.wagtailmedusa',
]
Replacing GET parameters with custom routing
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Pages which require GET parameters (eg, pagination) don't generate suitable filenames for generated HTML files so they need to be changed to use custom routing instead.
For example, lets say we have a Blog Index which uses pagination. We can override the 'route' method to make it respond on urls like '/page/1' and pass the page number through to the serve method:
.. code:: python
class BlogIndex(Page):
...
def serve(self, request, page=1):
...
def route(self, request, path_components):
if self.live and len(path_components) == 2 and path_components[0] == 'page':
try:
return self.serve(request, page=int(path_components[1]))
except (TypeError, ValueError):
pass
return super(BlogIndex, self).route(request, path_components)
Rendering pages which use custom routing
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For page types that override the route method, we need to let django medusa know which URLs it responds on. This is done by overriding the 'get_static_site_paths' method to make it yield one string per URL path.
For example, the BlogIndex above would need to yield one URL for each page of results:
.. code:: python
def get_static_site_paths(self):
# Get page count
page_count = ...
# Yield a path for each page
for page in range(page_count):
yield '/%d/' % (page + 1)
# Yield from superclass
for path in super(BlogIndex, self).get_static_site_paths():
yield path
Rendering
~~~~~~~~~
To render a site, just run ``./manage.py staticsitegen``. This will render the entire website and place the HTML in a folder called 'medusa_output'. The static and media folders need to be copied into this folder manually after the rendering is complete.
To test, open the 'medusa_output' folder in a terminal and run ``python -m SimpleHTTPServer``.
.. _django medusa: https://github.com/mtigas/django-medusa

Wyświetl plik

Wyświetl plik

@ -0,0 +1,24 @@
from django_medusa.renderers import StaticSiteRenderer
from wagtail.wagtailcore.models import Site
from wagtail.wagtaildocs.models import Document
class PageRenderer(StaticSiteRenderer):
def get_paths(self):
# Get site
# TODO: Find way to get this to work with other sites
site = Site.objects.filter(is_default_site=True).first()
if site is None:
return []
# Return list of paths
return site.root_page.get_static_site_paths()
class DocumentRenderer(StaticSiteRenderer):
def get_paths(self):
# Return list of paths to documents
return (doc.url for doc in Document.objects.all())
renderers = [PageRenderer, DocumentRenderer]

Wyświetl plik

@ -1,4 +1,5 @@
from django.db import models
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from modelcluster.fields import ParentalKey
from wagtail.wagtailcore.models import Page, Orderable
from wagtail.wagtailcore.fields import RichTextField
@ -187,11 +188,48 @@ class EventIndex(Page):
intro = RichTextField(blank=True)
ajax_template = 'tests/includes/event_listing.html'
def get_context(self, request):
def get_events(self):
return self.get_children().live().type(EventPage)
def get_paginator(self):
return Paginator(self.get_events(), 4)
def get_context(self, request, page=1):
# Pagination
paginator = self.get_paginator()
try:
events = paginator.page(page)
except PageNotAnInteger:
events = paginator.page(1)
except EmptyPage:
events = paginator.page(paginator.num_pages)
# Update context
context = super(EventIndex, self).get_context(request)
context['events'] = EventPage.objects.filter(live=True)
context['events'] = events
return context
def route(self, request, path_components):
if self.live and len(path_components) == 1:
try:
return self.serve(request, page=int(path_components[0]))
except (TypeError, ValueError):
pass
return super(EventIndex, self).route(request, path_components)
def get_static_site_paths(self):
# Get page count
page_count = self.get_paginator().num_pages
# Yield a path for each page
for page in range(page_count):
yield '/%d/' % (page + 1)
# Yield from superclass
for path in super(EventIndex, self).get_static_site_paths():
yield path
EventIndex.content_panels = [
FieldPanel('title', classname="full title"),
FieldPanel('intro', classname="full"),

Wyświetl plik

@ -622,6 +622,19 @@ class Page(MP_Node, ClusterableModel, Indexed):
"""
return self.serve(self.dummy_request())
def get_static_site_paths(self):
"""
This is a generator of URL paths to feed into a static site generator
Override this if you would like to create static versions of subpages
"""
# Yield paths for this page
yield '/'
# Yield paths for child pages
for child in self.get_children().live():
for path in child.specific.get_static_site_paths():
yield '/' + child.slug + path
def get_ancestors(self, inclusive=False):
return Page.objects.ancestor_of(self, inclusive)

Wyświetl plik

@ -162,6 +162,47 @@ class TestServeView(TestCase):
self.assertContains(response, '<a href="/events/christmas/">Christmas</a>')
class TestStaticSitePaths(TestCase):
def setUp(self):
self.root_page = Page.objects.get(id=1)
# For simple tests
self.home_page = self.root_page.add_child(instance=SimplePage(title="Homepage", slug="home"))
self.about_page = self.home_page.add_child(instance=SimplePage(title="About us", slug="about"))
self.contact_page = self.home_page.add_child(instance=SimplePage(title="Contact", slug="contact"))
# For custom tests
self.event_index = self.root_page.add_child(instance=EventIndex(title="Events", slug="events"))
for i in range(20):
self.event_index.add_child(instance=EventPage(title="Event " + str(i), slug="event" + str(i)))
def test_local_static_site_paths(self):
paths = list(self.about_page.get_static_site_paths())
self.assertEqual(paths, ['/'])
def test_child_static_site_paths(self):
paths = list(self.home_page.get_static_site_paths())
self.assertEqual(paths, ['/', '/about/', '/contact/'])
def test_custom_static_site_paths(self):
paths = list(self.event_index.get_static_site_paths())
# Event index path
expected_paths = ['/']
# One path for each page of results
expected_paths.extend(['/' + str(i + 1) + '/' for i in range(5)])
# One path for each event page
expected_paths.extend(['/event' + str(i) + '/' for i in range(20)])
paths.sort()
expected_paths.sort()
self.assertEqual(paths, expected_paths)
class TestPageUrlTags(TestCase):
fixtures = ['test.json']