Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django custom model managers

I'm confused about the correct way to use Django custom model managers - based on the docs you can create a series of managers for one model as a way of filtering. But why not create one manager class with a series of functions for filtering? Is one method better than the other? and why?

For example:

class MaleManager(models.Manager):
    def get_query_set(self):
        return super(MaleManager, self).get_query_set().filter(sex='M')

class FemaleManager(models.Manager):
    def get_query_set(self):
        return super(FemaleManager, self).get_query_set().filter(sex='F')

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    sex = models.CharField(max_length=1, choices=(('M', 'Male'), ('F', 'Female')))
    people = models.Manager()
    men = MaleManager()
    women = FemaleManager()

versus

class PersonManager(models.Manager):
    def males(self):
        return super(MaleManager, self).get_query_set().filter(sex='M')

    def females(self):
        return super(FemaleManager, self).get_query_set().filter(sex='F')

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    sex = models.CharField(max_length=1, choices=(('M', 'Male'), ('F', 'Female')))
    people = PersonManager()

Person.people.females() # to get list of females
Person.people.males() # to get a list of males
like image 271
9-bits Avatar asked Nov 13 '11 21:11

9-bits


1 Answers

With first method you can write:

men = Person.men.all()

or

peters_men = Person.men.filter(first_name='Peter')

For the second one method get_query_set is 'inherit' from model, then it return query set without customization. I don't know any reason to discard your second method, if you are using Admin interface you should check that this is suported.

Also, for the second one method you should correct your question. Is

class PersonManager(models.Manager):
    def males(self):
        return super(PersonManager, self).get_query_set().filter(sex='M')

Read django manager doc: "You can override a Manager's base QuerySet by overriding the Manager.get_query_set() method. get_query_set() should return a QuerySet with the properties you require."

Edited 2017 Be careful, get_query_set is renamed from djanto 1.7 to get_queryset. More info at Modifying a manager’s initial QuerySet

like image 200
dani herrera Avatar answered Oct 20 '22 14:10

dani herrera