查询Django模板中特定相关对象的数据

时间:2011-02-06 03:15:29

标签: python django django-models

我正在尝试使用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)

这是一个非常简单的设置,用户和Widget通过未知数量的Finished_Widget对象连接。我想在html中显示的是Widget名称的实例列表和最近完成的小部件的日期。显然下面的代码不起作用,但希望它能说明我想要输出的数据。

{% for widget in widget_list %}
<p>{{ widget.name }}</p>
<p>{{ widget__Finished_Widget.latest.created }}</p>
{% endfor %}

我已经考虑过这个问题的许多不同方法,包括:

  • 通过视图附加所需日期作为附加属性
  • 在视图中创建字典并在模板中调用该字典
  • ManyToManyField使用'through'参数
  • 将W添加到Widget,调用最新Finished_Widget的创建日期

不幸的是,我无法完成任何这些工作,而且我不确定哪条甚至是正确的道路。

注意:我已经在SO上发现了很多关于这个问题的变化,这使得它非常接近欺骗,但它们似乎没有帮助我很多,因为需要缩小Finished_Widget列表到与用户ID匹配的用户ID,与Widget ID匹配,仅匹配最新的。

2 个答案:

答案 0 :(得分:2)

根据传递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 %}

虽然这段代码很容易编写,但每次迭代都会执行db查询。

一种快速解决方案称为查询分区。使用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毫无意义地试图填充dict,那么这可能会很慢。

答案 1 :(得分:0)

嗯,我认为这里没有足够的信息来完全回答你的问题,但是只返回最近的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 %}