从 Django 模板中的特定相关对象查询数据
Posted
技术标签:
【中文标题】从 Django 模板中的特定相关对象查询数据【英文标题】:Querying data from a specific related object in Django template 【发布时间】:2011-06-22 03:07:43 【问题描述】:我正在尝试使用 Django 显示来自多个模型的信息表,但我不确定这样做的最佳实践是什么。这是我的 models.py 的精简版:
from django.contrib.auth.models import User
class Widget(models.Model):
name = models.CharField(max_length=50)
pass
class Finished_Widget(models.Model):
user = models.ForeignKey(User)
thing = models.ForeignKey(Thing)
created = models.DateTimeField(editable=False)
这是一个非常简单的设置,用户和小部件通过未知数量的 Finished_Widget 对象连接。我想在我的 html 中显示小部件名称的实例列表和最近完成的小部件的日期。显然下面的代码不起作用,但希望它能说明我希望输出的数据。
% for widget in widget_list %
<p> widget.name </p>
<p> widget__Finished_Widget.latest.created </p>
% endfor %
我想了很多不同的方法来解决这个问题,包括:
通过视图将所需日期作为附加属性附加 在视图中创建字典并在模板中调用它 ManyToManyField 使用 'through' 参数 向 Widget 添加 meta 调用最新 Finished_Widget 的创建日期很遗憾,我无法完成这些工作,我不确定哪些(如果有的话)是正确的。
注意:我已经在 SO 上发现了很多关于这个问题的变体,这使得这非常接近于欺骗,但它们似乎对我没有多大帮助,因为需要将 Finished_Widget 列表缩小到那些匹配用户 ID,匹配 Widget ID,并且只有最新的。
【问题讨论】:
【参考方案1】:根据传入user
对象的需要更新了答案。
在您看来,最简单的方法是处理这个问题,但它有它的问题。
for widget in widget_list:
widget.latest_finished_widget = widget.finished_widget_set.filter(user=request.user).latest('created')
% for widget in widget_list %
<p> widget.name </p>
<p> widget.latest_finished_widget </p>
% endfor %
虽然这段代码很容易编写,但每次迭代都要执行一次数据库查询。
一种快速的解决方案称为查询分区。使用 2 个查询和 python 尽可能高效地填充反向关系,而无需使用 SQL。
widgets = Widget.objects.filter(...)
finished_widget_map = dict(
[(x['thing__id'], x['created']) for x in
Finished_Widget.objects.filter(thing__in=widgets, user=request.user).values_list('thing__id', 'created').order_by('created')])
# this ensures we only select what we need, thing__id and the created column
# ordering by created will ensure only the last (latest) will appear in our dictionary
for widget in widgets:
widget.latest_finished_widget_created = finished_widget_map.get(widget.id, 'No Widget')
% for widget in widgets %
widget.name
widget.latest_finished_widget_created
% endfor %
不过,总会有取舍。如果有很多 Finished_Widgets python 无意义地试图填充字典,这可能会很慢。
【讨论】:
Yuji,我想你可能不小心强调了为什么我在这方面遇到了这么多麻烦。你能解释一下你从哪里得到'finished_widget_set'吗?看起来它可能是我找不到文档的 django 模板语法的某些方面?还是你假设我会在别处定义它? @IanWhalen,好问题!是的,django 自动生成方便的方法来“向后”检索关系docs.djangoproject.com/en/dev/topics/db/queries/…——默认情况下:fieldname_set。尽管如此,它仍然是低效的,因为您可能会想象每个小部件 1 个查询。当您有一个对象并想要所有 100 个相关对象时,它会更有用,而不是 100 个对象,每个对象都有 1 个您想要的相关对象。 PS:模板点表示法是严格基于python的,除了点表示法之外没有特殊的模板语法:)docs.djangoproject.com/en/dev/ref/templates/api/#render它执行python dict查找、attr查找、索引查找,然后默默地失败.所以如果有一个你不认识的点符号方法,它是一个 python dict key、attr 或 index! 嗨,Yuji,我不想“不回答”这个问题,但我意识到你给出的第一个建议存在相当大的问题。 'widget.finished_widget_set.latest' 部分将返回整个数据库中最新的finished_widget,而我需要它只显示当前经过身份验证的用户的最新版本。但是,我被阻止了,因为您无法在模板中传递参数,因此“widget.finished_widget_set(user=user).latest”将不起作用。这有意义吗? @IanWhalen:那么您将不得不通过您的视图在您的对象上设置一个属性(模型方法不应处理请求)。我强烈建议我指出的第二种方法,尽管如此!更新示例【参考方案2】:好吧,我认为这里没有足够的信息来完全回答您的问题,但是解决仅返回最新 Finished_Widget 问题的一个简单方法是向 User 模型添加一个名为“latest_widget”的方法:
class User(models.Model):
#...
def latest_widget(self):
return self.widgets.all().order_by('-created')[0]
从技术上讲,您可以将其添加到 Finished_Widget 模型中,尽管它没有多大意义。如果您使用 Django 的 auth 模块中的 User 模型,您可能希望对模型进行子类化以添加此功能。
一旦你有了这个方法,从模板中调用它就很简单了。如果您有一个用户列表,例如名为 user_list,您可以像这样显示每个用户和他/她的最新小部件:
% for uu in user_list %
<p>
uu.username: uu.latest_widget.name
</p>
% endfor %
【讨论】:
对不起,如果我不够清楚,沃尔特,但我将遍历小部件列表,而不是用户,我将寻求从最新访问“创建”字段Finished_Widget 对象,不是最新的 Widget 对象。 他似乎正在迭代widget_list
,这可能是Widget
实例——所以它必须进入那里。无论如何,您的想法都有效:) 编辑:浏览器刷新失败
啊,是的,我现在明白了。好吧,对我来说,制定解决方案最有帮助的是查看一些示例数据(因为它存在于您的模型和数据库中)以及它应该如何显示在页面上。以上是关于从 Django 模板中的特定相关对象查询数据的主要内容,如果未能解决你的问题,请参考以下文章
如何获取与传递给 Django 模板的查询集相关的查询集对象
用于从相关查询中列出所有 ForeignKey 对象的 Django 查询