在 Django 循环模板中对第二个模型使用键值查找?

Posted

技术标签:

【中文标题】在 Django 循环模板中对第二个模型使用键值查找?【英文标题】:Use Key-Value Lookup for Second Model in Django Template For Loop? 【发布时间】:2019-07-25 22:58:32 【问题描述】:

我想找到一种方法,在 Django for 循环中使用键值查找来查找第二个模型。

This question 在模板中的字典键值循环上是正确的,但我使用的是两个规范化数据模型。有一个包含相关链接的“父”数据对象 (EventDetail) 和包含用户操作数据的特定日期信息的“子”数据对象 (DateEvent)。

我有一个模板标签link_if_exists,它被重复了很多次。 Django-debug-toolbar 告诉我这现在被重复了 76 次。这个“重复”消息本身就被重复了很多次。

这就是我现在拥有的:

app_extras.py

@register.filter()
def link_if_exists(title):
    """Return a link if it exists"""
    event_link = None
    try:
        event_link = EventDetail.objects.filter(title=title).values_list('link', flat=True)[0]
    except IndexError:
        pass

    if event_link != "":
        return event_link

    return False

模板.html

% load 'app_extras' %

% for item in child_date_items %
    % if item.title|link_if_exists %
        <a href="item.title|link_if_exists">item.title</a>
    % endif %
% endfor %

models.py

class DateEvent(models.Model)
    title = models.CharField(max_length=250)
    event_date = models.DateField(default=date.today)
    event_datetime = models.DateTimeField(auto_now=False)

class EventDetail(models.Model)
    title = models.CharField(max_length=250)
    link = models.URLField(max_length=200, default="", blank=True)

views.py

class ProblemView(TemplateView):
    template_name = "template.html"

    def get_context_data(self, **kwargs):
        context = super(ProblemView, self).get_context_data(**kwargs)
        date_today = utils.get_date_today()
        child_date_items = DateEvent.objects.filter(event_date=date_today)
        context['child_date_items'] = child_date_items
        return context

Django 调试工具栏输出

SELECT link FROM
table WHERE title='title'
...
| duplicated 74 times

我所追求的是这样的:

将“event_detail”添加到views.py

class NewView(TemplateView):
    template_name = "template.html"

    def get_context_data(self, **kwargs):
        context = super(NewView, self).get_context_data(**kwargs)
        date_today = utils.get_date_today()
        child_date_items = DateEvent.objects.filter(event_date=date_today)
        context['child_date_items'] = child_date_items
        event_detail = EventDetail.objects.all()
        context['event_detail'] = event_detail
        return context

在 Ideal_template.html 中查找标题作为获取“链接”值的关键

% for item in child_date_items %
    % if event_detail[item.title]['link'] %
        <a href="event_detail[item.title]['link']">item.title</a>
    % endfor %
% endfor %

我不知道这个功能是否存在,所以我愿意接受其他建议。我也愿意在views.py 中计算它并迭代模板中的一个公共对象。我知道我可以复制链接数据并在 DateEvent 模型中添加一个链接列,但这似乎很浪费,如果可能的话我想避免这种情况。这不是我需要这种类型逻辑的唯一字段,因此将所有内容添加到 Child 对象会占用数据库中的大量额外空间。

【问题讨论】:

为了后代,我添加了一个使用“模板片段缓存”的快速解决方法:docs.djangoproject.com/en/2.1/topics/cache/…。这对我很有帮助,但我可能确实需要在我的模型上做一些工作,正如@Endre Both 所指出的那样 【参考方案1】:

您需要对模型做一些工作。如果它们之间存在一对多的关系(几个DateEvents 对应一个EventDetail),那么与其手动复制title,然后手动再次链接它们,您应该将关系形式化为模型级别:

class EventDetail(models.Model)
    title = models.CharField(max_length=250)
    link = models.URLField(max_length=200, default="", blank=True)

class DateEvent(models.Model)
    event_detail = models.ForeignKey(EventDetail, on_delete=models.CASCADE)
    event_date = models.DateField(default=date.today)
    event_datetime = models.DateTimeField(auto_now=False)

然后您可以从任何DateEvent 对象引用link 字段,而无需任何条件和重复查询(如果您正确使用select_related())。

因此,如果您正在使用 DateEvents,您会使用:

date_events = (
    DateEvent.objects
        .filter(event_date=date_today)
        .select_related('event_detail')
)

然后,在模板中:

% for item in child_date_items %
    <a href="item.event_detail.link">item.event_detail.title</a>
% endfor %

【讨论】:

很好的答案。我在其他地方看到了“select_related”。但是我如何将您的答案与预期结果联系起来?我正在循环DateEvent 并希望在模板中包含来自EventDetail 的链接以及DateEvent 中的大多数数据。在我的模型上完成这项工作后,我该如何到达那里? 另外,您对这种方法的总体性能有什么想法,以及考虑规范化与非规范化吗? 在项目正常运行之前,我不会过多考虑性能。但一般来说,如果您明智地使用数据库查询,则不需要非规范化,因为它会给您带来新的问题需要处理,以换取您通常可以通过其他方式实现的性能提升。 太好了,也感谢您更新模板代码。

以上是关于在 Django 循环模板中对第二个模型使用键值查找?的主要内容,如果未能解决你的问题,请参考以下文章

您如何在 F# 或任何函数式语言中对第二个(或第三个、第四个、...)参数进行 curry?

循环模板的键值 - Django 查询

用于循环的 django 模板语言

django第二个项目--使用模板

C++ pair的基本用法

Django 添加第二个静态文件 URL