Ad

Context Processor For Filter Empty Categories

In my blog the posts are divided based on the categories. I've excluded the category named Uncategorized from the list of categories and now I want exclude the categories that are empty.

Into a context_processor I've the query below that working fine:

MyCategory.objects.exclude(category_name="Uncategorized")

I've tried with a query like this:

def myblog_menu(request):

    myblog_menu_link = MyCategory.objects.exclude(category_name="Uncategorized").filter(category_name__category_set__isnull=True)
    return {
        'myblog_menu_link': myblog_menu_link,
    }

but I see this error:

Unsupported lookup 'category_set' for CharField or join on the field not permitted.

How I can fix it?

models.py

class MyCategory(models.Mode):
  category_name = models.CharField(...)
  .
  .
  :

class BlogPost(models.Mode):
  title = models.CharField(...)
  category = models.ForeignKey(MyCategory, related_name="category_set", ....)
  .
  .
  :
Ad

Answer

You can exclude categories that are empty with:

MyCategory.objects.exclude(
    category_name='Uncategorized'
).filter(
    category_set__isnull=False
).distinct()

This will thus generate a query that looks like:

SELECT DISTINCT mycategory.*
FROM mycategory
INNER JOIN blogpost ON mycategory.id = blogpost.category_id
WHERE NOT (mycategory.category_name = 'Uncategorized')
AND blogpost.id IS NOT NULL

We here thus specify that if we make a LEFT OUTER JOIN with BlogPost, that should be empty. The query here is an INNER JOIN, which is an optimization, since if we filter out nullables, then it is clear that we do not have to generate those in the first place.

That being said, I strongly advice you to alter the related_name of your category foreign key to blogpost_set, or just leave it as it is. The related_name is the name of the object in reverse, a Category has no category_set, it has a set of blogposts:

class BlogPost(models.Mode):
  title = models.CharField(...)
  category = models.ForeignKey(MyCategory, related_name='blogpost_set', ....)

In that case the query is:

MyCategory.objects.exclude(
    category_name='Uncategorized'
).filter(
    blogpost_set__isnull=False
).distinct()
Ad
source: stackoverflow.com
Ad