Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Django how to sort by fields that don't exist

Currently, I have two models

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

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

from django.db import models

class Category(models.Model):
  
  name = models.CharField(max_length=30, unique=True)
  
  def __str__(self):
    return f'{self.name}' 

I want to create a logic that gets the number of posts per category and sorts them in descending order.
"http://localhost:8000/api/category?ordering=-post_count"
Through the url as above
I want to make it like the result of this query.

        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

I want to use Django ordering, but post_count is a non-existent field(Category model), so I can’t use it.
I’d appreciate it if you could tell me a good way.

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)

I tried to query the data I wanted to get.
I tried to create a custom query.

>Solution :

The related_name=… parameter [Django-doc] is the name of the relation in reverse, so from the Category model to the Post model in this case. Therefore it (often) makes not much sense to name it the same as the forward relation. You thus might want to consider renaming the category relation to 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,
    )
    # …

We can then define an alias of the count and order by the number of posts:

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):
    # …
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading