Django2.2上下文管理器{{template_tags}}}变量限制?
我在Django2.2中有一个模板视图,我在其中添加了两个模型和查询以查找用户数据的指标(他们每月阅读多少篇文章) 我遇到了一个奇怪的问题,如果我在页面上放置多个上下文变量,页面上的每个变量都会返回“0”,但第一个变量会返回“0”。如果我只是更改标记中变量的顺序,则每个日期函数似乎都在正确计算(只要它是第一个出现的)。我在文档中找不到任何关于这方面的信息……我猜这也不是一个显示这些信息的好方法,我应该使用DjangoTemplateTag并在那里执行操作 *定义对象&查询Django2.2上下文管理器{{template_tags}}}变量限制?,django,django-templates,django-2.0,Django,Django Templates,Django 2.0,我在Django2.2中有一个模板视图,我在其中添加了两个模型和查询以查找用户数据的指标(他们每月阅读多少篇文章) 我遇到了一个奇怪的问题,如果我在页面上放置多个上下文变量,页面上的每个变量都会返回“0”,但第一个变量会返回“0”。如果我只是更改标记中变量的顺序,则每个日期函数似乎都在正确计算(只要它是第一个出现的)。我在文档中找不到任何关于这方面的信息……我猜这也不是一个显示这些信息的好方法,我应该使用DjangoTemplateTag并在那里执行操作 *定义对象&查询 def get_con
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)
{%block content%}
{{articles_last30}}
{{articles_last60}}
{{articles_last90}}
{%endblock%}
对于上例中的context,context,context*使用示例数据
页面上的输出为(4,0,0)
如果顺序颠倒,我得到
(20,0,0)
注意:我在控制台中没有收到任何错误,页面加载正常。谁能给我指出正确的方向吗
-感谢您的时间=)您使用了一个生成器来生成文章\u read\u date
,事实上:
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)
[]
如您所见,第二个列表(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))
也就是说,因为它有一个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)))
)
)
从django.db.models导入计数,Q
nw=时区。现在()
context.update(
上下文['readArticleList']。聚合(
文章最后30个=计数('pk',过滤器=Q(读取日期\uuu gt=nw时间差(天数=30)),
文章最后60=计数('pk',过滤器=Q(读取日期\uuu gt=nw时间增量(天数=60)),
文章\u last90=计数('pk',过滤器=Q(读取日期\u gt=nw时间增量(天数=90)))
)
)
你可以用一种更高效、更干净的方式做你正在做的事情
首先,尽管您应该注意到约定是,模型不是以复数形式命名的。所以它不是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(项目列表)要好得多。
你只需要意识到,read\u time\uu gt=ninty\u days\u前
意味着最后一次阅读的文章超过了九天
更多信息请参见。您的
文章\u read\u date
是一个迭代器,因此在第一次for
循环后,它已耗尽。您说的是在进行预成熟优化,为了避免进一步查询,我将其转换为一个集合@Dssii3056。你可以用一种更简单的方式来做你正在做的事情。在这里使用集合可能是一个问题,因为这意味着如果有多篇文章
s具有相同的阅读日期
,那么它仍然算作一篇。再次感谢@WillemVanOnsem---@解锁我,我的印象是Django查询创建[List],而且只要我不关心为集合的内容编制索引,set()就更好了……我可能在这方面也错了,但我想我会分享“为什么”。如果是model.DateTimeField+,用户不需要在同一秒钟内完成多篇文章吗?调用set()是否会截断时间并留下日期?谢谢。这是非常有帮助的!那么调用set(article_read_date)或set(article_list.read_date for article_list in article_list)也可以解决这个问题*无论如何,我更喜欢你的方式,但只是想进一步了解我的错误所在。@Dssii3056:是的,如果你构建了一个集(…)
,那么你可以对它进行多次迭代。但这将导致三个额外的查询,而我们可以在一个查询中完成,这三个查询比其他任何查询都要高效。因为它们都在数据库级别运行,这比在django中将其作为python对象运行要高效得多@WillemVanOnsem但是最后一个解决方案也在数据库级别工作,除了我们在同一个JOIN
@WillemVanOnsem上计算三个Count(..)
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