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

时间:2019-06-02 16:36:00

标签: django django-templates

我在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)

注意:我没有在控制台中收到任何错误,并且页面加载正常。谁能指出我正确的方向?

-谢谢您的时间=)

2 个答案:

答案 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))

话虽如此,由于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中了解更多信息。