Search code examples
pythondjangodjango-modelsdjango-ormdjango-managers

Django manager queries don't work in a chain of queries. AttributeError: 'QuerySet' object has no attribute <the manager method>


Problem: I've implemented a custom manager for a model with just one custom query set named get_by_tag and it's working fine if I use it this way:

ViewStatistic.objects.get_by_tag('some-tag-name').filter(user=user_id)

But when I change the order of queries, in this way:

ViewStatistic.objects.filter(user=user_id).get_by_tag('some-tag-name')

it doesn't work! and raises this error:

AttributeError: 'QuerySet' object has no attribute 'get_by_tag'

Am I missing something?! How can I do this in such a order?

P.S: The custom manager is something like this:

class MyCustomManager(models.Manager):
    def get_by_tag(self, tag_name):
        posts = Post.objects.filter(tags__pk=tag_name)
        return super().get_queryset().filter(post__pk__in=posts)

Solution

  • If you want to use your queryset methods inside of queryset chain and not only directly after the manager, you should define them as methods of custom QuerySet class that you connect to a manager.

    Two solutions are described in Django documentation Creating a manager with QuerySet methods.

    Common part - a custom QuerySet class with queryset methods

    class MyCustomQuerySet(models.QuerySet):
        def get_by_tag(self, tag_name):
            return self.filter(post__pk__in=Post.objects.filter(tags__pk=tag_name))
    
        # more possible queryset methods ...
    

    A) if your manager has only queryset methods and no other custom methods
        then you can create it simply from the QuerySet.

    class MyModel(models.Model):
        objects = MyCustomQuerySet.as_manager()
    

    B) if your manager need also other methods that do not return a queryset:

    class MyCustomManager(models.Manager):
        ...  # other methods
    
    class MyModel(models.Model):
        objects = MyCustomManager.from_queryset(MyCustomQuerySet)()