kopia lustrzana https://github.com/wagtail/wagtail
Merge branch 'master' into form-builder
commit
4c4b05689a
|
@ -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
|
||||
|
|
|
@ -102,12 +102,17 @@ Required dependencies
|
|||
=====================
|
||||
|
||||
- `pip <https://github.com/pypa/pip>`_
|
||||
- `libjpeg <http://ijg.org/>`_
|
||||
- `libxml2 <http://xmlsoft.org/>`_
|
||||
- `libxslt <http://xmlsoft.org/XSLT/>`_
|
||||
- `zlib <http://www.zlib.net/>`_
|
||||
|
||||
Optional dependencies
|
||||
=====================
|
||||
|
||||
- `PostgreSQL`_
|
||||
- `Elasticsearch`_
|
||||
- `Redis`_
|
||||
|
||||
Installation
|
||||
============
|
||||
|
@ -137,6 +142,7 @@ with a regular Django project.
|
|||
.. _the Wagtail codebase: https://github.com/torchbox/wagtail
|
||||
.. _PostgreSQL: http://www.postgresql.org
|
||||
.. _Elasticsearch: http://www.elasticsearch.org
|
||||
.. _Redis: http://redis.io/
|
||||
|
||||
_`Remove the demo app`
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -13,6 +13,7 @@ It supports Django 1.6.2+ on Python 2.6 and 2.7. Django 1.7 and Python 3 support
|
|||
wagtail_search
|
||||
deploying
|
||||
performance
|
||||
static_site_generation
|
||||
contributing
|
||||
support
|
||||
roadmap
|
||||
|
|
|
@ -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
|
|
@ -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]
|
|
@ -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
|
||||
|
@ -188,11 +189,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"),
|
||||
|
|
|
@ -82,8 +82,6 @@ def content_type_use(request, content_type_app_name, content_type_model_name):
|
|||
except EmptyPage:
|
||||
pages = paginator.page(paginator.num_pages)
|
||||
|
||||
print page_class
|
||||
|
||||
return render(request, 'wagtailadmin/pages/content_type_use.html', {
|
||||
'pages': pages,
|
||||
'app_name': content_type_app_name,
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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']
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue