My goal: get Count of items per month displayed in my template, i.e.: May 2021 - 5, June 2021 - 10, Sep 2021 - 3, Oct 2021 - 2, etc
What I've done. I first created a test-project and my Index view inherited from CreateView (needed that for a form). Everything worked fine. However, in my main project my IndexView is inherited from django's TemplateView, and with the same code it shows like this: Sep 2021 - 1, Sep 2021 - 1, Oct 2021 - 1, Oct 2021 - 1, Oct 2021 - 1... you get the point. So, for some reason, it sees every item as a separate date without trying to aggregate them.
So the difference-maker has to be the inheritance from different views in django, however, in my main project, I cannot make my index view inherit from CreateView. Also, I'm still new to Django and would really appreciate all the help I can get. It took me a lot of effort to figure it out up until this point.
Here's my working code (in the test-project):
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 (pay attention to context['per_month'] line)
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 (not sure if it's relevant here, but just in case)
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 %}
Output:
Aug 2021 - 2 Sep 2021 - 1 Oct 2021 - 3
Here's my NOT working code (main project):
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)
Note: I tried experimenting with both: date_posted and deadline_date (in case the problem was DatetimeField, as opposed to DateField), but it didn't help.
views.py (same context['per_month'] line)
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 (same as above)
Output:
Aug 2021 -1 Aug 2021 -1 Oct 2021 - 1 Oct 2021 - 1 Oct 2021 - 1 Oct 2021 - 1
CodePudding user response:
You should add a .order_by(…)
to force grouping by, so:
context['per_month'] = Item.objects.values(
month=TruncMonth('date_posted')
).annotate(c=Count('id')).order_by('month')