Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

204
Visualizações
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 Respostas
Responde à pergunta

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 Relatório

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 Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda