Last active
May 9, 2023 17:49
-
-
Save alexgleason/09b1802b004babd74e96 to your computer and use it in GitHub Desktop.
Many to many relationships in Wagtail
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.db import models | |
from wagtail.wagtailsnippets.models import register_snippet | |
from wagtail.wagtailcore.models import Page | |
from modelcluster.fields import ParentalKey | |
from wagtail.wagtailadmin.edit_handlers import InlinePanel | |
@register_snippet | |
class Category(models.Model): | |
""" | |
There can be many categories related to many posts. | |
""" | |
title = models.CharField(max_length=255) | |
class Post(Page): | |
""" | |
There can be many posts related to many categories. | |
""" | |
# Categories come from a different table, but it's useful to have | |
# a way to retrieve them easily in the correct format. | |
@property | |
def categories(self): | |
categories = [ | |
# Grabs rows from the relationship index and formats them correctly. | |
# See the `PostCategoryRelationship` class below. | |
n.category for n in self.post_category_relationship.all() | |
] | |
return categories | |
# Only inline panels work here. | |
content_panels = Page.content_panels + [ | |
# This name comes from the "related_name" field explained below. | |
InlinePanel('post_category_relationship') | |
] | |
class PostCategoryRelationship(models.Model): | |
""" | |
An index of references between posts and categories. | |
This is where the relationship is defined. | |
Ex. a post with three categories will create three rows in this table. | |
For instance, a post titled "Bitcoin is dead" in the categories | |
"tech", "finance", and "life" will create the following rows: | |
row = 1 | |
post = "Bitcoin is dead" | |
category = "tech" | |
row = 2 | |
post = "Bitcoin is dead" | |
category = "finance" | |
row = 3 | |
post = "Bitcoin is dead" | |
category = "life" | |
""" | |
# The post this relationship is for. | |
# ParentalKey is just like ForeignKey, but needed for Wagtail's "preview" | |
# function to work. More: https://github.com/torchbox/django-modelcluster | |
post = ParentalKey( | |
'Post', | |
related_name='post_category_relationship' | |
) | |
# The "related name" allows us to grab rows from this table with a post. | |
# It creates a new property on all posts that you can access like so: | |
# | |
# my_post.post_category_relationship | |
# The category related to this post | |
category = models.ForeignKey( | |
'Category', | |
related_name="+" | |
) | |
panels = [ | |
FieldPanel('category') | |
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.db import models | |
from wagtail.wagtailsnippets.models import register_snippet | |
from wagtail.wagtailcore.models import Page | |
from modelcluster.fields import ParentalKey | |
from wagtail.wagtailadmin.edit_handlers import InlinePanel | |
@register_snippet | |
class Category(models.Model): | |
title = models.CharField(max_length=255) | |
class Post(Page): | |
@property | |
def categories(self): | |
categories = [ | |
n.category for n in self.post_category_relationship.all() | |
] | |
return categories | |
content_panels = Page.content_panels + [ | |
InlinePanel('post_category_relationship') | |
] | |
class PostCategoryRelationship(models.Model): | |
post = ParentalKey( | |
'Post', | |
related_name='post_category_relationship' | |
) | |
category = models.ForeignKey( | |
'Category', | |
related_name="+" | |
) | |
panels = [ | |
FieldPanel('category') | |
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{% if page.categories %} | |
<ul class="categories"> | |
{% for category in page.categories %} | |
<li>{{ category.title }}</li> | |
{% endfor %} | |
</ul> | |
{% endif %} |
This gist is from around 5 years ago. I think Wagtail now has native support for Django's ManyToMany field.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you for sharing this, but isn't this an one to many relationship? How can we reference it from Category?