The blog models provide the foundation for the bakery demo’s blogging functionality. These models include support for blog posts with authors, tags, StreamField content, and a routable index page with tag filtering.
A Blog Page model that represents individual blog posts.
Full Class Definition
class BlogPage(Page): """ A Blog Page We access the Person object with an inline panel that references the ParentalKey's related_name in BlogPersonRelationship. More docs: https://docs.wagtail.org/en/stable/topics/pages.html#inline-models """ introduction = models.TextField(help_text="Text to describe the page", blank=True) image = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", help_text="Landscape mode only; horizontal width between 1000px and 3000px.", ) body = StreamField( BaseStreamBlock(), verbose_name="Page body", blank=True, use_json_field=True ) subtitle = models.CharField(blank=True, max_length=255) tags = ClusterTaggableManager(through=BlogPageTag, blank=True) date_published = models.DateField("Date article published", blank=True, null=True)
def authors(self): """ Returns the BlogPage's related people. Again note that we are using the ParentalKey's related_name from the BlogPersonRelationship model to access these objects. This allows us to access the Person objects with a loop on the template. If we tried to access the blog_person_ relationship directly we'd print `blog.BlogPersonRelationship.None` """ # Only return authors that are not in draft return [ n.person for n in self.blog_person_relationship.filter( person__live=True ).select_related("person") ]
Returns a list of live Person objects associated with the blog post through the BlogPersonRelationship.
@propertydef get_tags(self): """ Similar to the authors function above we're returning all the tags that are related to the blog post into a list we can access on the template. We're additionally adding a URL to access BlogPage objects with that tag """ tags = self.tags.all() base_url = self.get_parent().url for tag in tags: tag.url = f"{base_url}tags/{tag.slug}/" return tags
Returns all tags with URLs for accessing filtered blog posts by tag.
Index page for blogs with routable tag filtering functionality.
Full Class Definition
class BlogIndexPage(RoutablePageMixin, Page): """ Index page for blogs. We need to alter the page model's context to return the child page objects, the BlogPage objects, so that it works as an index page RoutablePageMixin is used to allow for a custom sub-URL for the tag views defined above. """ introduction = models.TextField(help_text="Text to describe the page", blank=True) image = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", help_text="Landscape mode only; horizontal width between 1000px and 3000px.", )
Returns child BlogPage objects, optionally filtered by tag.
get_child_tags()
def get_child_tags(self): tags = [] for post in self.get_posts(): # Not tags.append() because we don't want a list of lists tags += post.get_tags tags = sorted(set(tags)) return tags
Returns a sorted list of all unique tags used by child blog posts.
Defines the many-to-many relationship between BlogPage and Person models.
Full Class Definition
class BlogPersonRelationship(Orderable, models.Model): """ This defines the relationship between the `Person` within the `base` app and the BlogPage below. This allows people to be added to a BlogPage. We have created a two way relationship between BlogPage and Person using the ParentalKey and ForeignKey """ page = ParentalKey( "BlogPage", related_name="blog_person_relationship", on_delete=models.CASCADE ) person = models.ForeignKey( "base.Person", related_name="person_blog_relationship", on_delete=models.CASCADE ) panels = [FieldPanel("person")] api_fields = [ APIField("page"), APIField("person"), ]
Tag model for creating many-to-many relationships between BlogPage and tags.
Full Class Definition
class BlogPageTag(TaggedItemBase): """ This model allows us to create a many-to-many relationship between the BlogPage object and tags. There's a longer guide on using it at https://docs.wagtail.org/en/stable/reference/pages/model_recipes.html#tagging """ content_object = ParentalKey( "BlogPage", related_name="tagged_items", on_delete=models.CASCADE )
# Get all blog posts ordered by publication datefrom bakerydemo.blog.models import BlogPageposts = BlogPage.objects.live().order_by('-date_published')# Get blog post authorsfor post in posts: authors = post.authors() for author in authors: print(f"{author.first_name} {author.last_name}")# Get all tags for a blog postpost = BlogPage.objects.first()tags = post.get_tagsfor tag in tags: print(f"{tag.name}: {tag.url}")