You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Wagtail技术问询:能否在Orderable内部嵌套另一个Orderable?

Absolutely! Nesting Orderable models within an InlinePanel is totally doable in Wagtail—this is exactly the kind of structured content workflow the framework was built to support. Let’s tweak your code to make each card hold 1-10 PDFs, while keeping your 0-20 card limit intact.

Step 1: Update Your Models

We’ll restructure your models to create a parent-child relationship:

  • The main ArchitectPage (mostly unchanged)
  • A parent Orderable for each card (acts as the container)
  • A child Orderable for individual PDF items linked to each card

Here’s the revised code:

from wagtail.models import Page, Orderable
from wagtail.admin.panels import MultiFieldPanel, InlinePanel, ImageChooserPanel, FieldPanel, DocumentChooserPanel
from wagtail.documents.models import Document
from wagtail.images.models import Image
from django.db import models

class ArchitectPage(Page):
    search_fields = Page.search_fields + [] 

    content_panels = Page.content_panels + [
        MultiFieldPanel(
            # Manages the top-level cards (0-20 total)
            [InlinePanel('architect_cards', max_num=20, min_num=0, label="Architect Document Card")],
            heading="Architect PDF Cards"
        ),
    ]

    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading='Content'),
        ObjectList(Page.promote_panels, heading='SEO'),
        ObjectList(Page.settings_panels, heading='Settings', classname='settings'),
    ])

# Parent Orderable: Represents a single display card
class ArchitectDownloadCard(Orderable):
    page = ParentalKey(ArchitectPage, on_delete=models.CASCADE, related_name='architect_cards')
    image = models.ForeignKey(
        'wagtailimages.Image', null=True, blank=True, on_delete=models.CASCADE, related_name='+'
    )
    caption = models.CharField(blank=True, max_length=250)

    panels = [
        ImageChooserPanel('image'),
        FieldPanel('caption'),
        # Nested inline panel for PDFs (1-10 per card)
        InlinePanel('card_pdfs', max_num=10, min_num=1, label="PDF File"),
    ]

# Child Orderable: Represents a single PDF linked to a card
class ArchitectPdfItem(Orderable):
    card = ParentalKey(ArchitectDownloadCard, on_delete=models.CASCADE, related_name='card_pdfs')
    pdf_document = models.ForeignKey(
        'wagtaildocs.Document', null=True, blank=False, on_delete=models.SET_NULL, related_name='+'
    )
    pdf_label = models.CharField(blank=True, max_length=100, help_text="Optional label (e.g., 'Updated 2024' or 'Version 2')")

    panels = [
        DocumentChooserPanel('pdf_document'),
        FieldPanel('pdf_label'),
    ]

Key Model Changes:

  • Renamed your original ArchitectDownloads to ArchitectDownloadCard to better reflect its role as a container
  • Added ArchitectPdfItem as the child Orderable to handle individual PDFs per card
  • Set min_num=1 on the nested InlinePanel to enforce at least one PDF per card (adjust this if you need more flexibility)
  • Added an optional pdf_label field to help editors distinguish multiple PDFs on the same card

Step 2: Update Your Template

Now we’ll loop through the cards first, then iterate over each PDF inside its parent card. Here’s the adjusted template:

{% for card in page.architect_cards.all %}
<div class="document line-up-card">
    <div class="w3-card-4 w3-margin w3-white" data-aos="fade-down">
        {% image card.image fill-150x150-c100 %}
        <div class="w3-container">
            <p>{{ card.caption }}</p>
        </div>
        <hr>
        <!-- Loop through all PDFs for this card -->
        {% for pdf_item in card.card_pdfs.all %}
        <div class="download">
            <a href="{{ pdf_item.pdf_document.url }}" class="smooth-over-button noDecoration">
                <i class="fa fa-download"></i>
                <p class="btn-txt">
                    <!-- Show custom label if set, else use the document title -->
                    {% if pdf_item.pdf_label %}
                        {{ pdf_item.pdf_label }}
                    {% else %}
                        {{ pdf_item.pdf_document.title }}
                    {% endif %}
                </p>
            </a>
        </div>
        {% endfor %}
    </div>
</div>
{% endfor %}

Template Improvements:

  • Outer loop targets the top-level cards (architect_cards)
  • Inner loop pulls all PDFs linked to the current card (card_pdfs)
  • Added fallback logic to display the document title if no custom label is provided
  • Cleaned up the structure to group all PDFs under their parent card

Critical Post-Change Step

Don’t forget to run database migrations to apply these model changes:

python manage.py makemigrations
python manage.py migrate

This will update your database schema to support the new parent-child relationship between cards and PDFs.

内容的提问来源于stack exchange,提问作者Joelad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 13:37:28