我在Django2.2中有一个模板视图,在其中我添加了两个模型和查询来查询用户数据(他们每月阅读多少篇文章)的指标。
我遇到一个奇怪的问题,如果我在页面上放置多个上下文变量,则页面上除“第一个变量”之外的每个变量都将返回“ 0”。如果仅更改标记中变量的顺序,则每个日期函数似乎都在正确计算(只要它是第一个出现)。我在文档中找不到任何关于此的信息……我猜测这也不是显示此信息的好方法,我应该改用DjangoTemplateTag并在那里执行操作。
*定义对象和查询
def get_context_data(self, **kwargs):
context = super(userDashBoardView, self).get_context_data(**kwargs)
context['readArticleList'] = Articles.objects.filter(Unread = False,userId = self.request.user.SFPK )
*为避免进行进一步的查询,我将查询分为一组以执行进一步的功能
article_list = set(context['readArticleList'])
article_read_date = (article_list.read_date for article_list in article_list)
context['articles_last30'] = len(set(x for x in article_read_date if x > timezone.now() - timedelta(days=30)))
context['articles_last60'] = len(set(x for x in article_read_date if x > timezone.now() - timedelta(days=60)))
context['articles_last90'] = len(set(x for x in article_read_date if x > timezone.now() - timedelta(days=90)))
return context
{% block content %}
{{articles_last30}}
{{articles_last60}}
{{articles_last90}}
{% endblock %}
<br/>
对于上例中的上下文,上下文,上下文*使用示例数据
页面上的输出为(4,0,0)
如果顺序相反,我会得到
(20,0,0)
注意:我没有在控制台中收到任何错误,并且页面加载正常。谁能指出我正确的方向?
-谢谢您的时间=)
答案 0 :(得分:1)
您确实为article_read_date
使用了 generator ,
article_read_date = (article_list.read_date for article_list in article_list)
这意味着在 之后对其进行迭代,生成器将显示为“ 已用尽”。迭代器上的另一个循环将不再产生任何值。下面是一个说明性示例:
>>> l = [1,4,2,5]
>>> g = (x for x in l)
>>> list(g)
[1, 4, 2, 5]
>>> list(g)
[]
如您所见,第二个list(g)
不再产生任何值。
您可以使用以下方法创建集合:
article_read_date = [a.read_date for a in context['readArticleList']]
def count_since(iterable, _timed):
timestamp = timezone.now() - timed
return sum(x > timestamp for x in iterable)
context['articles_last30'] = count_since(article_read_date, timedelta(days=30))
context['articles_last60'] = count_since(article_read_date, timedelta(days=60))
context['articles_last90'] = count_since(article_read_date, timedelta(days=90))
话虽如此,由于django-2.0,Count
[Django-doc]具有filter=
属性,因此您可以通过一个额外的查询来统计文章,例如:
from django.db.models import Count, Q
nw = timezone.now()
context.update(
context['readArticleList'].aggregate(
articles_last30=Count('pk', filter=Q(read_date__gt=nw-timedelta(days=30))),
articles_last60=Count('pk', filter=Q(read_date__gt=nw-timedelta(days=60))),
articles_last90=Count('pk', filter=Q(read_date__gt=nw-timedelta(days=90)))
)
)
答案 1 :(得分:1)
您可以以更高效,更清洁的方式来做自己的工作。
首先,您应该注意,约定是模型不以复数形式命名。因此它不是Articles.objects..
,而是Article.objects..
。您应该将模型重命名为Article
,而不是Articles
。
如果我们假设Article(s)
是一个具有字段读取日期的模型,则应该如此。
class Article(models.Model):
read_date = models.DateTimeField()
... other_fields ..
因为您非常想要效率。您可以直接从数据库计算结果。
def get_context_data(self, **kwargs):
thirty_days_ago = datetime.now() - timedelta(days=30)
sixty_days_ago = datetime.now() - timedelta(day=60)
ninty_days_ago = datetime.now() - timedelta(day=90)
ctx = super().get_context_data(**kwargs)
ctx['articles_last90'] = \
Article.objects.filter(read_date__gt=ninty_days_ago).count()
ctx['articles_last60'] = \
Article.objects.filter(read_date__gt=sixty_days_ago).count()
ctx['last_last30'] = \
Article.objects.filter(read_date__gt=thirty_days_ago).count()
return ctx
通过这种方式,除了文章数之外,您永远不会将任何内容加载到python内存中。它比迭代甚至使用len(list_of_items)都要好。
您只需要意识到read_time__gt=ninty_days_ago
是指最近阅读超过90天的文章。
从Django Docs中了解更多信息。