Python 按属性筛选
是否可以按模型属性筛选Django查询集 我的模型中有一个方法:Python 按属性筛选,python,django,orm,Python,Django,Orm,是否可以按模型属性筛选Django查询集 我的模型中有一个方法: @property def myproperty(self): [..] 现在我想通过这个属性进行过滤,比如: MyModel.objects.filter(myproperty=[..]) 这有可能吗?没有。Django过滤器在数据库级别运行,生成SQL。要基于Python属性进行过滤,您必须将对象加载到Python中以评估属性——此时,您已经完成了加载该对象的所有工作。我可能误解了您最初的问题,但Python中有一
@property
def myproperty(self):
[..]
现在我想通过这个属性进行过滤,比如:
MyModel.objects.filter(myproperty=[..])
这有可能吗?没有。Django过滤器在数据库级别运行,生成SQL。要基于Python属性进行过滤,您必须将对象加载到Python中以评估属性——此时,您已经完成了加载该对象的所有工作。我可能误解了您最初的问题,但Python中有一个内置项
filtered = filter(myproperty, MyModel.objects)
但最好使用:
或者更好,a:
我知道这是一个古老的问题,但为了那些在这里跳跃的人,我认为阅读下面的问题和相关答案是有用的:
请有人纠正我,但我想我已经找到了一个解决办法,至少对我自己来说是这样 我想处理那些属性完全等于。。。不管怎样 但是我有几个模型,这个例程应该适用于所有模型。它确实:
def selectByProperties(modelType, specify):
clause = "SELECT * from %s" % modelType._meta.db_table
if len(specify) > 0:
clause += " WHERE "
for field, eqvalue in specify.items():
clause += "%s = '%s' AND " % (field, eqvalue)
clause = clause [:-5] # remove last AND
print clause
return modelType.objects.raw(clause)
有了这个通用子例程,我可以选择所有与我的“specify”(propertyname,propertyvalue)组合字典完全相同的元素
第一个参数取a(models.Model)
第二本词典类似于:
{“财产1”:“77”,“财产2”:“12”}
它创建了一个SQL语句,如
SELECT * from appname_modelname WHERE property1 = '77' AND property2 = '12'
并返回这些元素的查询集
这是一个测试功能:
from myApp.models import myModel
def testSelectByProperties ():
specify = {"property1" : "77" , "property2" : "12"}
subset = selectByProperties(myModel, specify)
nameField = "property0"
## checking if that is what I expected:
for i in subset:
print i.__dict__[nameField],
for j in specify.keys():
print i.__dict__[j],
print
然后呢?你觉得呢?看来我会解决这个问题
它不会按@property
进行过滤,因为F
在将对象引入python之前会与数据库进行对话。但仍然把它作为答案放在这里,因为我想要按属性过滤的原因是,我真的想要通过两个不同字段上的简单算术结果过滤对象
因此,大致如下:
companies = Company.objects\
.annotate(chairs_needed=F('num_employees') - F('num_chairs'))\
.filter(chairs_needed__lt=4)
而不是将属性定义为:
@property
def chairs_needed(self):
return self.num_employees - self.num_chairs
然后对所有对象进行列表理解。根据@TheGrimmScientist建议的解决方法,您可以通过在管理器或查询集上定义这些“sql属性”来创建这些“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)
使用查询集:
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()
更多信息,请参阅。
请注意,我没有使用文档,也没有测试上述内容 也可以使用queryset注释来复制属性get/set逻辑,如建议的那样,与
属性结合使用。这可能会产生一些在Python级别和数据库级别都有效的东西
但是,不确定缺点:请参见示例。我也有同样的问题,我开发了这个简单的解决方案:
objects_id = [x.id for x in MyModel.objects.all() if x.myProperty == [...]]
MyModel.objects.filter(id__in=objects_id)
我知道这不是性能最好的解决方案,但在像我这样的简单情况下可能会有所帮助不幸的是,这个功能没有实现,这将是一个有趣的扩展,至少可以在生成结果集后过滤掉匹配的对象。如何在管理中处理它?有什么解决方法吗?一旦你有了Python对象,就可以对它进行过滤,但是他问的是Django QuerySet.filter,它构造SQL queries.right,但是如上所述,我想将该属性添加到我的数据库过滤器中。查询完成后进行过滤正是我想要避免的。没有括号的x.myproperty位于SQLAlchemy中:您可以通过将django与SQLAlchemy连接起来,但我怀疑这两者是否可以按您希望的方式连接。对于浏览此答案的人,此链接是关于在Django管理员使用“SimpleListFilter”。有用,但不是问题的答案,除非是在一个非常具体的情况下。一般来说,这似乎是一个体面的工作。我不认为这是理想的,但这比每次需要这样的东西时都必须使用存储库来修改从PyPI安装的包的模型要好得多。现在我已经有时间使用它了:这种方法的真正缺点是.raw()返回的查询集不是完全成熟的查询集,我的意思是缺少queryset方法:AttributeError:“RawQuerySet”对象没有属性“值”
您的代码审阅问题链接会通知您它是由作者自愿删除的。您是否介意在这里更新您的答案,或者添加代码链接或解释,或者删除您的答案?@hlongmore:很抱歉。这个问题被移到了这样的地步。我修复了上面的链接。
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()
objects_id = [x.id for x in MyModel.objects.all() if x.myProperty == [...]]
MyModel.objects.filter(id__in=objects_id)