问题
I have a Profile
class which is a OneToOne with Location
model. Every profile has one and only location.
class Location(models.Model):
profile = models.OneToOne(Profile)
point = PointField()
In one of my views, I display a list of profiles. For example, I first find profiles with locations and then find associated profiles.
ref_location = Point(0,0) # point to calculate distances from
locations = Location.objects.filter(point__distance_lte=(ref_location, D(m=50 * 1000))) \
profiles = Profile.objects.filter(pk__in=locations.values('profile_id'))
What I would want is to be able to know the distance to each of these profile instances, e.g. I want to do something like:
profiles = Profile.objects.filter(pk__in=locations.values('profile_id'))\
.annotate(distance=Distance('location__point', ref_location))
and then iterate over
for p in profiles:
print(p.distance.km)
Which is not possible
What I can do is annotate
the locations
instead, which isn't much use, because in the template I loop over profiles
, not locations
回答1:
You can use Subquery (for Django version >= 1.11) to compose this query:
locations = Location.objects.filter(
point__distance_lte=(OuterRef('ref_location'), D(m=50 * 1000))
).annotate(distance=Distance(OuterRef('point'), ref_location))
profiles = Profile.objects.filter(
pk__in=Subquery(locations.values('profile_id')
).annotate(distance=Subquery(locations.values('distance')))
Or for Django version < 1.11 you can compose this query as follows:
locations = Location.objects.filter(
point__distance_lte=(ref_location), D(m=50 * 1000))
).annotate(distance=Distance('point', ref_location))
profiles = Profile.objects.filter(
pk__in=locations.values('profile_id')
).annotate(distance=locations.values('distance'))
The point is that you annotate the distance to the Location
objects and then you annotate that distance to the appropriate profile.
来源:https://stackoverflow.com/questions/51506916/geodjango-distance-annotation-on-related-model