【问题标题】:Display Multiple Queryset in List View在列表视图中显示多个查询集
【发布时间】:2018-07-30 01:19:06
【问题描述】:

我正在尝试将具有多个模型的多个查询集显示为时间线,并按时间对它们进行排序,而不是在另一个之后显示一个查询集,我当前的代码如下所示:

<div class="user-info col-md-8">
{% for obj in user.marks_set.all %}
                     <p>{{ obj.module }}</p> 
                      <p>{{ obj.grade }}</p>
                      <p>{{ obj.date }}</p>
{% endfor %}
{% for obj in events %}
                      {{ obj.content }}
{% endfor %}
</div>

所有模型都有日期字段,我正在尝试显示所有内容并按日期排序 em,而不是显示所有标记,然后显示所有事件

【问题讨论】:

  • 你面临什么问题?
  • 我正在尝试找到一种方法将 em 显示为时间线和 order_by = "-date" 例如 (mark ,event, mark) 而不是在所有事件之后显示所有标记

标签: django django-models django-templates django-views


【解决方案1】:

我的做法是使用 itertools 链和 attrgetter

from itertools import chain
from operator import attrgetter

class MyListView(ListView):
    template_name = 'list.html'
    def get_queryset(self):
        qs1 = Events.objects.all() #your first qs
        qs2 = Marks.objects.all()  #your second qs
        #you can add as many qs as you want
        queryset = sorted(chain(qs1,qs2),key=attrgetter('timestamp'),)
        return queryset

从这篇帖子Combine 2 Django Querysets from Different Models得到答案

编辑

#models.py
class Events(models.Model):
    ...
    timestamp = models.DateTimeField(auto_now=False, auto_now_add=True,)

class Marks(models.Model):

    ...
    timestamp = models.DateTimeField(auto_now=False, auto_now_add=True,)


#templates
 {% for item in queryset %}
 {% if item.anyfieldusniquetoqs1 %}
   #here goes all qs1 field you want to display
 {% else %}
   #here goes all qs2 field you want to display
 {% endfor %}

【讨论】:

  • 我尝试了您的解决方案来解决两个模型通过 FK 关系相关的情况。尝试使用子模型上的 FK 字段使用 attrgetter 会引发 AttributeError: 'ParentTable' object has no attribute 'fk_field_childtable'。如何解决这个问题?
  • @LeLouch 你如何在模板中使用?你会遍历查询集吗?能给我举个例子吗?提前致谢!
  • @12379095 它们与 FK 无关,它们只是有一个名为 timestamp 的公共字段我已经编辑了您可以检查 models.py 的答案
【解决方案2】:

虽然与核心问题无关,但由于标题显示此答案,所以我将其发布给新手:

要从单个 ListView 返回多个查询集,如果您可以将所有查询集组合在一个变量中,那么它在 Django 中变得可以接受。简单的方法是使用字典。

例如:我需要从同一个模型中获取两个查询,一个是所有卖家,另一个是前 5 个卖家。 所以在 views.py:

class ViewName(ListView):
    model = ModelName
    template_name = "seller_info.html"
    context_object_name = 'sellers'

    def get_queryset(self):
        queryset = {'all_sellers': ModelName.objects.all(), 
                    'top_seller': ModelName.objects.all().filter(is_highest=True)[:5]}
        return queryset

seller_info.html 中,您可以通过以下方式访问每个查询集:

用于显示所有卖家:

{% if sellers %}
    {% for seller in sellers.all_sellers %}
      <p> {{ seller.name }} </p>
    {% endfor %}
{% endif %}

用于显示 top_seller:

{% if sellers.top_seller %}
    {% for seller in sellers.top_seller %}
      <p> {{ seller.name }} </p>
    {% endfor %}
{% endif %}

请注意,如果只有一个畅销书,那么也使用上面的 html 格式,但将查询集修改为:'top_seller': ModelName.objects.all().filter(is_highest=True)[:1]

【讨论】:

    【解决方案3】:

    您可以将所有查询集压缩在一起。因此,如果您覆盖 get_context_data 然后说您有包含事件查询集和标记查询集的变量事件和标记,则可以将它们存储到一个上下文变量中。然后在模板中,您可以将所有内容放在一个表格中,并为事件和标记设置一个单独的列。这将按日期将所有内容按顺序排列,但它们只会位于不同的列中。

    Views.py

    class MyClass(ListView):
        get_context_data(self,**kwargs):
            context = super().get_context_data(**kwargs)
            events = Events.objects.all().order_by('-date')
            marks = Marks.objects.all().order_by('-date')
            context['group'] = zip(events,marks)
            return context
    

    模板

    <table class="table">
        <thead class="thead">
            <tr>
                <th>Events</th>
                <th>Marks</th>
            </tr>
        </thead>
        <tbody>
            {% for events,marks in group %}
                <td>{{ events }}</td>
                <td>{{ marks }}</td>
            {% endfor %}
        </tbody>
    </table>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-18
      • 2013-09-01
      • 2018-10-14
      • 1970-01-01
      • 2023-03-12
      • 2019-06-24
      • 1970-01-01
      相关资源
      最近更新 更多