Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

203
Views
Make Django ORM automatically fetch properties

Say I have a Post model like this:

class Post(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    text_content = models.CharField()

    @property
    def comment_count(self):
        return self.comments.count()

Say I need to get all the data for the post with ID 3. I know that I can retrieve the user along with the post in one query, by doing Post.objects.select_related('user').get(pk=3), allowing me to save a query. However, is there a way to automatically fetch comment_count as well?

I know I could use Post.objects.annotate(comment_count=Count('comments')) (which will require me to remove the property or change the name of the annotation, as there would be an AttributeError), however is it possible to make the ORM do that part automatically, since the property is declared in the model?

Although I could just add the .annotate, this can get very tedious when there are multiple properties and foreign keys that need to be fetched on multiple places.

over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

Maybe this is not a perfect solution for you but you might find something similar that works. You could add a custom object manager, see docs

Then you could add a method like with_comment_count(). OR if you always want to annotate, then you can modify the initial queryset.

class PostManager(models.Manager):
    def with_comment_count(self):
        return self.annotate(
            comment_count=Count('comments')
        )
    # Or this to always annotate
    def get_queryset(self):
        return super().get_queryset().annotate(
            comment_count=Count('comments')
        )

class Post(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    text_content = models.CharField()
    objects = PostManager()

Then you could query like this.

post = Post.objects.get(pk=1).with_comment_count()
post.comment_count
over 4 years ago · Santiago Trujillo Report

0

Thanks to Felix Eklöf I managed to get it to work! As specified in the question, this was in the case in which there were multiple properties/foreign keys that need prefetching, and as such the ability to 'chain' prefetching was needed. This isn't possible by chaining PostManager methods, since they don't return a PostManager but a QuerySet, however I came up with a function that caches whatever it is asked to cache all at once, avoiding the need for chaining methods:

class PostManager(models.Manager):
    def caching(self, *args):
        query = self.all()
        if 'views' in args:
            query = query.annotate(view_count=Count('views'))
        if 'comments' in args:
            query = query.annotate(comment_count=Count('comments'))
        if 'user' in args:
            query = query.select_related('user')
        if 'archives' in args:
            query = query.prefetch_related('archives')
        return query

class Post(models.Model):
    objects = PostManager()
    ...

# caching can then be added by doing, this, for instance:
Post.objects.caching('views', 'user', 'archives').get(id=3)

Note that for this to work, I also had to change @property to @cached_property, thus allowing the ORM to replace the value, and allow proper caching with the same name.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!