简化Django的ORM查询
问题描述:
因此,这里是我的很好的功能:简化Django的ORM查询
def is_serviceable(address):
"""
Checks if an address can be serviced by an Employee.
Returns True if address' lat-lng intersects with any of Employees' coverage.
If it doesn't, but address' locality is listed in world District model,
returns False and locality name.
Just returns False if nothing found.
-- address -- django-address Address object. Address should be geocoded (i.e
have latitude and longitude fields correctly filled)
"""
pnt = Point(address.longitude, address.latitude)
employee_exists = Employee.objects.filter(coverage__mpoly__intersects=pnt).exists()
district = District.objects.filter(mpoly__intersects=pnt).first()
if (employee_exists):
return employee_exists
elif district:
return False, district.name
else:
return False
得到我想要我必须执行两个数据库查询什么,首先要Employee表,然后到区表。这似乎不是一种可扩展的方法。然而,由于员工的覆盖属性实际上是与区模型许多一对多关系领域:
class Employee(models.Model):
coverage = models.ManyToManyField(
District,
related_name="employees",
verbose_name=_("assigned districts")
)
class District(models.Model):
mpoly = models.MultiPolygonField()
...我敢肯定,有一种方法来查询压缩到一个查询集,或者,如果Django的ORM不适合这种单一的SQL语句。不过,我不知道从哪里开始挖掘。有什么想法吗?
编辑:解决感谢Django的注释功能。
答
下面是基于Sayse的答案的解决方案:
pnt = Point(address.longitude, address.latitude)
district = District.objects.filter(mpoly__intersects=pnt).annotate(emps=Count('employees')).only('name').first()
if district:
if district.emps:
return True
return False, district.name
else:
return False
还没有分析它,但它只是一个查询而不是两个,这正是我一直在寻找的。此外,它首先查询区表,这意味着员工表上的负载较轻。
答
Employee对象访问其相关区对象:
x=Employee.objects.all()[0]
print x.district_set.all()
答
你可以做对员工的计数的注释,然后在那
District.objects.filter(mpoly__intersects=pnt).annotate(emps=Count('employees')).filter(emps__gt=0).first()
您也可以将数过滤想要使用.only('name')
,因为这是您在该区域实际使用的所有内容。
免责声明:这是未经测试,我不知道我这实际上将是任何更快,因为exists
是不是很密集
谢谢!注释非常酷,正是我所需要的。 – khvn
@khvn - 不用担心,尽情享受吧!你可以通过改变'elif'到'if区域'来删除检查'emp'(s)两次。 – Sayse
很好的结果。再次感谢! – khvn