kopia lustrzana https://github.com/wagtail/wagtail
130 wiersze
4.5 KiB
Markdown
130 wiersze
4.5 KiB
Markdown
(wagtailsnippets_rendering)=
|
|
|
|
# Rendering snippets
|
|
|
|
As Django models, snippets can be rendered in Django templates using a custom template tag. Alternatively, they can also be included as part of a Wagtail page's rendering process.
|
|
|
|
## Including snippets in template tags
|
|
|
|
The simplest way to make your snippets available to templates is with a template tag. This is mostly done with vanilla Django, so perhaps reviewing Django's documentation for [custom template tags](django:howto/custom-template-tags) will be more helpful. We'll go over the basics, though, and point out any considerations to make for Wagtail.
|
|
|
|
First, add a new Python file to a `templatetags` folder within your app - for example, `myproject/demo/templatetags/demo_tags.py`. We'll need to load some Django modules and our app's models, and ready the `register` decorator:
|
|
|
|
```python
|
|
from django import template
|
|
from demo.models import Advert
|
|
|
|
register = template.Library()
|
|
|
|
# ...
|
|
|
|
# Advert snippets
|
|
@register.inclusion_tag('demo/tags/adverts.html', takes_context=True)
|
|
def adverts(context):
|
|
return {
|
|
'adverts': Advert.objects.all(),
|
|
'request': context['request'],
|
|
}
|
|
```
|
|
|
|
`@register.inclusion_tag()` takes two variables: a template and a boolean on whether that template should be passed a request context. It's a good idea to include request contexts in your custom template tags, since some Wagtail-specific template tags like `pageurl` need the context to work properly. The template tag function could take arguments and filter the adverts to return a specific instance of the model, but for brevity, we'll just use `Advert.objects.all()`.
|
|
|
|
Here's what's in the template used by this template tag:
|
|
|
|
```html+django
|
|
{% for advert in adverts %}
|
|
<p>
|
|
<a href="{{ advert.url }}">
|
|
{{ advert.text }}
|
|
</a>
|
|
</p>
|
|
{% endfor %}
|
|
```
|
|
|
|
Then, in your own page templates, you can include your snippet template tag with:
|
|
|
|
```html+django
|
|
{% load wagtailcore_tags demo_tags %}
|
|
|
|
...
|
|
|
|
{% block content %}
|
|
|
|
...
|
|
|
|
{% adverts %}
|
|
|
|
{% endblock %}
|
|
```
|
|
|
|
## Binding pages to snippets
|
|
|
|
In the above example, the list of adverts is a fixed list that is displayed via the custom template tag independent of any other content on the page. This might be what you want for a common panel in a sidebar, but, in another scenario, you might wish to display just one specific instance of a snippet on a particular page. This can be accomplished by defining a foreign key to the snippet model within your page model and adding a {class}`~wagtail.admin.panels.FieldPanel` to the page's `content_panels` list. For example, if you wanted to display a specific advert on a `BookPage` instance:
|
|
|
|
```python
|
|
# ...
|
|
class BookPage(Page):
|
|
advert = models.ForeignKey(
|
|
'demo.Advert',
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL,
|
|
related_name='+'
|
|
)
|
|
|
|
content_panels = Page.content_panels + [
|
|
FieldPanel('advert'),
|
|
# ...
|
|
]
|
|
```
|
|
|
|
The snippet could then be accessed within your template as `page.advert`.
|
|
|
|
To attach multiple adverts to a page, the `FieldPanel` can be placed on an inline child object of `BookPage` rather than on `BookPage` itself. Here, this child model is named `BookPageAdvertPlacement` (so-called because there is one such object for each time that an advert is placed on a BookPage):
|
|
|
|
```python
|
|
from django.db import models
|
|
|
|
from wagtail.models import Page, Orderable
|
|
|
|
from modelcluster.fields import ParentalKey
|
|
|
|
# ...
|
|
|
|
class BookPageAdvertPlacement(Orderable, models.Model):
|
|
page = ParentalKey('demo.BookPage', on_delete=models.CASCADE, related_name='advert_placements')
|
|
advert = models.ForeignKey('demo.Advert', on_delete=models.CASCADE, related_name='+')
|
|
|
|
class Meta(Orderable.Meta):
|
|
verbose_name = "advert placement"
|
|
verbose_name_plural = "advert placements"
|
|
|
|
panels = [
|
|
FieldPanel('advert'),
|
|
]
|
|
|
|
def __str__(self):
|
|
return self.page.title + " -> " + self.advert.text
|
|
|
|
|
|
class BookPage(Page):
|
|
# ...
|
|
|
|
content_panels = Page.content_panels + [
|
|
InlinePanel('advert_placements', label="Adverts"),
|
|
# ...
|
|
]
|
|
```
|
|
|
|
These child objects are now accessible through the page's `advert_placements` property, and from there we can access the linked `Advert` snippet as `advert`. In the template for `BookPage`, we could include the following:
|
|
|
|
```html+django
|
|
{% for advert_placement in page.advert_placements.all %}
|
|
<p>
|
|
<a href="{{ advert_placement.advert.url }}">
|
|
{{ advert_placement.advert.text }}
|
|
</a>
|
|
</p>
|
|
{% endfor %}
|
|
```
|