Количество предметов в месяц работает в CreateView, но не в TemplateView
Моя цель: получить количество элементов в месяц, отображаемое в моем шаблоне, т.е.: май 2021 - 5, июнь 2021 - 10, сентябрь 2021 - 3, октябрь 2021 - 2 и т.д.
Что я сделал. Сначала я создал тестовый проект и мое представление Index унаследовал от CreateView (это нужно было для формы). Все работало нормально. Однако, в моем основном проекте мой IndexView наследуется от TemplateView от django, и с тем же кодом он отображается следующим образом: Sep 2021 - 1, Sep 2021 - 1, Oct 2021 - 1, Oct 2021 - 1, Oct 2021 - 1... вы поняли суть. Таким образом, по какой-то причине он рассматривает каждый элемент как отдельную дату, не пытаясь их объединить.
Итак, разделителем должно быть наследование от различных представлений в django, однако, в моем основном проекте я не могу заставить мое представление index наследоваться от CreateView. Кроме того, я все еще новичок в Django и буду очень признателен за любую помощь, которую смогу получить. Мне потребовалось много усилий, чтобы разобраться в этом до этого момента.
Вот мой рабочий код (в тестовом проекте):
models.py
class Movie(models.Model):
title = models.CharField('Movie name', max_length=100)
gross = models.IntegerField('Gross', help_text='Worldwide, in dollars.')
release_date = models.DateField('Date of release', blank=True, null=True)
def __str__(self):
return self.title
views.py (обратите внимание на строку context['per_month'])
class IndexView(CreateView):
form_class = CreateMovieForm
template_name = 'home/index.html'
success_url = '/'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# per_month = queryset of dictionaries: month + number of movies in each month
context['per_month'] = Movie.objects.annotate(
month=TruncMonth('release_date')).values('month').annotate(c=Count('id')).values('month', 'c')
context['movies'] = Movie.objects.all()
return context
forms.py (не уверен, что здесь это уместно, но на всякий случай)
class CreateMovieForm(forms.ModelForm):
class Meta:
model = Movie
fields = '__all__'
widgets = {'release_date': DateInput(attrs={'value': timezone.now().date})}
index.html
{% for month in per_month %}
<ul>
<li>
{{ month.month|date:"M Y" }} - {{ month.c }}
</li>
</ul>
{% endfor %}
Выход:
<>>Август 2021 - 2 Сентябрь 2021 - 1 Октябрь 2021 - 3
Вот мой НЕ РАБОТАЮЩИЙ код (основной проект):
models.py
class Item(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(User, on_delete=models.CASCADE)
assigned_to = models.ManyToManyField(User)
date_posted = models.DateTimeField(auto_now_add=True)
deadline_date = models.DateField(null=True)
Примечание: я пробовал экспериментировать с обоими вариантами: date_posted и deadline_date (на случай, если проблема в DatetimeField, а не в DateField), но это не помогло.
views.py (та же строка context['per_month'])
class IndexView(LoginRequiredMixin, TemplateView):
template_name = 'bugtracker/main.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# per_month = queryset of dictionaries: month + number of movies in each month
context['per_month'] = Item.objects.annotate(
month=TruncMonth('date_posted')).values('month').annotate(c=Count('id')).values('month', 'c')
index.html (то же, что и выше)
Выход:
<>>Август 2021 -1 август 2021 -1 октябрь 2021 - 1 октябрь 2021 - 1 октябрь 2021 - 1 Октябрь 2021 - 1
Вы должны добавить .order_by(…)
для принудительной группировки по, так:
context['per_month'] = Item.objects.values(
month=TruncMonth('date_posted')
).annotate(c=Count('id')).order_by('month')