Контекстный процессор для фильтрации пустых категорий - PullRequest
1 голос
/ 25 мая 2019

В моем блоге посты разделены по категориям. Я исключил категорию с именем Uncategorized из списка категорий и теперь хочу исключить категории, которые являются пустыми.

В context_processor у меня есть запрос, который работает нормально:

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

Я пробовал с таким запросом:

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,
    }

но я вижу эту ошибку:

Неподдерживаемый поиск 'category_set' для CharField или присоединение к полю не допускается.

Как я могу это исправить?

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", ....)
  .
  .
  :

1 Ответ

1 голос
/ 25 мая 2019

Вы можете исключить категории, которые пусты с:

MyCategory.objects.exclude(
    category_name='Uncategorized'
).filter(
    <b>category_set__isnull=False</b>
)<b>.distinct()</b>

Таким образом, будет сгенерирован запрос, который выглядит следующим образом:

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

Мы здесь, таким образом, указываем, что если мы сделаем LEFT OUTER JOIN с BlogPost, это должно быть пустым. Запрос здесь представляет собой INNER JOIN, что является оптимизацией, поскольку, если мы отфильтруем nullables, то ясно, что нам не нужно генерировать их в первую очередь.

При этом я настоятельно советую вам изменить related_name вашего category внешнего ключа на blogpost_set или просто оставить его как есть. related_name - это имя объекта в обратном направлении, Category не имеет category_set, оно имеет набор blogposts:

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

В этом случае запрос:

MyCategory.objects.exclude(
    category_name='Uncategorized'
).filter(
    <b>blogpost_set__isnull</b>=False
).distinct()
...