0
0
mirror of https://github.com/wagtail/wagtail.git synced 2024-11-30 01:46:24 +01:00
wagtail/docs/topics/pages.rst

526 lines
20 KiB
ReStructuredText
Raw Normal View History

===========
Page models
===========
2014-07-23 11:11:50 +02:00
Each page type (a.k.a. content type) in Wagtail is represented by a Django model. All page models must inherit from the :class:`wagtail.core.models.Page` class.
2014-07-23 11:11:50 +02:00
As all page types are Django models, you can use any field type that Django provides. See `Model field reference <https://docs.djangoproject.com/en/stable/ref/models/fields/>`_ for a complete list of field types you can use. Wagtail also provides :class:`~wagtail.core.fields.RichTextField` which provides a WYSIWYG editor for editing rich-text content.
2014-07-23 11:11:50 +02:00
2015-02-19 17:48:54 +01:00
.. topic:: Django models
If you're not yet familiar with Django models, have a quick look at the following links to get you started:
2015-10-05 22:06:37 +02:00
* `Creating models <https://docs.djangoproject.com/en/stable/intro/tutorial02/#creating-models>`_
* `Model syntax <https://docs.djangoproject.com/en/stable/topics/db/models/>`_
2015-02-19 17:48:54 +01:00
2015-09-21 15:44:31 +02:00
An example Wagtail page model
2015-06-19 11:12:39 +02:00
=============================
2014-07-23 11:11:50 +02:00
This example represents a typical blog post:
2014-07-23 11:11:50 +02:00
.. code-block:: python
from django.db import models
2015-09-21 15:44:31 +02:00
from modelcluster.fields import ParentalKey
from wagtail.core.models import Page, Orderable
from wagtail.core.fields import RichTextField
Rename wagtail.wagtailadmin to wagtail.admin Conflicts: docs/advanced_topics/customisation/admin_templates.rst docs/advanced_topics/customisation/page_editing_interface.rst docs/advanced_topics/i18n/duplicate_tree.rst docs/advanced_topics/jinja2.rst docs/advanced_topics/settings.rst docs/getting_started/integrating_into_django.rst docs/getting_started/tutorial.rst docs/reference/hooks.rst docs/reference/pages/panels.rst docs/topics/pages.rst docs/topics/streamfield.rst wagtail/admin/blocks.py wagtail/admin/checks.py wagtail/admin/edit_handlers.py wagtail/admin/forms.py wagtail/admin/rich_text.py wagtail/admin/search.py wagtail/admin/site_summary.py wagtail/admin/templatetags/wagtailadmin_tags.py wagtail/admin/tests/test_admin_search.py wagtail/admin/tests/test_buttons_hooks.py wagtail/admin/tests/test_compare.py wagtail/admin/tests/test_edit_handlers.py wagtail/admin/tests/test_page_chooser.py wagtail/admin/tests/test_pages_views.py wagtail/admin/tests/test_rich_text.py wagtail/admin/tests/test_widgets.py wagtail/admin/tests/tests.py wagtail/admin/urls/__init__.py wagtail/admin/views/account.py wagtail/admin/views/chooser.py wagtail/admin/views/collection_privacy.py wagtail/admin/views/collections.py wagtail/admin/views/home.py wagtail/admin/views/page_privacy.py wagtail/admin/viewsets/model.py wagtail/admin/wagtail_hooks.py wagtail/admin/widgets.py wagtail/contrib/settings/registry.py wagtail/contrib/wagtailsearchpromotions/wagtail_hooks.py wagtail/contrib/wagtailstyleguide/wagtail_hooks.py wagtail/project_template/project_name/settings/base.py wagtail/project_template/project_name/urls.py wagtail/tests/non_root_urls.py wagtail/tests/settings.py wagtail/tests/snippets/models.py wagtail/tests/testapp/models.py wagtail/tests/testapp/wagtail_hooks.py wagtail/tests/urls.py wagtail/wagtaildocs/models.py wagtail/wagtaildocs/views/chooser.py wagtail/wagtaildocs/wagtail_hooks.py wagtail/wagtailembeds/wagtail_hooks.py wagtail/wagtailforms/models.py wagtail/wagtailforms/tests/test_views.py wagtail/wagtailforms/views.py wagtail/wagtailforms/wagtail_hooks.py wagtail/wagtailimages/models.py wagtail/wagtailimages/views/chooser.py wagtail/wagtailimages/wagtail_hooks.py wagtail/wagtailredirects/forms.py wagtail/wagtailredirects/wagtail_hooks.py wagtail/wagtailsites/forms.py wagtail/wagtailsites/views.py wagtail/wagtailsites/wagtail_hooks.py wagtail/wagtailsnippets/tests.py wagtail/wagtailsnippets/wagtail_hooks.py wagtail/wagtailusers/forms.py wagtail/wagtailusers/views/groups.py wagtail/wagtailusers/wagtail_hooks.py
2017-11-17 11:44:34 +01:00
from wagtail.admin.edit_handlers import FieldPanel, MultiFieldPanel, InlinePanel
from wagtail.images.edit_handlers import ImageChooserPanel
from wagtail.search import index
2014-07-23 11:11:50 +02:00
2015-02-19 17:25:17 +01:00
2014-07-23 11:11:50 +02:00
class BlogPage(Page):
2015-09-21 15:44:31 +02:00
# Database fields
2014-07-23 11:11:50 +02:00
body = RichTextField()
date = models.DateField("Post date")
feed_image = models.ForeignKey(
'wagtailimages.Image',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+'
)
2015-09-21 15:44:31 +02:00
2016-07-15 20:58:47 +02:00
# Search index configuration
2015-09-21 15:44:31 +02:00
search_fields = Page.search_fields + [
2015-09-21 15:44:31 +02:00
index.SearchField('body'),
index.FilterField('date'),
]
2015-09-21 15:44:31 +02:00
# Editor panels configuration
content_panels = Page.content_panels + [
FieldPanel('date'),
FieldPanel('body', classname="full"),
2015-09-21 15:44:31 +02:00
InlinePanel('related_links', label="Related links"),
]
promote_panels = [
MultiFieldPanel(Page.promote_panels, "Common page configuration"),
ImageChooserPanel('feed_image'),
]
2014-07-23 11:11:50 +02:00
2015-09-21 15:44:31 +02:00
2015-10-05 22:06:37 +02:00
# Parent page / subpage type rules
2015-09-21 15:44:31 +02:00
parent_page_types = ['blog.BlogIndex']
subpage_types = []
class BlogPageRelatedLink(Orderable):
page = ParentalKey(BlogPage, on_delete=models.CASCADE, related_name='related_links')
2015-09-21 15:44:31 +02:00
name = models.CharField(max_length=255)
url = models.URLField()
panels = [
FieldPanel('name'),
FieldPanel('url'),
]
.. important::
2015-09-21 15:44:31 +02:00
Ensure that none of your field names are the same as your class names. This will cause errors due to the way Django handles relations (`read more <https://github.com/wagtail/wagtail/issues/503>`_). In our examples we have avoided this by appending "Page" to each model name.
2014-07-23 11:11:50 +02:00
2015-09-21 15:44:31 +02:00
Writing page models
===================
2014-07-23 11:11:50 +02:00
2015-09-21 15:44:31 +02:00
Here we'll describe each section of the above example to help you create your own page models.
2014-07-23 11:11:50 +02:00
2015-09-21 15:44:31 +02:00
Database fields
---------------
2015-10-05 22:06:37 +02:00
Each Wagtail page type is a Django model, represented in the database as a separate table.
2015-10-05 22:06:37 +02:00
Each page type can have its own set of fields. For example, a news article may have body text and a published date, whereas an event page may need separate fields for venue and start/finish times.
In Wagtail, you can use any Django field class. Most field classes provided by third party apps should work as well.
2015-10-05 22:06:37 +02:00
Wagtail also provides a couple of field classes of its own:
2015-09-21 15:44:31 +02:00
- ``RichTextField`` - For rich text content
- ``StreamField`` - A block-based content field (see: :doc:`/topics/streamfield`)
2015-09-21 15:44:31 +02:00
For tagging, Wagtail fully supports `django-taggit <https://django-taggit.readthedocs.org/en/latest/>`_ so we recommend using that.
2015-09-21 15:44:31 +02:00
Search
------
The ``search_fields`` attribute defines which fields are added to the search index and how they are indexed.
This should be a list of ``SearchField`` and ``FilterField`` objects. ``SearchField`` adds a field for full-text search. ``FilterField`` adds a field for filtering the results. A field can be indexed with both ``SearchField`` and ``FilterField`` at the same time (but only one instance of each).
2015-09-21 15:44:31 +02:00
In the above example, we've indexed ``body`` for full-text search and ``date`` for filtering.
The arguments that these field types accept are documented in :ref:`wagtailsearch_indexing_fields`.
2015-09-21 15:44:31 +02:00
Editor panels
-------------
2015-10-05 22:06:37 +02:00
There are a few attributes for defining how the page's fields will be arranged in the page editor interface:
2015-09-21 15:44:31 +02:00
- ``content_panels`` - For content, such as main body text
- ``promote_panels`` - For metadata, such as tags, thumbnail image and SEO title
- ``settings_panels`` - For settings, such as publish date
Each of these attributes is set to a list of ``EditHandler`` objects, which defines which fields appear on which tabs and how they are structured on each tab.
2015-09-21 15:44:31 +02:00
Here's a summary of the ``EditHandler`` classes that Wagtail provides out of the box. See :doc:`/reference/pages/panels` for full descriptions.
**Basic**
These allow editing of model fields. The ``FieldPanel`` class will choose the correct widget based on the type of the field, though ``StreamField`` fields need to use a specialised panel class.
2015-09-21 15:44:31 +02:00
Rename wagtail.wagtailadmin to wagtail.admin Conflicts: docs/advanced_topics/customisation/admin_templates.rst docs/advanced_topics/customisation/page_editing_interface.rst docs/advanced_topics/i18n/duplicate_tree.rst docs/advanced_topics/jinja2.rst docs/advanced_topics/settings.rst docs/getting_started/integrating_into_django.rst docs/getting_started/tutorial.rst docs/reference/hooks.rst docs/reference/pages/panels.rst docs/topics/pages.rst docs/topics/streamfield.rst wagtail/admin/blocks.py wagtail/admin/checks.py wagtail/admin/edit_handlers.py wagtail/admin/forms.py wagtail/admin/rich_text.py wagtail/admin/search.py wagtail/admin/site_summary.py wagtail/admin/templatetags/wagtailadmin_tags.py wagtail/admin/tests/test_admin_search.py wagtail/admin/tests/test_buttons_hooks.py wagtail/admin/tests/test_compare.py wagtail/admin/tests/test_edit_handlers.py wagtail/admin/tests/test_page_chooser.py wagtail/admin/tests/test_pages_views.py wagtail/admin/tests/test_rich_text.py wagtail/admin/tests/test_widgets.py wagtail/admin/tests/tests.py wagtail/admin/urls/__init__.py wagtail/admin/views/account.py wagtail/admin/views/chooser.py wagtail/admin/views/collection_privacy.py wagtail/admin/views/collections.py wagtail/admin/views/home.py wagtail/admin/views/page_privacy.py wagtail/admin/viewsets/model.py wagtail/admin/wagtail_hooks.py wagtail/admin/widgets.py wagtail/contrib/settings/registry.py wagtail/contrib/wagtailsearchpromotions/wagtail_hooks.py wagtail/contrib/wagtailstyleguide/wagtail_hooks.py wagtail/project_template/project_name/settings/base.py wagtail/project_template/project_name/urls.py wagtail/tests/non_root_urls.py wagtail/tests/settings.py wagtail/tests/snippets/models.py wagtail/tests/testapp/models.py wagtail/tests/testapp/wagtail_hooks.py wagtail/tests/urls.py wagtail/wagtaildocs/models.py wagtail/wagtaildocs/views/chooser.py wagtail/wagtaildocs/wagtail_hooks.py wagtail/wagtailembeds/wagtail_hooks.py wagtail/wagtailforms/models.py wagtail/wagtailforms/tests/test_views.py wagtail/wagtailforms/views.py wagtail/wagtailforms/wagtail_hooks.py wagtail/wagtailimages/models.py wagtail/wagtailimages/views/chooser.py wagtail/wagtailimages/wagtail_hooks.py wagtail/wagtailredirects/forms.py wagtail/wagtailredirects/wagtail_hooks.py wagtail/wagtailsites/forms.py wagtail/wagtailsites/views.py wagtail/wagtailsites/wagtail_hooks.py wagtail/wagtailsnippets/tests.py wagtail/wagtailsnippets/wagtail_hooks.py wagtail/wagtailusers/forms.py wagtail/wagtailusers/views/groups.py wagtail/wagtailusers/wagtail_hooks.py
2017-11-17 11:44:34 +01:00
- :class:`~wagtail.admin.edit_handlers.FieldPanel`
- :class:`~wagtail.admin.edit_handlers.StreamFieldPanel`
2015-09-21 15:44:31 +02:00
**Structural**
These are used for structuring fields in the interface.
Rename wagtail.wagtailadmin to wagtail.admin Conflicts: docs/advanced_topics/customisation/admin_templates.rst docs/advanced_topics/customisation/page_editing_interface.rst docs/advanced_topics/i18n/duplicate_tree.rst docs/advanced_topics/jinja2.rst docs/advanced_topics/settings.rst docs/getting_started/integrating_into_django.rst docs/getting_started/tutorial.rst docs/reference/hooks.rst docs/reference/pages/panels.rst docs/topics/pages.rst docs/topics/streamfield.rst wagtail/admin/blocks.py wagtail/admin/checks.py wagtail/admin/edit_handlers.py wagtail/admin/forms.py wagtail/admin/rich_text.py wagtail/admin/search.py wagtail/admin/site_summary.py wagtail/admin/templatetags/wagtailadmin_tags.py wagtail/admin/tests/test_admin_search.py wagtail/admin/tests/test_buttons_hooks.py wagtail/admin/tests/test_compare.py wagtail/admin/tests/test_edit_handlers.py wagtail/admin/tests/test_page_chooser.py wagtail/admin/tests/test_pages_views.py wagtail/admin/tests/test_rich_text.py wagtail/admin/tests/test_widgets.py wagtail/admin/tests/tests.py wagtail/admin/urls/__init__.py wagtail/admin/views/account.py wagtail/admin/views/chooser.py wagtail/admin/views/collection_privacy.py wagtail/admin/views/collections.py wagtail/admin/views/home.py wagtail/admin/views/page_privacy.py wagtail/admin/viewsets/model.py wagtail/admin/wagtail_hooks.py wagtail/admin/widgets.py wagtail/contrib/settings/registry.py wagtail/contrib/wagtailsearchpromotions/wagtail_hooks.py wagtail/contrib/wagtailstyleguide/wagtail_hooks.py wagtail/project_template/project_name/settings/base.py wagtail/project_template/project_name/urls.py wagtail/tests/non_root_urls.py wagtail/tests/settings.py wagtail/tests/snippets/models.py wagtail/tests/testapp/models.py wagtail/tests/testapp/wagtail_hooks.py wagtail/tests/urls.py wagtail/wagtaildocs/models.py wagtail/wagtaildocs/views/chooser.py wagtail/wagtaildocs/wagtail_hooks.py wagtail/wagtailembeds/wagtail_hooks.py wagtail/wagtailforms/models.py wagtail/wagtailforms/tests/test_views.py wagtail/wagtailforms/views.py wagtail/wagtailforms/wagtail_hooks.py wagtail/wagtailimages/models.py wagtail/wagtailimages/views/chooser.py wagtail/wagtailimages/wagtail_hooks.py wagtail/wagtailredirects/forms.py wagtail/wagtailredirects/wagtail_hooks.py wagtail/wagtailsites/forms.py wagtail/wagtailsites/views.py wagtail/wagtailsites/wagtail_hooks.py wagtail/wagtailsnippets/tests.py wagtail/wagtailsnippets/wagtail_hooks.py wagtail/wagtailusers/forms.py wagtail/wagtailusers/views/groups.py wagtail/wagtailusers/wagtail_hooks.py
2017-11-17 11:44:34 +01:00
- :class:`~wagtail.admin.edit_handlers.MultiFieldPanel` - For grouping similar fields together
- :class:`~wagtail.admin.edit_handlers.InlinePanel` - For inlining child models
- :class:`~wagtail.admin.edit_handlers.FieldRowPanel` - For organising multiple fields into a single row
2015-09-21 15:44:31 +02:00
**Chooser**
``ForeignKey`` fields to certain models can use one of the below ``ChooserPanel`` classes. These add a nice modal chooser interface, and the image/document choosers also allow uploading new files without leaving the page editor.
2015-09-21 15:44:31 +02:00
Rename wagtail.wagtailadmin to wagtail.admin Conflicts: docs/advanced_topics/customisation/admin_templates.rst docs/advanced_topics/customisation/page_editing_interface.rst docs/advanced_topics/i18n/duplicate_tree.rst docs/advanced_topics/jinja2.rst docs/advanced_topics/settings.rst docs/getting_started/integrating_into_django.rst docs/getting_started/tutorial.rst docs/reference/hooks.rst docs/reference/pages/panels.rst docs/topics/pages.rst docs/topics/streamfield.rst wagtail/admin/blocks.py wagtail/admin/checks.py wagtail/admin/edit_handlers.py wagtail/admin/forms.py wagtail/admin/rich_text.py wagtail/admin/search.py wagtail/admin/site_summary.py wagtail/admin/templatetags/wagtailadmin_tags.py wagtail/admin/tests/test_admin_search.py wagtail/admin/tests/test_buttons_hooks.py wagtail/admin/tests/test_compare.py wagtail/admin/tests/test_edit_handlers.py wagtail/admin/tests/test_page_chooser.py wagtail/admin/tests/test_pages_views.py wagtail/admin/tests/test_rich_text.py wagtail/admin/tests/test_widgets.py wagtail/admin/tests/tests.py wagtail/admin/urls/__init__.py wagtail/admin/views/account.py wagtail/admin/views/chooser.py wagtail/admin/views/collection_privacy.py wagtail/admin/views/collections.py wagtail/admin/views/home.py wagtail/admin/views/page_privacy.py wagtail/admin/viewsets/model.py wagtail/admin/wagtail_hooks.py wagtail/admin/widgets.py wagtail/contrib/settings/registry.py wagtail/contrib/wagtailsearchpromotions/wagtail_hooks.py wagtail/contrib/wagtailstyleguide/wagtail_hooks.py wagtail/project_template/project_name/settings/base.py wagtail/project_template/project_name/urls.py wagtail/tests/non_root_urls.py wagtail/tests/settings.py wagtail/tests/snippets/models.py wagtail/tests/testapp/models.py wagtail/tests/testapp/wagtail_hooks.py wagtail/tests/urls.py wagtail/wagtaildocs/models.py wagtail/wagtaildocs/views/chooser.py wagtail/wagtaildocs/wagtail_hooks.py wagtail/wagtailembeds/wagtail_hooks.py wagtail/wagtailforms/models.py wagtail/wagtailforms/tests/test_views.py wagtail/wagtailforms/views.py wagtail/wagtailforms/wagtail_hooks.py wagtail/wagtailimages/models.py wagtail/wagtailimages/views/chooser.py wagtail/wagtailimages/wagtail_hooks.py wagtail/wagtailredirects/forms.py wagtail/wagtailredirects/wagtail_hooks.py wagtail/wagtailsites/forms.py wagtail/wagtailsites/views.py wagtail/wagtailsites/wagtail_hooks.py wagtail/wagtailsnippets/tests.py wagtail/wagtailsnippets/wagtail_hooks.py wagtail/wagtailusers/forms.py wagtail/wagtailusers/views/groups.py wagtail/wagtailusers/wagtail_hooks.py
2017-11-17 11:44:34 +01:00
- :class:`~wagtail.admin.edit_handlers.PageChooserPanel`
- :class:`~wagtail.images.edit_handlers.ImageChooserPanel`
- :class:`~wagtail.documents.edit_handlers.DocumentChooserPanel`
- :class:`~wagtail.snippets.edit_handlers.SnippetChooserPanel`
2015-09-21 15:44:31 +02:00
.. note::
In order to use one of these choosers, the model being linked to must either be a page, image, document or snippet.
2015-10-05 22:06:37 +02:00
To link to any other model type, you should use ``FieldPanel``, which will create a dropdown box.
2015-09-21 15:44:31 +02:00
2015-09-23 21:54:39 +02:00
Customising the page editor interface
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The page editor can be customised further. See :doc:`/advanced_topics/customisation/page_editing_interface`.
2015-09-21 15:44:31 +02:00
.. _page_type_business_rules:
2015-10-05 22:06:37 +02:00
Parent page / subpage type rules
--------------------------------
2015-09-21 15:44:31 +02:00
These two attributes allow you to control where page types may be used in your site. It allows you to define rules like "blog entries may only be created under a blog index".
Both take a list of model classes or model names. Model names are of the format ``app_label.ModelName``. If the ``app_label`` is omitted, the same app is assumed.
2015-10-05 22:06:37 +02:00
- ``parent_page_types`` limits which page types this type can be created under
- ``subpage_types`` limits which page types can be created under this type
2015-09-21 15:44:31 +02:00
By default, any page type can be created under any page type and it is not necessary to set these attributes if that's the desired behaviour.
Setting ``parent_page_types`` to an empty list is a good way of preventing a particular page type from being created in the editor interface.
.. _page_urls:
Page URLs
---------
The most common method of retrieving page URLs is by using the ``{% pageurl %}`` template tag. Since it's called from a template, ``pageurl`` automatically includes the optimizations mentioned below. For more information, see :ref:`pageurl_tag`.
Page models also include several low-level methods for overriding or accessing page URLs.
Customising URL patterns for a page model
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2018-04-03 18:07:53 +02:00
The ``Page.get_url_parts(request)`` method will not typically be called directly, but may be overridden to define custom URL routing for a given page model. It should return a tuple of ``(site_id, root_url, page_path)``, which are used by ``get_url`` and ``get_full_url`` (see below) to construct the given type of page URL.
When overriding ``get_url_parts()``, you should accept ``*args, **kwargs``:
.. code-block:: python
def get_url_parts(self, *args, **kwargs):
and pass those through at the point where you are calling ``get_url_parts`` on ``super`` (if applicable), e.g.:
.. code-block:: python
super().get_url_parts(*args, **kwargs)
While you could pass only the ``request`` keyword argument, passing all arguments as-is ensures compatibility with any
future changes to these method signatures.
For more information, please see :meth:`wagtail.core.models.Page.get_url_parts`.
Obtaining URLs for page instances
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``Page.get_url(request)`` method can be called whenever a page URL is needed. It defaults to returning local URLs (not including the protocol or domain) if it can detect that the page is on current site (via ``request.site``); otherwise, a full URL including the protocol and domain is returned. Whenever possible, the optional ``request`` argument should be included to enable per-request caching of site-level URL information and facilitate the generation of local URLs.
2018-03-16 18:57:19 +01:00
A common use case for ``get_url(request)`` is in any custom template tag your project may include for generating navigation menus. When writing such a custom template tag, ensure that it includes ``takes_context=True`` and use ``context.get('request')`` to safely pass the
request or ``None`` if no request exists in the context.
For more information, please see :meth:`wagtail.core.models.Page.get_url`.
In the event a full URL (including the protocol and domain) is needed, ``Page.get_full_url(request)`` can be used instead. Whenever possible, the optional ``request`` argument should be included to enable per-request caching of site-level URL information. For more information, please see :meth:`wagtail.core.models.Page.get_full_url`.
2015-09-21 15:44:31 +02:00
Template rendering
==================
Each page model can be given an HTML template which is rendered when a user browses to a page on the site frontend. This is the simplest and most common way to get Wagtail content to end users (but not the only way).
2015-09-21 15:44:31 +02:00
2015-09-23 21:05:49 +02:00
Adding a template for a page model
----------------------------------
Wagtail automatically chooses a name for the template based on the app label and model class name.
Format: ``<app_label>/<model_name (snake cased)>.html``
For example, the template for the above blog page will be: ``blog/blog_page.html``
You just need to create a template in a location where it can be accessed with this name.
Template context
----------------
Wagtail renders templates with the ``page`` variable bound to the page instance being rendered. Use this to access the content of the page. For example, to get the title of the current page, use ``{{ page.title }}``. All variables provided by `context processors <https://docs.djangoproject.com/en/stable/ref/templates/api/#subclassing-context-requestcontext>`_ are also available.
2015-09-23 21:05:49 +02:00
Customising template context
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
All pages have a ``get_context`` method that is called whenever the template is rendered and returns a dictionary of variables to bind into the template.
2015-10-04 17:25:36 +02:00
To add more variables to the template context, you can override this method:
2015-09-23 21:05:49 +02:00
.. code-block:: python
class BlogIndexPage(Page):
...
def get_context(self, request):
context = super().get_context(request)
2015-09-23 21:05:49 +02:00
# Add extra variables and return the updated context
context['blog_entries'] = BlogPage.objects.child_of(self).live()
return context
The variables can then be used in the template:
.. code-block:: HTML+Django
{{ page.title }}
2015-09-23 21:05:49 +02:00
{% for entry in blog_entries %}
{{ entry.title }}
{% endfor %}
Changing the template
---------------------
2015-10-04 17:25:36 +02:00
Set the ``template`` attribute on the class to use a different template file:
2015-09-23 21:05:49 +02:00
.. code-block:: python
class BlogPage(Page):
...
template = 'other_template.html'
Dynamically choosing the template
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2015-10-04 17:25:36 +02:00
The template can be changed on a per-instance basis by defining a ``get_template`` method on the page class. This method is called every time the page is rendered:
2015-09-23 21:05:49 +02:00
.. code-block:: python
class BlogPage(Page):
...
use_other_template = models.BooleanField()
def get_template(self, request):
if self.use_other_template:
return 'blog/other_blog_page.html'
return 'blog/blog_page.html'
In this example, pages that have the ``use_other_template`` boolean field set will use the ``blog/other_blog_page.html`` template. All other pages will use the default ``blog/blog_page.html``.
2015-09-23 21:05:49 +02:00
More control over page rendering
--------------------------------
All page classes have a ``serve()`` method that internally calls the ``get_context`` and ``get_template`` methods and renders the template. This method is similar to a Django view function, taking a Django ``Request`` object and returning a Django ``Response`` object.
2015-09-23 21:05:49 +02:00
2015-10-04 17:25:36 +02:00
This method can also be overridden for complete control over page rendering.
For example, here's a way to make a page respond with a JSON representation of itself:
2015-09-23 21:05:49 +02:00
.. code-block:: python
from django.http import JsonResponse
class BlogPage(Page):
...
def serve(self, request):
return JsonResponse({
'title': self.title,
'body': self.body,
'date': self.date,
# Resizes the image to 300px width and gets a URL to it
'feed_image': self.feed_image.get_rendition('width-300').url,
})
2015-09-21 15:44:31 +02:00
2015-09-29 22:26:44 +02:00
Inline models
=============
2015-09-21 15:44:31 +02:00
2015-09-29 22:26:44 +02:00
Wagtail can nest the content of other models within the page. This is useful for creating repeated fields, such as related links or items to display in a carousel. Inline model content is also versioned with the rest of the page content.
Each inline model requires the following:
- It must inherit from :class:`wagtail.core.models.Orderable`
2015-09-29 22:26:44 +02:00
- It must have a ``ParentalKey`` to the parent model
.. note:: django-modelcluster and ParentalKey
2015-10-05 22:06:37 +02:00
The model inlining feature is provided by `django-modelcluster <https://github.com/torchbox/django-modelcluster>`_ and the ``ParentalKey`` field type must be imported from there:
2015-09-29 22:26:44 +02:00
2015-10-05 22:06:37 +02:00
.. code-block:: python
2015-09-29 22:26:44 +02:00
from modelcluster.fields import ParentalKey
2015-10-05 22:06:37 +02:00
``ParentalKey`` is a subclass of Django's ``ForeignKey``, and takes the same arguments.
2015-09-29 22:26:44 +02:00
For example, the following inline model can be used to add related links (a list of name, url pairs) to the ``BlogPage`` model:
.. code-block:: python
from django.db import models
from modelcluster.fields import ParentalKey
from wagtail.core.models import Orderable
2015-09-29 22:26:44 +02:00
class BlogPageRelatedLink(Orderable):
page = ParentalKey(BlogPage, on_delete=models.CASCADE, related_name='related_links')
2015-09-29 22:26:44 +02:00
name = models.CharField(max_length=255)
url = models.URLField()
panels = [
FieldPanel('name'),
FieldPanel('url'),
]
Rename wagtail.wagtailadmin to wagtail.admin Conflicts: docs/advanced_topics/customisation/admin_templates.rst docs/advanced_topics/customisation/page_editing_interface.rst docs/advanced_topics/i18n/duplicate_tree.rst docs/advanced_topics/jinja2.rst docs/advanced_topics/settings.rst docs/getting_started/integrating_into_django.rst docs/getting_started/tutorial.rst docs/reference/hooks.rst docs/reference/pages/panels.rst docs/topics/pages.rst docs/topics/streamfield.rst wagtail/admin/blocks.py wagtail/admin/checks.py wagtail/admin/edit_handlers.py wagtail/admin/forms.py wagtail/admin/rich_text.py wagtail/admin/search.py wagtail/admin/site_summary.py wagtail/admin/templatetags/wagtailadmin_tags.py wagtail/admin/tests/test_admin_search.py wagtail/admin/tests/test_buttons_hooks.py wagtail/admin/tests/test_compare.py wagtail/admin/tests/test_edit_handlers.py wagtail/admin/tests/test_page_chooser.py wagtail/admin/tests/test_pages_views.py wagtail/admin/tests/test_rich_text.py wagtail/admin/tests/test_widgets.py wagtail/admin/tests/tests.py wagtail/admin/urls/__init__.py wagtail/admin/views/account.py wagtail/admin/views/chooser.py wagtail/admin/views/collection_privacy.py wagtail/admin/views/collections.py wagtail/admin/views/home.py wagtail/admin/views/page_privacy.py wagtail/admin/viewsets/model.py wagtail/admin/wagtail_hooks.py wagtail/admin/widgets.py wagtail/contrib/settings/registry.py wagtail/contrib/wagtailsearchpromotions/wagtail_hooks.py wagtail/contrib/wagtailstyleguide/wagtail_hooks.py wagtail/project_template/project_name/settings/base.py wagtail/project_template/project_name/urls.py wagtail/tests/non_root_urls.py wagtail/tests/settings.py wagtail/tests/snippets/models.py wagtail/tests/testapp/models.py wagtail/tests/testapp/wagtail_hooks.py wagtail/tests/urls.py wagtail/wagtaildocs/models.py wagtail/wagtaildocs/views/chooser.py wagtail/wagtaildocs/wagtail_hooks.py wagtail/wagtailembeds/wagtail_hooks.py wagtail/wagtailforms/models.py wagtail/wagtailforms/tests/test_views.py wagtail/wagtailforms/views.py wagtail/wagtailforms/wagtail_hooks.py wagtail/wagtailimages/models.py wagtail/wagtailimages/views/chooser.py wagtail/wagtailimages/wagtail_hooks.py wagtail/wagtailredirects/forms.py wagtail/wagtailredirects/wagtail_hooks.py wagtail/wagtailsites/forms.py wagtail/wagtailsites/views.py wagtail/wagtailsites/wagtail_hooks.py wagtail/wagtailsnippets/tests.py wagtail/wagtailsnippets/wagtail_hooks.py wagtail/wagtailusers/forms.py wagtail/wagtailusers/views/groups.py wagtail/wagtailusers/wagtail_hooks.py
2017-11-17 11:44:34 +01:00
To add this to the admin interface, use the :class:`~wagtail.admin.edit_handlers.InlinePanel` edit panel class:
2015-09-29 22:26:44 +02:00
.. code-block:: python
content_panels = [
...
InlinePanel('related_links', label="Related links"),
]
The first argument must match the value of the ``related_name`` attribute of the ``ParentalKey``.
2015-09-29 23:04:43 +02:00
Working with pages
==================
Wagtail uses Django's `multi-table inheritance <https://docs.djangoproject.com/en/stable/topics/db/models/#multi-table-inheritance>`_ feature to allow multiple page models to be used in the same tree.
2015-09-29 23:04:43 +02:00
Each page is added to both Wagtail's builtin :class:`~wagtail.core.models.Page` model as well as its user-defined model (such as the ``BlogPage`` model created earlier).
2015-09-29 23:04:43 +02:00
Pages can exist in Python code in two forms, an instance of ``Page`` or an instance of the page model.
When working with multiple page types together, you will typically use instances of Wagtail's :class:`~wagtail.core.models.Page` model, which don't give you access to any fields specific to their type.
2015-09-29 23:04:43 +02:00
.. code-block:: python
# Get all pages in the database
>>> from wagtail.core.models import Page
2015-09-29 23:04:43 +02:00
>>> Page.objects.all()
[<Page: Homepage>, <Page: About us>, <Page: Blog>, <Page: A Blog post>, <Page: Another Blog post>]
When working with a single page type, you can work with instances of the user-defined model. These give access to all the fields available in ``Page``, along with any user-defined fields for that type.
2015-09-29 23:04:43 +02:00
.. code-block:: python
# Get all blog entries in the database
>>> BlogPage.objects.all()
[<BlogPage: A Blog post>, <BlogPage: Another Blog post>]
You can convert a ``Page`` object to its more specific user-defined equivalent using the ``.specific`` property. This may cause an additional database lookup.
2015-09-29 23:04:43 +02:00
.. code-block:: python
>>> page = Page.objects.get(title="A Blog post")
>>> page
<Page: A Blog post>
2015-09-29 23:04:43 +02:00
# Note: the blog post is an instance of Page so we cannot access body, date or feed_image
2015-09-29 23:04:43 +02:00
>>> page.specific
<BlogPage: A Blog post>
2014-07-23 11:11:50 +02:00
2014-09-01 17:16:15 +02:00
Tips
2015-06-19 11:12:39 +02:00
====
2014-09-01 17:16:15 +02:00
Friendly model names
2015-09-21 15:44:31 +02:00
--------------------
2014-09-01 17:16:15 +02:00
2015-10-05 22:06:37 +02:00
You can make your model names more friendly to users of Wagtail by using Django's internal ``Meta`` class with a ``verbose_name``, e.g.:
2014-09-01 17:16:15 +02:00
.. code-block:: python
2014-09-01 17:16:15 +02:00
class HomePage(Page):
...
2014-09-01 17:31:41 +02:00
class Meta:
2015-09-23 10:52:26 +02:00
verbose_name = "homepage"
2014-09-01 17:16:15 +02:00
When users are given a choice of pages to create, the list of page types is generated by splitting your model names on each of their capital letters. Thus a ``HomePage`` model would be named "Home Page" which is a little clumsy. Defining ``verbose_name`` as in the example above would change this to read "Homepage", which is slightly more conventional.
Page QuerySet ordering
----------------------
``Page``-derived models *cannot* be given a default ordering by using the standard Django approach of adding an ``ordering`` attribute to the internal ``Meta`` class.
.. code-block:: python
class NewsItemPage(Page):
publication_date = models.DateField()
...
class Meta:
ordering = ('-publication_date', ) # will not work
This is because ``Page`` enforces ordering QuerySets by path. Instead, you must apply the ordering explicitly when constructing a QuerySet:
.. code-block:: python
news_items = NewsItemPage.objects.live().order_by('-publication_date')
.. _custom_page_managers:
Custom Page managers
--------------------
You can add a custom ``Manager`` to your ``Page`` class. Any custom Managers should inherit from :class:`wagtail.core.models.PageManager`:
.. code-block:: python
from django.db import models
from wagtail.core.models import Page, PageManager
class EventPageManager(PageManager):
""" Custom manager for Event pages """
class EventPage(Page):
start_date = models.DateField()
objects = EventPageManager()
Alternately, if you only need to add extra ``QuerySet`` methods, you can inherit from :class:`wagtail.core.models.PageQuerySet`, and call :func:`~django.db.models.managers.Manager.from_queryset` to build a custom ``Manager``:
.. code-block:: python
from django.db import models
from django.utils import timezone
from wagtail.core.models import Page, PageManager, PageQuerySet
class EventPageQuerySet(PageQuerySet):
def future(self):
today = timezone.localtime(timezone.now()).date()
return self.filter(start_date__gte=today)
EventPageManager = PageManager.from_queryset(EventPageQuerySet)
class EventPage(Page):
start_date = models.DateField()
objects = EventPageManager()