Search code examples
djangodjango-queryset

django count ids in every subgroup


I have models of subjects, topics and questions structured as following:

class Subject(models.Model):
    subject = models.CharField(max_length=200, unique=True)        
class Topic(models.Model):
    subject = models.ForeignKey(Subject, on_delete=models.CASCADE)
    topic = models.CharField(max_length=200, blank=False)
class Question(models.Model):
    subject = models.ForeignKey(Subject, on_delete=models.CASCADE,                                
    topic = ChainedForeignKey(
        "Topic",
        chained_field="subject",
        chained_model_field="subject",
        show_all=False,
        auto_choose=True,
    )

Now I want to create a query that will count ids for each subject, topic. viz:

╔═════════╤═══════╤═══════╗
║ subject │ topic │ count ║
╠═════════╪═══════╪═══════╣
║ 1       │ 1     │ 10    ║
╟─────────┼───────┼───────╢
║ 1       │ 2     │ 11    ║
╟─────────┼───────┼───────╢
║ 2       │ 3     │ 5     ║
╟─────────┼───────┼───────╢
║ 2       │ 4     │ 4     ║
╚═════════╧═══════╧═══════╝

So far tried the following:

numberq=Question.objects.all().values('subject','topic').annotate(TotalQuestions=Count('topic'))
numberq=Question.objects.all().values('subject','topic','id').order_by('subject','topic')        
numberq=df.groupby(['subject','topic'])['id'].count()#.size()

Unfortunately nothing yielding expected results. Can someone please guide? As a bonus 🙃 I also want to replace the subject_id and topic_id by the respective name fields.


Solution

  • from django.db.models import Count, F
    
    result = Question.objects.values('subject__subject', 'topic__topic')\
                         .annotate(count=Count('id'))\
                         .annotate(subject_name=F('subject__subject'), 
    topic_name=F('topic__topic'))\
                         .order_by('subject__subject', 'topic__topic')
    

    Here you can use F function to reference the subject and topic fields, and aliases them as subject_name and topic_name in the result.