我不知道这个的正确术语,所以我希望标题不会引起混淆。
我有以下型号。
func updateStatus(image: UIImage, error: Error?, context: UnsafeRawPointer) {
// Your code here
}
这允许我查询class Material(models.Model):
yes = models.IntegerField()
no = models.IntegerField()
def _votes(self):
return int(self.no + self.yes)
def _ratio(self):
v = self.votes
y = self.yes
try:
return float(y)/v
except ZeroDivisionError:
return float(0)
ratio = property(_ratio)
votes = property(_votes)
项并使用每个字段。
Material
到目前为止一切顺利。我想过滤过滤器的值。例如,如果比率大于0.8,我只想选择一个Material.objects.all()[0].yes # returns 5
Material.objects.all()[0].no # returns 3
Material.objects.all()[0].votes # returns 8
Material.objects.all()[0].ratio # returns 0.625
实例。
Material
然而,这样做会返回并错误声称Material.objects.filter(ratio__gt=0.8) # what I'd want to do
不是字段。
ratio
我该如何执行此查询?我假设我需要对模型进行一些更改,因此FieldError: Cannot resolve keyword 'ratio' into field. Choices are: id, no, yes
和ratio
会被注册为实际字段。怎么办?
答案 0 :(得分:3)
属性在模型级别定义。 Python可以处理这些属性,你可以用它做很复杂的事情(例如执行HTTP请求)。数据库不知道有属性,也没有大多数数据库执行非常复杂的功能(通常数据库本身不执行非常复杂的任务)。
这意味着为了过滤,我们可以在之后检索所有值。但这当然是低效的:它意味着我们首先将所有项目加载到内存中,如果过滤器相当严格,我们将做很多工作,只丢掉大量的结果。
F
- 表达式如果属性相当简单,我们可以写一个与之等效的数据库。例如,您的.vote
属性实际上是:
fvotes = F('yes') + F('no') # total number of votes
其中F(..)
是Django用来引用列的对象。
如果对于我们的ratio
,我们将始终排除没有votes
的值(因为阈值高于零),那么我们可以编写我们的注释,如:
fratio = F('yes') / fvotes # ratio of the votes
现在我们可以使用以下额外属性注释我们的数据库:
from django.db.models import F
fvotes = F('yes') + F('no')
Material.objects.annotate(
votes=fvotes,
fratio=F('yes') / fvotes
).filter(fratio__gt=0.8)
所以在这里我们基本上写了一些查询:
SELECT yes, no, yes + no AS votes, yes / (yes + no) AS ratio
FROM material
WHERE ratio > 0.8
因此,此查询在数据库级别执行,这通常比在Django级别手动执行过滤运行得更快。但如前所述,将Python函数转换为F
- 表达式需要一些技巧。此外,一些函数可以不能转换为表达式。例如,大多数数据库无法访问文件系统,无法联系Web服务等。在这种情况下,您必须手动进行过滤。
如果您必须手动进行过滤(出于上述原因),我们可以使用Python的filter(..)
函数。请注意,此过滤器不会返回QuerySet
,因此我们无法在其上执行其他.filter(..)
,.first()
,.annotate(..)
等功能。在这种情况下,我们可以使用lambda表达式:
filter(lambda x: x.ratio > 0.8, Material.objects.all())
所以在这里我们将所有 Material
个对象加载到内存中,让Python手动计算ratio
并执行检查。