这是How to filter a queryset based on the result of a method on the model class that returns a boolean?的反转 - 我想基于QuerySet过滤器定义一个布尔实例方法,或者甚至更好地定义一个明显配对的QuerySet过滤器和布尔实例方法。
我已经编写了QuerySet / Manager子类,以根据文档为各种模型实现自定义过滤,例如。
class MyModelQuerySet(QuerySet):
def visible_to_user(self, user):
# Filter logic
class MyModelManager(Manager):
def get_queryset(self):
return MyModelQuerySet(self.model, using=self._db)
def visible_to_user(self, user):
return self.get_queryset().visible_to_user(user)
class MyModel(Model):
objects = MyModelManager()
我需要的是我可以使用模型实例调用的东西。
目前,我正在创建一个仅包含实例的QuerySet,在其上运行过滤器,并查看是否还有任何内容:
class MyModel(Model):
objects = MyModelManager()
def visible_to_user(self, user):
qs = self.__class__.objects.filter(pk=self.pk)
if hasattr(qs, 'visible_to_user'):
return qs.visible_to_user(user).exists()
return False
这很好且通用(它实际上是在mixin中定义的,因此我可以在我的所有模型中使用它)但它效率不高 - 它每次从数据库重新检索实例在许多情况下,对于单个实例的情况,过滤器逻辑的优化程度很低。
简单地在模型上编写面向实例的布尔函数就足够了,我担心维护这个问题会非常棘手 - 基本上对一个版本所做的任何更改都必须反映在另一个版本中,这是更多当他们处于完全不同的阶级时很困难,两者之间没有明显的联系。
我考虑过的一个选项是将两个函数放在一个mixin中,然后每个组件使用适当的版本:
class VisibleToUserMixin(object):
def _qs_visible_to_user(self, user):
# QuerySet logic
def _instance_visible_to_user(self, user):
# Instance logic
class MyModelQuerySet(VisibleToUser, QuerySet):
def visible_to_user(self, user):
return self._qs_visible_to_user(user)
class MyModel(VisibleToUser, Model):
def visible_to_user(self, user):
return self._instance_visible_to_user(user)
这为QuerySet和Model子类添加了一些包袱,但至少它将所有逻辑保存在一个地方,维护人员很容易看到依赖。
有关最佳做法的建议吗?