在 Wagtail 中获取另一个页面的密码保护版本的数据

Obtaining another page's data for a password-protected version in Wagtail

我是 Python 和 Wagtail 的新手。我已经掌握了我正在处理的 Wagtail 网站的大部分内容,但我被困在一个问题上。

该站点将显示一组零售产品(工厂)(完成和工作)和同一组贸易产品(仅显示贸易价格)。我有 PlantIndexPagePlantPage Wagtail 模型,后者有各种产品字段和两个价格字段。

交易价格信息应使用 Wagtail's 'page privacy' 密码选项进行密码保护,因此我认为我需要一个单独的索引页面 (TradePlantIndexPage),我可以在其中应用此页面隐私设置Wagtail 管理员,有效包含其自己的 public PlantPage 产品页面的交易版本。

所以我有很多 PlantPage 页(每个植物产品一个),一个 TradePlantPage 页使用 RoutablePageMixin@route 接受任何 PlantPage 产品的弹头。

# working: /plants/
class PlantIndexPage(Page):
    def get_context(self, request):
        context = super().get_context(request)
        context['plants'] = Page.objects.exact_type(PlantPage).live().all().order_by('title')
        return context

# working, password protected: /trade/
class TradePlantIndexPage(PlantIndexPage):
    template = 'plants/plant_index_page.html'  # for PlantIndexPage and TradePlantIndexPage

    def get_context(self, request):
        context = super().get_context(request)
        context['trade'] = True  # condition in template depends on this to show trade prices
        return context

# working: /plants/<plant_page_slug>
class PlantPage(Page):
    price_retail = models.DecimalField(...)
    price_trade = models.DecimalField(...)
    # ...

# not yet working: /trade/plant/<plant_page_slug>
class TradePlantPage(RoutablePageMixin, PlantPage):
    parent_page_types = ['TradePlantIndexPage']
    subpage_types = []

    template = 'plants/plant_page.html'  # for PlantPage and TradePlantPage

    def get_context(self, request):
        context = super().get_context(request)
        context['trade'] = True  # condition in template depends on this to show trade price
        context['plant'] = Page.objects.page(???).live()  # how to get PlantPage by slug?
        return context

    @route(r'^([-\w]+)/$')
    def trade(self, request, plant_slug):
        self.trade = True
        # how to render TradePlantPage with PlantPage content based on plant_slug?

我会将 TradePlantIndexPage 的植物列表 link 发送到 URL,其中 TradePlantPage 可用(/trade/plant/<plant_page_slug>)而不是PlantPage (/plants/<plant_page_slug>).

为了显示带有 TradePlantPage 的特定植物,我如何根据 trade @routeplant_slug 获得 PlantPage 的正确实例,并设置上下文,以便使用 page 变量的 PlantPage 模板有效?

我在代码中附加了与此相关的 comments/questions。谢谢


更新

感谢 gasman 友好且易于理解的回答,TradePlantPage 的贸易路线现在可以正常使用。按照该答案的建议使用 plant 而不是 page,我已将 PlantPage 的上下文方法更新为:

    def get_context(self, request):
        context = super().get_context(request)
        context['trade'] = False
        context['plant'] = context['page']
        return context

这是可行的,但我想知道 context['plant'] = context['page'] 是否是能够在共享模板中使用 plant 而不是 page 的次优方式。例如,我想它会使用于字段数据的内存加倍?无论如何,对于这个小网站来说可能不是问题,除非我听到其他消息,否则我会使用它。

RoutablePageMixin 路由方法中,返回 HTTP 响应的过程与普通 Django 视图函数的工作方式相同 - 请参阅 Django's 'Views and templates' tutorial。不使用页面的 template 属性 和 get_context 方法,除非您明确地将它们连接起来(为了简单起见,我建议不要这样做,并设置模板和直接在方法中的上下文变量)。

您的路由方法需要执行以下操作:

  • 根据 plant_slug 检索正确的 PlantPage - 我们将为此使用 Django 的 get_object_or_404 助手
  • 呈现模板 plants/plant_page.html,向其传递上下文变量 trade(设置为 True)、plant(设置为检索到的 PlantPage)和 page(设置到当前页面,即 TradePlantPage 对象)。

这给了我们代码:

from django.shortcuts import get_object_or_404, render

class TradePlantPage(RoutablePageMixin, PlantPage):
    parent_page_types = ['TradePlantIndexPage']
    subpage_types = []

    @route(r'^([-\w]+)/$')
    def trade(self, request, plant_slug):
        plant = get_object_or_404(PlantPage, slug=plant_slug)

        return render(request, 'plants/plant_page.html', {
            'trade': True,
            'plant': plant,
            'page': self,
        })

注意:这里我假设您的 plant_page.html 模板设置为在从 PlantPageTradePlantPage 调用时期望变量 plant - 例如您使用 {{ plant.title }} 而不是 {{ page.title }} 来输出植物名称。如果不是这种情况,通过在上面的代码中设置 'page': plant,,将 PlantPage 对象作为 page 传递可能没问题。但是,我建议让模板访问当前呈现的 'real' 页面对象是个好主意 - 例如,这样您就可以在站点导航中突出显示正确的项目。