Add 'Categories' section to tutorial

This demonstrates the use of snippets and many-to-many relations.
pull/3332/head
Matt Westcott 2017-02-01 21:58:43 +00:00
rodzic c63f6d7922
commit 37c7b696ef
2 zmienionych plików z 105 dodań i 2 usunięć

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 176 KiB

Wyświetl plik

@ -168,6 +168,7 @@ Lets start with a simple index page for our blog. In ``blog/models.py``:
from wagtail.wagtailcore.fields import RichTextField
from wagtail.wagtailadmin.edit_handlers import FieldPanel
class BlogIndexPage(Page):
intro = RichTextField(blank=True)
@ -269,7 +270,7 @@ Create a template at ``blog/templates/blog/blog_page.html``:
Note the use of Wagtail's built-in ``get_parent()`` method to obtain the
URL of the blog this post is a part of.
Now create a few blog posts as children of ``BlogIndexPage.``
Now create a few blog posts as children of ``BlogIndexPage``.
Be sure to select type "Blog Page" when creating your posts.
.. figure:: ../_static/images/tutorial/tutorial_4a.png
@ -302,7 +303,7 @@ Much of the work you'll be doing in Wagtail revolves around the concept of hiera
In this case, the ``BlogIndexPage`` is a "node" and individual ``BlogPage`` instances
are the "leaves".
Take another look at the guts of ``BlogIndexPage:``
Take another look at the guts of ``blog_index_page.html``:
.. code-block:: html+django
@ -707,6 +708,108 @@ something like this:
:alt: A simple tag view
Categories
~~~~~~~~~~
Let's add a category system to our blog. Unlike tags, where a page author can bring a tag into existence simply by using it on a page, our categories will be a fixed list, managed by the site owner through a separate area of the admin interface.
First, we define a ``BlogCategory`` model. A category is not a page in its own right, and so we define it as a standard Django ``models.Model`` rather than inheriting from ``Page``. Wagtail introduces the concept of "snippets" for reusable pieces of content that need to be managed through the admin interface, but do not exist as part of the page tree themselves; a model can be registered as a snippet by adding the ``@register_snippet`` decorator. All the field types we've used so far on pages can be used on snippets too - here we'll give each category an icon image as well as a name. Add to ``blog/models.py``:
.. code-block:: python
from wagtail.wagtailsnippets.models import register_snippet
@register_snippet
class BlogCategory(models.Model):
name = models.CharField(max_length=255)
icon = models.ForeignKey(
'wagtailimages.Image', null=True, blank=True,
on_delete=models.SET_NULL, related_name='+'
)
panels = [
FieldPanel('name'),
ImageChooserPanel('icon'),
]
def __str__(self):
return self.name
class Meta:
verbose_name_plural = 'blog categories'
.. note::
Note that we are using ``panels`` rather than ``content_panels`` here - since snippets generally have no need for fields such as slug or publish date, the editing interface for them is not split into separate 'content' / 'promote' / 'settings' tabs as standard, and so there is no need to distinguish between 'content panels' and 'promote panels'.
Migrate this change in, and create a few categories through the Snippets area which now appears in the admin menu.
We can now add categories to the ``BlogPage`` model, as a many-to-many field. The field type we use for this is ``ParentalManyToManyField`` - this is a variant of the standard Django ``ManyToManyField`` which ensures that the chosen objects are correctly stored against the page record in the revision history, in much the same way that ``ParentalKey`` replaces ``ForeignKey`` for one-to-many relations.
.. code-block:: python
# New imports added for forms and ParentalManyToManyField
from django import forms
from django.db import models
from modelcluster.fields import ParentalKey, ParentalManyToManyField
from modelcluster.tags import ClusterTaggableManager
from taggit.models import TaggedItemBase
# ...
class BlogPage(Page):
date = models.DateField("Post date")
intro = models.CharField(max_length=250)
body = RichTextField(blank=True)
tags = ClusterTaggableManager(through=BlogPageTag, blank=True)
categories = ParentalManyToManyField('blog.BlogCategory', blank=True)
# ... (Keep the main_image method and search_fields definition)
content_panels = Page.content_panels + [
MultiFieldPanel([
FieldPanel('date'),
FieldPanel('tags'),
FieldPanel('categories', widget=forms.CheckboxSelectMultiple),
], heading="Blog information"),
FieldPanel('intro'),
FieldPanel('body'),
InlinePanel('gallery_images', label="Gallery images"),
]
Here we're making use of the ``widget`` keyword argument on the ``FieldPanel`` definition to specify a checkbox-based widget instead of the default multiple select box, as this is often considered more user-friendly.
Finally, we can update the ``blog_page.html`` template to display the categories:
.. code-block:: html+django
<h1>{{ page.title }}</h1>
<p class="meta">{{ page.date }}</p>
{% with categories=page.categories.all %}
{% if categories %}
<h3>Posted in:</h3>
<ul>
{% for category in categories %}
<li style="display: inline">
{% image category.icon fill-32x32 style="vertical-align: middle" %}
{{ category.name }}
</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
.. figure:: ../_static/images/tutorial/tutorial_10.jpg
:alt: A blog post with categories
Where next
----------