Accueil / Blog / Métier / 2016 / Wagtail : How to make your own content type models (part 1)

Wagtail : How to make your own content type models (part 1)

Par Yann Fouillat — publié 29/07/2016
We are used to initialize our CMS directly from a web interface, often including lots of complex panels. Wagtail prefers to use the Django philosophy and offers us to define our content type as models instead.
Wagtail : How to make your own content type models (part 1)

Wagtail

Knowledge of Django base principles is required to understand this post properly. If this is not your case, I advise you to read the introduction from the official documentation.

Wagtail Initialization

The initialization of a Wagtail website is very similar to a Django one: making its virtual environnment, install Wagtail, then use the wagtail command. You then just have to make the database and create a super user account:

$ mkvirtualenv my_wagtail
$ pip install wagtail
$ wagtail start my_wagtail
$ cd my_wagtail
$ python manage.py migrate
$ python manage.py createsuperuser

We have two apps by default: home and search. home contains a content type whereas search define a view allowing searches.

Fields

Every content type is actually a Django model inheriting from the Page model. This model already has some field by default (such as a title, a slug, ...). The default fields list is in the documentation.

The fields used are the ones from Django (CharField, DateTimeField, ...), plus some from Wagtail: RichTextField, used to write rich text (with a WYSIWYG), and StreamField, that we will see further along this post. Let's make our first content type by modifying HomePage:

class HomePage(Page):
    subtitle = models.CharField(max_length=255)
    intro = RichTextField()
    image = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )

An image field is a simple ForeignKey to the wagtailimages.Image model. It is possible to link to a document using the same method by using the wagtaildocs.Document model.

StreamField

A StreamField is a particular field allowing mixing other type of field in an organized way. A presentation is available on Youtube. Let's see how to make a StreamField:

class HomePage(Page):
    [...]
    body = StreamField([
        ('title', blocks.CharBlock(classname="full title")),
        ('paragraph', blocks.RichTextBlock()),
        ('image', ImageChooserBlock()),
    ])

A StreamField is a list of blocks. The complete list of blocks is available in the documentation.

Good, now that we have the fields of our content type defined, we just have to choose how to show them in the edit view.

Panels

/blog/metier/2016/images-presentation-wagtail/panels

Wagtail has several panel by default to organize the fields. content_panels for the content itself, promote_panels for metadata and settings_panels for the settings:

class HomePage(Page):
    # [...]

    content_panels = Page.content_panels + [
        FieldPanel('subtitle'),
        ImageChooserPanel('image'),
        FieldPanel('intro', classname="full"),
        StreamFieldPanel('body')
    ]

A panel is a list of FieldPanels. There are several types.

FieldPanel

FieldPanel for every basic field. FieldPanel have the optional parameter classname to add a CSS class to the field. Wagtail has several classes available:

  • title.
  • full, giving the input the full size of its container.
  • col1 to col12, telling the size the input will be.
/blog/metier/2016/images-presentation-wagtail/field-row-panel

StreamFieldPanel

StreamFieldPanel for StreamField fields :

/blog/metier/2016/images-presentation-wagtail/stream-field-panel

ChooserPanel

The ChooserPanel to select already existing objects. There are four different one: PageChooserPanel, ImageChooserPanel, DocumentChooserPanel or SnippetChooserPanel :

/blog/metier/2016/images-presentation-wagtail/image-chooser-panel

How to structure fields

There are three types of FieldPanel just to structure fields:

MultiFieldPanel

MultiFieldPanel is used to group fields together. An accordion can be made by adding collapsible as a class name. collapsed can be added to have it collapsed by default.

content_panels = Page.content_panels + [
    MultiFieldPanel([
            FieldPanel('subtitle'),
            ImageChooserPanel('image'),
        ],
        heading="Un MultiFieldPanel",
        classname="collapsible collapsed",
    ),
    FieldPanel('intro', classname="full"),
    StreamFieldPanel('body')
]
/blog/metier/2016/images-presentation-wagtail/multi-field-panel

FieldRowPanel

FieldRowPanel is used to have several fields on the same line. It is important to precise classname with the size of the columns in order for the fields to display correctly:

content_panels = Page.content_panels + [
    FieldRowPanel([
        FieldPanel('subtitle', classname="col6"),
        FieldPanel('intro', classname="col6"),
    ]),
    ImageChooserPanel('image'),
    StreamFieldPanel('body')
]
/blog/metier/2016/images-presentation-wagtail/field-row-panel

InlinePanel

InlinePanel is used to handle another model, and is specifically used to make a multiple field.

InlinePanels use a specific model: Orderable (Documentation):

class HomePage(Page):
    [...]

    content_panels = Page.content_panels + [
        [...]
        InlinePanel('links', label="Liens")
    ]

class HomePageLien(Orderable):
    page = ParentalKey(HomePage, related_name='links')
    name = models.CharField(max_length=255)
    url = models.URLField()

    panels = [
        FieldPanel('name'),
        FieldPanel('url'),
    ]
/blog/metier/2016/images-presentation-wagtail/inline-panel

ParentalKey is just a ForeignKey used for django-modelcluster (for more information, see the documentation)

Just like every other Django model, we first have to make and run the migrations:

$ python manage.py makemigrations
$ python manage.py migrate

Don't hesitate to read the documentation to go further.

We now can create our first contents. But there is still a last thing to understand.

Hierarchy

Wagtail organizes contents as a tree view. Just like every tree, there is a root page by default for every site (yes, Wagtail is multisite). To this root page, we usually tie up a child page of homepage type. This is the first level. Then, from this homepage, we will have child pages of list type (the second level), and then the detail pages. As an example, we will consider that our homepage will contain a blog page which will list the blog post in preview mode. To do this, this page only accepts blog post type page as children. We can also define that the only parent page type possible in the blog post is the blog index. In order to do that, Wagtail has two attributes we can define on our page models: parent_page_types and subpage_types (Documentation).

For our homepage, we will thus create another model BlogIndex which will only accept blog post type as children:

class BlogIndex(Page):
    [...]
    subpage_types = ['app.BlogPage']

And we will add another model, BlogPage, which will only allow a page of type BlogIndex as a parent, and which will not be able to have children:

class BlogPage(Page):
    [...]
    parent_page_types = ['app.BlogIndex']
    subpage_types = []

Conclusion

You now have every tools to do your own Pages. We will see in the next post how to use this model and its manager.

ABONNEZ-VOUS À LA NEWSLETTER !
Voir aussi
Internationalisation avec Django Internationalisation avec Django 27/11/2018

En tant que développeurs nous sommes parfois confronté à la problématique de l'accessibilité ...

Python : Bien configurer son environnement de développement Python : Bien configurer son environnement de développement 07/12/2015

Comment utiliser les bonnes pratiques de développement Python.

Formation Django initiation à Toulouse du 13 au 15 mars Formation Django initiation à Toulouse du 13 au 15 mars 26/01/2017

Entrez de plain-pied dans l'univers de Django aux côtés de développeurs ayant une expérience de ...

Retour sur la PyConFr 2016 Retour sur la PyConFr 2016 18/10/2016

Nous étions présents à Rennes pour PyConFr 2016. Voici notre compte-rendu à chaud.

Wagtail: How to use the Page model and its manager (part 2) Wagtail: How to use the Page model and its manager (part 2) 08/08/2016

The Page model has several methods specific to Wagtail. This is also the case of its manager. We ...