Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Django2.2上下文管理器{{template_tags}}}变量限制?_Django_Django Templates_Django 2.0 - Fatal编程技术网

Django2.2上下文管理器{{template_tags}}}变量限制?

Django2.2上下文管理器{{template_tags}}}变量限制?,django,django-templates,django-2.0,Django,Django Templates,Django 2.0,我在Django2.2中有一个模板视图,我在其中添加了两个模型和查询以查找用户数据的指标(他们每月阅读多少篇文章) 我遇到了一个奇怪的问题,如果我在页面上放置多个上下文变量,页面上的每个变量都会返回“0”,但第一个变量会返回“0”。如果我只是更改标记中变量的顺序,则每个日期函数似乎都在正确计算(只要它是第一个出现的)。我在文档中找不到任何关于这方面的信息……我猜这也不是一个显示这些信息的好方法,我应该使用DjangoTemplateTag并在那里执行操作 *定义对象&查询 def get_con

我在Django2.2中有一个模板视图,我在其中添加了两个模型和查询以查找用户数据的指标(他们每月阅读多少篇文章)

我遇到了一个奇怪的问题,如果我在页面上放置多个上下文变量,页面上的每个变量都会返回“0”,但第一个变量会返回“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)
{%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