Django 使用相关的多个字段按距离排序

Django 使用相关的多个字段按距离排序,django,geodjango,django-orm,Django,Geodjango,Django Orm,我有这两种型号 class Store(models.Model): coords = models.PointField(null=True,blank=True) objects = models.GeoManager() class Product(models.Model): stores = models.ManyToManyField(Store, null=True, blank=True) objects = models.GeoManager

我有这两种型号

class Store(models.Model):
    coords = models.PointField(null=True,blank=True)
    objects = models.GeoManager()

class Product(models.Model):
    stores  = models.ManyToManyField(Store, null=True, blank=True)
    objects = models.GeoManager()
我想按到某个点的距离对产品进行排序。如果Product中的stores字段是外键,我会这样做,它会工作

pnt = GEOSGeometry('POINT(5 23)')
Product.objects.distance(pnt, field_name='stores__coords').order_by('distance')
但是,由于这个领域是一个众多的领域,它与

ValueError: <django.contrib.gis.db.models.fields.PointField: coords> is not in list
ValueError:不在列表中
我有点期待这一点,因为它不清楚应该使用哪个商店来计算距离,但有没有办法做到这一点


我需要按到特定点的距离订购的产品列表。

这是我解决问题的方法,但我并不喜欢这个解决方案。我觉得效率很低。应该有更好的办法对付詹戈。所以,在我找到更好的解决方案之前,我可能不会使用这个。这就是我所做的

我在产品模型中添加了一个新方法

class Product(models.Model):
    stores  = models.ManyToManyField(Store, null=True, blank=True)
    objects = models.GeoManager()

    def get_closes_store_distance(point):
        sorted_stores =  self.stores.distance(point).order_by('distance')
        if sorted_stores.count() > 0:
            store = sorted_stores[0]
            return store.distance.m
        return 99999999 # If no store, return very high distance
然后我可以这样分类

def sort_products(self, obj_list, lat, lng):
    pt = 'POINT(%s %s)' % (lng, lat)
    srtd = sorted(obj_list, key=lambda obj: obj.get_closest_store_distance(pt))
    return srtd

任何更好的解决方案或改进方法都是非常受欢迎的。

只是一个想法,也许这对您有用,这应该只需要两个数据库查询(取决于预取的工作方式)。如果它不起作用,不要苛刻地评判,我没有试过:

class Store(models.Model):
    coords = models.PointField(null=True,blank=True)
    objects = models.GeoManager()

class Product(models.Model):
    stores  = models.ManyToManyField(Store, null=True, blank=True, through='ProductStore')
    objects = models.GeoManager()

class ProductStore(models.Model):
    product = models.ForeignKey(Product)
    store = models.ForeignKey(Store)
    objects = models.GeoManager()
然后:

我将“从一个产品到一个点的距离”作为从该点到该产品商店的最小距离。我将把输出作为按距离升序排序的所有产品的(产品,距离)列表。(某位悬赏者的评论指出,他们有时也希望(产品、距离、商店)按距离排序,然后在产品中存储。)

每个模型都有一个对应的表。模型的字段是表的列。每个模型/表都应该有一个填充-(命名)blanks语句,其中其记录/行是构成true语句的记录/行

Store(coords,...) // store [store] is at [coords] and ...
Product(product,store,...) // product [product] is stocked by store [store] and ...
由于产品和manyToManyField一样有门店,因此它已经是一个“ProductStore”产品和库存门店表,门店已经是一个“StoreCoord”门店及其坐标表

对于具有manyToManyField的模型,可以在query filter()中提及任何对象的字段

这方面的SQL很简单:

select p.product,distance
    select p.product,distance(s.coord,[pnt]) as distance
    from Store s join Product p
    on s.store=p.store
group by product
having distance=min(distance)
order by distance
将此映射到一个应用程序应该很简单。然而,我对Django还不够熟悉,现在还不能给出确切的代码

from django.db.models import F

q = Product.objects.all()
    .filter(store__product=F('product'))
    ...
    .annotate(distance=Min('coord.distance([pnt])'))
    ...
    .order_by('distance')
Min()就是一个示例

你也可以通过明确地做出一个决定来得到帮助


也可以通过接口查询此信息。但是,上面的名称不适合Django原始查询。默认情况下,表名将是APPL_store和APPL_product,其中APPL是您的应用程序名。此外,距离不是点域操作符。你必须给出正确的距离函数。但是您不需要在原始级别进行查询。

我也遇到了这个困难。也许这在詹戈身上是不可能的?也许有人必须为它创建一个原始sql?@JoeJ我会把我所做的作为一个可能的答案,但我不喜欢它。也许原始SQL可以工作,但我不太适应空间查询之类的。查看答案,看看你的想法。产品有一个
manytomy
Store
,但拥有
点域的是商店。一个产品可以在一个或多个商店中。。。哪个距离是一个拥有多个门店的产品的距离?较低的?更高的?“全部?”利亚雷斯问了个好问题。就我而言,这是最接近的一个。我需要一个产品搜索,在地图上显示你周围的产品。你碰巧找到了一个有效的解决方案吗?@VikasGulati&manuel:我将重复一个问题的评论(VikasGulati可能没有看到):什么是“产品到一个点的距离”?(可能是从该点到该产品商店的最小距离。)具体输出是什么?(可能是所有产品的(产品,距离)列表,按距离升序排序。)@philipxy:Yes distance是最小值。在一个类似的问题中,我希望得到的输出是按计算出的最小距离排序的产品列表+每个产品都应该按距离重新排序预取相关存储。谢谢你的回答。我在一年多前发布了这篇文章,不幸的是,我再也无法访问代码或测试这篇文章了。如果有人发现它对他们有效,我会将其标记为已回答。谢谢你的回答。我在一年多前发布了这篇文章,不幸的是,我再也无法访问代码或测试这篇文章了。如果有人发现它对他们有效,我会把它标记为已回答。明白。(该网站最近发布了悬赏信息。)
from django.db.models import F

q = Product.objects.all()
    .filter(store__product=F('product'))
    ...
    .annotate(distance=Min('coord.distance([pnt])'))
    ...
    .order_by('distance')