Доступ к свойствам модели подстраницы в файле шаблона Трясогузка

вот мой файл model.py

...

class LinkFields(models.Model):
    link_external = models.URLField(
        "External link",
        blank=True,
        null=True,
        help_text='Set an external link if you want to describe the event from an other web site',
    )
    link_page = models.ForeignKey(
        'wagtailcore.Page',
        null=True,
        on_delete=models.SET_NULL,
        blank=True,
        related_name='+',
        help_text='Choose an existing page (event must have already been created)',
    )

    @property
    def link(self):
        if self.link_page:
            return self.link_page.url
        else:
            return self.link_external

    panels = [
        FieldPanel('link_external'),
        PageChooserPanel('link_page'),
    ]

    class Meta:
        abstract = True

class RelatedLink(LinkFields):
    title = models.CharField(max_length=255, help_text="Link title")

    panels = [
        FieldPanel('title'),
        MultiFieldPanel(LinkFields.panels, "Link"),
    ]

    class Meta:
        abstract = True


class HomePage(Page):
    body = RichTextField(blank=True)

    content_panels = Page.content_panels + [
        FieldPanel('body', classname="full"),
        InlinePanel('related_links', label="Related events"),
    ]


class EventsPage(Page):

    # Database fields

    date = models.DateField("Event date")
    topicTag = models.CharField(max_length = 25)
    name = models.CharField(max_length = 50)
    city = models.CharField(max_length = 20, default="Where it is")
    place = models.CharField(max_length = 20, blank=True)
    body = RichTextField(blank=True)

    # Search index configuration

    search_fields = Page.search_fields + (
        index.SearchField('topicTag'),
        index.SearchField('place'),
        index.FilterField('date'),
    )

    # Editor panels configuration

    content_panels = Page.content_panels + [
        FieldPanel('date'),
        FieldPanel('topicTag'),
        FieldPanel('name', classname="title"),
        FieldPanel('city'),
        FieldPanel('place'),
        FieldPanel('body'),
    ]


class EventsRelatedLink(Orderable, RelatedLink):
    page = ParentalKey('HomePage', related_name='related_links')

EventsPages — это подстраницы HomePage, которые сами отображают ссылки на последующие подстраницы. Моя проблема заключается в том, что для каждой ссылки подстраницы, которую я показываю на главной странице, я хотел бы получить доступ к свойствам так называемой подстраницы, чтобы отобразить своего рода предварительный просмотр.

Вот мой шаблон home_page.html:

{% extends "base.html" %}

{% load wagtailcore_tags %}

{% block body_class %}template-homepage{% endblock %}

{% block content %}
   <h1>THE <span class="pink">OPEN SOURCE</span> INNOVATION SPRING</h1>

   <div class="intro">{{ page.body|richtext }}</div>

   {% if page.related_links.all %}
      <ul>
    {% for item in page.related_links.all %}
       <li><a href="{{ item.link }}">{{ item.title }}</a></li>
       <br><div class="description">{{ item.date }}
         <span class="pink">[{{ item.topicTag }}]</span>
          {{ item.name }} <span class="pink">[{{ item.city }}]</span>
       </div>
    {% endfor %}
      </ul>
   {% endif %}
{% endblock %}

и, конечно, все "item.*" с * в качестве свойств модели EventsPage не работает. Я совершенно уверен, что ошибаюсь, но, пожалуйста, мне нужна помощь, чтобы сделать это.


person LaMut    schedule 15.01.2016    source источник


Ответы (1)


Во-первых, {{ item.date }} не будет работать, потому что item — это объект RelatedLink, а не объект страницы. Чтобы получить доступ к объекту страницы, вам потребуется {{ item.link_page.date }} (и, конечно же, некоторое альтернативное поведение, когда редактор предоставил link_external вместо link_page). Однако этого изменения самого по себе будет недостаточно — оно будет работать для основных свойств страницы, таких как item.link_page.title, но не для конкретных событий, таких как date.

Объяснение того, почему это происходит: всякий раз, когда вы извлекаете набор страниц с помощью такой операции, как EventPage.objects.all(), или page.get_children(), или (в данном случае) page.related_links, обычно все результаты будут одного типа. Если это операция, которая потенциально может охватывать несколько различных типов страниц (например, EventPage.objects.all() может когда-либо возвращать только объекты EventPage, а page.get_children() или page.related_links могут возвращать страницы любого типа), то для того, чтобы сохранить их все одинаковыми, она должна вернуть их как «наименьший общий знаменатель» — базовую модель страницы, от которой происходят все типы страниц. Это обеспечивает такие поля, как title, которые являются общими для всех страниц, но не поля специального назначения.

(Это ограничение работы поиска в базе данных — если бы мы хотели получить каждый объект страницы в его наиболее конкретной форме, запрос к базе данных должен был бы проверять все таблицы, связанные со страницей, одновременно, что крайне неэффективно.)

Имея это в виду, у вас есть несколько вариантов:

Во-первых, если вы знаете, что редакторы на вашем сайте будут выбирать только EventPage в качестве связанных ссылок - и это кажется безопасным предположением, основанным на вашем help_text и факте, что вы пишете такие вещи, как {{ item.date }} и {{ item.city }}, которые вероятно, не имеет смысла для других типов страниц - тогда вы можете применить это на уровне базы данных, указав внешний ключ на EventPage:

link_page = models.ForeignKey(
    'myapp.EventPage',  # replace 'myapp' with your application name
    null=True,
    on_delete=models.SET_NULL,
    blank=True,
    related_name='+',
    help_text='Choose an existing page (event must have already been created)',
)

С этим изменением средство выбора страницы в администраторе трясогузки позволит вам выбрать только EventPages для этого поля, а item.link_page даст вам полные EventPage объекты, что позволит вам написать {{ item.link_page.date }}.

Во-вторых: если вам нужно поддерживать другие типы страниц в связанных ссылках — например, может быть, у вас есть модель NewsPage, которая также имеет поле date, и вы хотите иметь возможность выбирать их также как связанные ссылки — тогда вы можете преобразовать базовые Page в более конкретный тип страницы, вызвав на нем .specific. Например: {{ item.link_page.specific.date }}. Недостатком является то, что .specific будет выполнять дополнительный поиск в базе данных каждый раз, когда вы его используете, что может снизить производительность. В качестве простой оптимизации вы можете использовать тег {% with %}, чтобы присвоить его переменной:

{% for item in page.related_links.all %}
   {% with item.link_page.specific as related_page %}
      <li><a href="{{ item.link }}">{{ item.title }}</a></li>
      <br><div class="description">{{ related_page.date }}
        <span class="pink">[{{ related_page.topicTag }}]</span>
         {{ related_page.name }} <span class="pink">[{{ related_page.city }}]</span>
      </div>
   {% endwith %}
{% endfor %}
person gasman    schedule 16.01.2016
comment
это решило мою проблему, и вы заставили меня более точно понять, как это работает. Большое спасибо - person LaMut; 18.01.2016