Django как сортировать по несуществующим полям
В настоящее время у меня есть две модели
posts.models
from django.db import models
from django_prometheus.models import ExportModelOperationsMixin
from users.models import User
from category.models import Category
# Create your models here.
class Post(ExportModelOperationsMixin('post'), models.Model):
header_image = models.ImageField(default='ancean-no-header-image.png')
title = models.CharField(max_length=100)
introduce = models.TextField(default='')
content = models.JSONField('json', null=True, blank=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, db_column="author", related_name='author')
category = models.ForeignKey(Category, on_delete=models.SET_NULL, db_column="category", related_name='category', null=True, blank=True)
wave = models.IntegerField(default=0) # wave field like 'like post' on general SNS
created_at = models.DateTimeField(null=True)
updated_at = models.DateTimeField(auto_now=True)
is_finish = models.BooleanField(default=False)
is_public = models.BooleanField(default=False)
def __str__(self):
return f'{self.title} - {self.author}'
category.models
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=30, unique=True)
def __str__(self):
return f'{self.name}'
Я хочу создать логику, которая получает количество сообщений в каждой категории и сортирует их в порядке убывания. "http://localhost:8000/api/category?ordering=-post_count" Через url, как указано выше. Я хочу, чтобы это выглядело как результат этого запроса.
SELECT c.name, count(*) AS post_count FROM category_category c JOIN posts_post p ON (c.id = p.category)
GROUP BY p.category
ORDER BY count(*) DESC
Я хочу использовать Django ordering, но post_count является несуществующим полем (модель Category), поэтому я не могу его использовать. Буду благодарен, если вы подскажете мне хороший способ.
category.views
class CategoryView(GenericAPIView, ListModelMixin):
queryset = Category.objects.all()
serializer_class = CategorySerializer
filter_backends = [OrderingFilter]
ordering_fields = ['post_count']
authentication_classes = []
def get(self, request, *args, **kwargs):
return self.list(request)
Я попытался запросить данные, которые хотел получить. Я попытался создать пользовательский запрос.
Параметр related_name=…
[Django-doc] - это имя отношения в reverse, то есть от модели Category
к модели Post
в данном случае. Поэтому (часто) не имеет особого смысла называть его так же, как и прямое отношение. Таким образом, вы можете рассмотреть возможность переименования отношения в category
posts
:
class Post(ExportModelOperationsMixin('post'), models.Model):
# …
category = models.ForeignKey(
Category,
on_delete=models.SET_NULL,
db_column='category',
related_name='posts',
null=True,
blank=True,
)
# …
Затем мы можем определить псевдоним count и упорядочить его по количеству сообщений:
from django.db.models import Count
class CategoryView(GenericAPIView, ListModelMixin):
queryset = Category.objects.annotate(post_count=Count('posts')).order_by(
'-post_count'
)
serializer_class = CategorySerializer
filter_backends = [OrderingFilter]
ordering_fields = ['post_count']
authentication_classes = []
# …
Note: In order to resolve from what class a method call is routed, the Method Resolution Order [python-doc] is used. Since mixins typically define a function in terms of what is already defined, mixins typically are listed before the base class (there are exceptions), but in this case, you thus reorder the classes to:
class CategoryView(ListModelMixin, GenericAPIView): # …