How to use custom manager with related objects?

I159 picture I159 · Sep 20, 2011 · Viewed 20.5k times · Source

I have a custom manager. I want to use it for related objects. I found use_for_related_fields in docs. But it does not work the way I used it:

class RandomQueryset(models.query.QuerySet):

    def randomize(self):       
        count = self.count()
        random_index = random.randint(0, count - 1)
        return self.all()[random_index]


class RandomManager(models.Manager):

    use_for_related_fields = True

    def get_query_set(self):
        return RandomQueryset(self.model, using=self._db)

    def randomize(self):
        return self.get_query_set().randomize()

I used it for one model:

>>> post = PostPages.default_manager.filter(image_gallery__isnull=False).distinct().randomize()

And tried to do the same with m2m related object:

>>> post.image_gallery.randomize()

Got an error:

AttributeError: 'ManyRelatedManager' object has no attribute 'randomize'

Is it possible to use a custom manager in the way I did it? If so, how do you make it work?

Edit

My models:

class ShivaImage(models.Model, ImageResizing):
    image = models.ImageField(upload_to='img')
    slide_show = models.BooleanField() 
    title = models.CharField(max_length=100)
    text = models.TextField(max_length=400)
    ordering = models.IntegerField(blank=True, null=True)

    objects = RandomManager()


class PostPages(models.Model):
    image_gallery = models.ManyToManyField(ShivaImage, blank=True,
                                       related_name='gallery',)
    # all the other fields... 

    objects = RandomManager()

Answer

Serafeim picture Serafeim · Sep 24, 2014

For completeness of the topic, Django 1.7 (finally) supports using a custom reverse manager, so you can do something like that (just copying from the django docs):

from django.db import models

class Entry(models.Model):
    objects = models.Manager()  # Default Manager
    entries = EntryManager()    # Custom Manager

b = Blog.objects.get(id=1)
b.entry_set(manager='entries').all()