子类化 models.Manager

7 投票
1 回答
539 浏览
提问于 2025-04-17 09:03

我觉得在子类中继承 models.manager 对象并重写 get_query_set 方法,和在子类中单独创建一个新方法并使用这个方法,没什么区别。我是参考了《Django》这本书的例子。

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()

这样我可以使用 Person.women.all()Person.men.all() 来获取所有男性或女性的模型对象。不过,我觉得其实不重写 get_query_set 方法也能做到类似的事情,只需这样做:

class MaleManager(models.Manager):
    def get_male(self):
        return self.filter(sex='M')
class FemaleManager(models.Manager):
    def get_female(self):
        return  return self.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()

现在,我可以用一些小技巧来获取这些对象,比如 Person.objects.get_male()Person.objects.get_female()。但其实在获取对象的方式上并没有太大的细微差别,只是在可读性和使用上,第一种方式更复杂,而第二种方式则更容易理解,代码也更少。这样做在编码和模式上有什么显著的区别吗?还有,如果我把这两个方法放在同一个类里,会怎么样呢?

class PeopleManager(models.Manager):
        def get_male(self):
            return self.filter(sex='M')
        def get_female(self):
            return  return self.filter(sex='F')

1 个回答

3
  1. 通常情况下,你不想为模型创建多个管理器。扩展默认的管理器会更好。

    class PeopleManager(models.Manager):
        def get_male(self):
            return self.filter(sex='M')
    
        def get_female(self):
            return  return self.filter(sex='F')
    
    class Person(models.Model):
        ....
        objects = PeopleManager()
    

    这样你就可以使用 Person.objects.get_male()Person.objects.get_female() 以及像 Person.objects.order_by() 这样的内置方法。你可以看看 django.contrib.auth.models 中的自定义管理器作为例子。

  2. get_query_set 对于继承来说是个不错的选择。例如,你可以定义

    class SmithManager(PeopleManager):
        def get_queryset(self):
            return super(SmithManager, self).get_query_set().filter(last_name='Smith')
    

    这样管理器的所有方法都会只返回姓氏为 Smith 的人(Person.objects.get_male() 只会返回名叫 Smith 的男性,依此类推)。而且你不需要重写所有的方法。

撰写回答