Python 带有自定义QuerySet类的Django抽象基模型

Python 带有自定义QuerySet类的Django抽象基模型,python,django,django-models,Python,Django,Django Models,我正在使用一种类似于T.Stone的答案的方法。但是,我添加了一个抽象基类,因此我的models.py如下所示: class CustomQuerySetManager(models.Manager): """A re-usable Manager to access a custom QuerySet""" def __getattr__(self, attr, *args): try: return getattr(self.__cla

我正在使用一种类似于T.Stone的答案的方法。但是,我添加了一个抽象基类,因此我的models.py如下所示:

class CustomQuerySetManager(models.Manager):
    """A re-usable Manager to access a custom QuerySet"""
    def __getattr__(self, attr, *args):
        try:
            return getattr(self.__class__, attr, *args)
        except AttributeError:
            return getattr(self.get_query_set(), attr, *args)

    def get_query_set(self):
        return self.model.QuerySet(self.model)

class MyModel(models.Model): 
    class Meta:
        abstract = True

    class QuerySet(QuerySet):
        def user(self, pub, *args, **kwargs):
            return self.filter(publisher=pub, *args, **kwargs)

    ...some more methods here

class Book(MyModel):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author, related_name='book_author')
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()

    objects=models.Manager()
    obj=CustomQuerySetManager() #for testing purposes only, this will override objects later
这使我能够获得给定出版商的所有书籍,如:

p = Publisher.object.get(pk=1)
Book.obj.user(p).all()
我想对此进行扩展,以便在图书模型中定义一个自定义查询,然后将一个Q对象传递给QuerySet类,这样查询“publisher=pub”对于不同的模型可能会有所不同。我仍然希望能够像Book.obj.user(p.all()那样调用它。在书中的某个地方,我需要:

pubQ=Q(publisher=pub)

我可以把它放在哪里?如何将它传递给抽象基类中定义的QuerySet,同时尽可能保持代码的干燥?

这个答案很聪明,但它打破了Python的“显式优于隐式”原则。我对代码的第一反应是告诉您不能在模型中声明自定义查询集,但我决定检查上面提到的SO答案,看看您是从哪里得到这个想法的。同样,它很聪明——这一点不容小觑,但编写良好的代码是自文档的,应该能够被任何随机的Django开发人员使用并运行。这正是同行代码评审派上用场的地方——如果你有一个同行代码评审,你会立即得到一个WTF

Django核心团队采用以下方式:

class MyQuerySet(models.query.QuerySet):
    def some_method(self, an_arg, another_arg, a_kwarg='some_value'):
        # do something
        return a_queryset

class MyManager(models.Manager):
    def get_query_set(self):
        return MyQuerySet(self.model)

    def some_method(self, *args, **kwargs):
        return self.get_query_set().some_method(*args, **kwargs)

在管理器中不重复实际的方法定义的意义上,这是枯燥的。但是,这也是明确的——你确切地知道发生了什么。它不像您引用的方法那样枯燥,但“显式优于隐式”。此外,如果在实际的Django代码库中这样做,您可以合理地确信在您自己的代码中这样做是一种良好的实践。而且,它的副作用是使子类中的扩展和重写更加容易。

感谢Chris的回答。这与我的问题中的代码实现了相同的功能,当然更干净。它没有回答我关于如何在模型级别定义Q对象的问题,这将从视图中的查询中获取单个参数。你对此有什么建议吗?我已经用classmethod实现了我想要的。谢谢你帮我清理代码。