sch*_*eck 81 python django orm
是否可以按模型属性过滤Django查询集?
我的模型中有一个方法:
@property
def myproperty(self):
[..]
Run Code Online (Sandbox Code Playgroud)
现在我想通过这个属性过滤,如:
MyModel.objects.filter(myproperty=[..])
Run Code Online (Sandbox Code Playgroud)
这有点可能吗?
Gle*_*ard 68
不.Django过滤器在数据库级别运行,生成SQL.要基于Python属性进行过滤,您必须将对象加载到Python中以评估属性 - 此时,您已经完成了加载它的所有工作.
Cli*_*int 37
我可能误解了你原来的问题,但是在python中有一个内置的过滤器.
filtered = filter(myproperty, MyModel.objects)
Run Code Online (Sandbox Code Playgroud)
但最好使用列表理解:
filtered = [x for x in MyModel.objects if x.myproperty()]
Run Code Online (Sandbox Code Playgroud)
甚至更好,一个生成器表达式:
filtered = (x for x in MyModel.objects if x.myproperty())
Run Code Online (Sandbox Code Playgroud)
The*_*ist 13
看起来像使用注释的F()将是我的解决方案.
它不会过滤@property,因为F在对象之前与数据库的对话被带入python.但仍然把它放在这里作为答案,因为我想要按属性过滤的原因是真的想要通过两个不同字段上的简单算术结果来过滤对象.
所以,有些东西:
companies = Company.objects\
.annotate(chairs_needed=F('num_employees') - F('num_chairs'))\
.filter(chairs_needed__lt=4)
Run Code Online (Sandbox Code Playgroud)
而不是将属性定义为:
@property
def chairs_needed(self):
return self.num_employees - self.num_chairs
Run Code Online (Sandbox Code Playgroud)
然后对所有对象进行列表理解.
rat*_*ray 12
重新关注@ TheGrimmScientist建议的解决方法,您可以通过在Manager或QuerySet上定义它们来创建这些"sql属性",并重用/链/组合它们:
经理:
class CompanyManager(models.Manager):
def with_chairs_needed(self):
return self.annotate(chairs_needed=F('num_employees') - F('num_chairs'))
class Company(models.Model):
# ...
objects = CompanyManager()
Company.objects.with_chairs_needed().filter(chairs_needed__lt=4)
Run Code Online (Sandbox Code Playgroud)
使用QuerySet:
class CompanyQuerySet(models.QuerySet):
def many_employees(self, n=50):
return self.filter(num_employees__gte=n)
def needs_fewer_chairs_than(self, n=5):
return self.with_chairs_needed().filter(chairs_needed__lt=n)
def with_chairs_needed(self):
return self.annotate(chairs_needed=F('num_employees') - F('num_chairs'))
class Company(models.Model):
# ...
objects = CompanyQuerySet.as_manager()
Company.objects.needs_fewer_chairs_than(4).many_employees()
Run Code Online (Sandbox Code Playgroud)
有关更多信息,请参阅https://docs.djangoproject.com/en/1.9/topics/db/managers/.请注意,我将删除文档并且未对上述内容进行测试.
我遇到了同样的问题,我开发了这个简单的解决方案:
objects_id = [x.id for x in MyModel.objects.all() if x.myProperty == [...]]
MyModel.objects.filter(id__in=objects_id)
Run Code Online (Sandbox Code Playgroud)
我知道这不是最高效的解决方案,但在我这样的简单情况下可能会有所帮助