WannaInternet
WannaInternet

Reputation: 424

How to count sub-categories in Django?

I have a Model called Topic and Problem:

class Topic(models.Model):
    name = models.CharField(max_length = 250, unique = True)
    slug = models.CharField(max_length = 250, unique = True)

    class Meta:
        ordering = ('name',)
        verbose_name = 'Topic'
        verbose_name_plural = 'Topics'

    def get_url(self):
        return reverse('problemdirectory', args = [self.slug])

    def __str__(self):
        return self.name

class Problem(models.Model):
    slug = models.CharField(max_length = 250, unique = True)
    topic = models.ForeignKey(Topic, on_delete = models.CASCADE)

    questionToProblem = models.TextField()
    solutionToProblem = models.TextField()

    class Meta:
        ordering = ('questionToProblem',)

    def get_url(self):
        return reverse('solution_details', args = [self.topic.slug, self.slug])

    def __str__(self):
        return self.questionToProblem

Topic is like a "folder", or category to Problem. How would I count the number of problems a certain Topic has in views.py and reference it in the HTML template?:

def topicList(request):
    topics = Topic.objects.all()
    #numberOfProblems = Problem.objects.count()
    Problem.objects.filter(topic__name= topic).count()
    topics.order_by('name')

    return render(request, 'topiclist.html', {'topics': topics})

I have tried importing Q and filter() with no success so far.

Upvotes: 0

Views: 553

Answers (3)

Ijharul Islam
Ijharul Islam

Reputation: 1477

Add a related_name as follows.

class Problem(models.Model):
   slug = models.CharField(max_length = 250, unique = True)
   topic = models.ForeignKey(Topic, related_name="problems", on_delete = models.CASCADE)

And add a property method in Topic model like this-

class Topic(models.Model):
   name = models.CharField(max_length = 250, unique = True)
   slug = models.CharField(max_length = 250, unique = True)

   @property
   def total_problems(self):
       return self.problems.all().count()

You can now get the total number of problems with every topic as follows.

topics = Topic.objects.all()
for topic in topics:
    total_problems = topic.total_problems

You can show the problem count in your templates inside a for loop as following.

{{topic.total_problems}}

Upvotes: 2

weAreStarsDust
weAreStarsDust

Reputation: 2742

What about calculated field in Topic class?

class Topic(models.Model):
    name = models.CharField(max_length = 250, unique = True)
    slug = models.CharField(max_length = 250, unique = True)

    @property
    def problem_count(self):
        return Problem.objects.filter(topic = self).count()

Then it will be available in your topics variable

def topicList(request):
    topics = Topic.objects.all().order_by('name')    
    return render(request, 'topiclist.html', {'topics': topics})

Upvotes: 2

Baktiyar Bekbergen
Baktiyar Bekbergen

Reputation: 384

from django.db.models import Count
def topicList(request):
    topics = Topic.objects.all().annotation(problem_count=Count('topic_set'))
    #numberOfProblems = Problem.objects.count()
    Problem.objects.filter(topic__name= topic).count()
    topics.order_by('name')

    return render(request, 'topiclist.html', {'topics': topics})

Upvotes: 0

Related Questions