2015-02-11 70 views
0

我有以下模型:定製SQL用來GeoDjango內置於ForignKey

class UserProfile(models.Model): 
    user = models.OneToOneField(User) 
    location = models.PointField(blank=True, null=True, srid=CONSTANTS.SRID) 

    objects = models.GeoManager() 

class Item(models.Model): 
    owner = models.ForeignKey(UserProfile) 

    objects = models.GeoManager() 

現在我需要按距離排序項目的一些觀點:

p = Point(12.5807203, 50.1250706) 
Item.objects.all().distance(p, field='owner__location') 

但是,這將引發我一個錯誤:

TypeError: ST_Distance output only available on GeometryFields. 

GeoDjango GeoQuerySet.distance() results in 'ST_Distance output only available on GeometryFields' when specifying a reverse relationship in field_name我可以看到這裏已經有票了。

現在我不喜歡在這個問題中提出的解決方案,因爲那樣我不會得到距離,我會失去距離。

所以我想我可以做到這一點通過自定義SQL查詢。我知道這個:

UserProfile.objects.distance(p) 

會產生這樣的事情:

SELECT (ST_distance_sphere("core_userprofile"."location",ST_GeomFromEWKB('\x0101000020e6100000223fd12b5429294076583c5002104940'::bytea))) AS "distance", "core_userprofile"."id", "core_userprofile"."user_id", "core_userprofile"."verified", "core_userprofile"."avatar_custom", "core_userprofile"."city", "core_userprofile"."location", "core_userprofile"."bio" FROM "core_userprofile" 

所以我的問題是:是否有一些簡單的方法如何手動建立這樣的查詢會按距離排序的項目?

回答

1

由於您要測量的距離的幾何距離爲UserProfile,因此查詢UserProfile對象並處理它們各自擁有的每個對象都是有意義的。 (該距離是由配置文件所擁有的所有項目一樣。)

例如:

all_profiles = UserProfile.objects.all() 
for profile in all_profiles.distance(p).order_by('distance'): 
    for item in profile.item_set.all(): 
     process(item, profile.distance) 

您可以讓這個更有效的與prefetch_related

all_profiles = UserProfile.objects.all() 
all_profiles = all_profiles.prefetch_related('item_set') # we'll need these 
for profile in all_profiles.distance(p).order_by('distance'): 
    for item in profile.item_set.all(): # items already prefetched 
     process(item, profile.distance) 

如果它是重要的是由於某種原因直接查詢Item對象,請嘗試使用extra

items = Item.objects.all() 
items = items.select_related('owner') 
distance_select = "st_distance_sphere(core_userprofile.location, ST_GeomFromEWKT('%s'))" % p.wkt 
items = items.extra({'distance': distance_select}) 
items = items.order_by('distance') 

Raw queries是另一種選擇,讓您從一個原始的SQL查詢得到的模型對象:

items = Item.objects.raw("SELECT core_item.* FROM core_item JOIN core_userprofile ...") 
+0

謝謝了額外的方法爲我工作最好的.. – 2015-02-15 23:12:19