Django2.2 Context Manager |{{template_tags}} |Переменный лимит? - PullRequest
1 голос
/ 02 июня 2019

У меня есть шаблонное представление в 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 ]

1 голос
/ 02 июня 2019

Вы можете делать то, что вы делаете, гораздо более эффективным и чистым способом.

Во-первых, вы должны заметить, что соглашение гласит, что модели не называются во множественном числе.Так что это не 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 означает статьи, которые в последний раз были прочитаны более девяноста дней назад.

Смотрите больше из Django Docs .

1 голос
/ 02 июня 2019

Вы используете генератор для article_read_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)
[]

Как видите, второй 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 <b>Count, Q</b>

nw = timezone.now()

context.update(
    context['readArticleList'].<b>aggregate(</b>
        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)))
    <b>)</b>
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...