Wagtail 通用画廊实现和 OneToOneField

Wagtail generic gallery implementation and OneToOneField

http://docs.wagtail.io/en/v1.13.1/getting_started/tutorial.html

wagtail getting_started 教程引入了博客画廊功能,实现如下:

class BlogPage(Page):
    ...

class BlogPageGalleryImage(Orderable)
    page = ParentalKey(BlogPage, related_name='gallery_images')
    image = ...

这种方式可行,但是 BlogPageGalleryImage 与 BlogPage 模型相结合。我的目的是制作一个可以嵌入任何模型(页面)的通用画廊模型。这个想法是使用中间画廊模型:

class BlogPage(Page):
    gallery = models.OneToOneField(Gallery, on_delete=models.SET_NULL, null=True)
    ...

class Gallery(Page):
    pass

class GalleryImage(Orderable):
    gallery = ParentalKey(Gallery, related_name='images')

然后在代码中,我们可以通过blog.gallery.images获取图片。

我的问题是如何让它与 wagtail 管理界面一起工作,以便在编辑博客页面对象时内联 create/edit 图库对象 (OneToOneField)。

一种方法是通过更通用的页面图像连接关系,将其与页面模型相关联,而不是特定的 BlogPage 模型。

这意味着任何页面都可以有图库图片,您只需要通过 InlinePanel.

将该字段公开给内容面板

您还可以创建一个 Mixin class 来提供一些有用的方法,而无需每次都重写它们。

这是一个例子:

from django.db import models

from wagtail.admin.edit_handlers import InlinePanel
from wagtail.core.models import Orderable, Page
from wagtail.images.edit_handlers import ImageChooserPanel

class ImageGalleryRelationship(Orderable, models.Model):
    """ Relationship between any `Page` and `Image` for an image gallery."""
    page = ParentalKey(Page, related_name='gallery_page')
    image = models.ForeignKey('wagtailimages.Image', related_name='gallery_image')
    panels = [ImageChooserPanel('image')]


class PageGalleryMixin():
    def gallery_images(self):
        images = [g.image for g in self.gallery_page.all()]
        return images

class BlogPage(Page, PageGalleryMixin):
    # all page fields, gallery does not need to be defined here
    content_panels = Page.content_panels + [
        InlinePanel('gallery_page', label='Image Gallery'),
        #...
    ]

注意:这不是OneToOne连接,InlinePanel需要ParentalKey关系。此解决方案中没有真正的 'Gallery' 模型,只有一组可排序关系。

在一般应用程序(或任何地方)中,models.py

class PageGalleryImage(Orderable):
    page = ParentalKey(Page,
                       on_delete=models.CASCADE,
                       related_name='image_gallery')
    image = models.ForeignKey('wagtailimages.Image',
                              on_delete=models.CASCADE,
                              related_name='page_gallery_image')
    caption = models.CharField(blank=True, max_length=250)

    panels = [
        ImageChooserPanel('image'),
        FieldPanel('caption'),
    ]

博客等其他应用,models.py:

class BlogPage(Page):
    content_panels = Page.content_panels + [
        ...
        InlinePanel('image_gallery', label="Gallery images"),
    ]

这提供了一个应用程序 = 一个图库。