Django自定义管理器通过相关模型过滤附近

时间:2017-11-17 10:54:47

标签: django django-models django-orm django-managers

我有两个模型ShopAddress

购物Model

class Shop(BaseModel):
    name = models.CharField(
        max_length=100,
        blank=True,
        null=True
    )
    address = models.ForeignKey(
        Address,
        blank=True,
        null=True,
        on_delete=models.SET_NULL
    )
    objects = LocationManager()

地址Model

class Address(BaseModel):
    latitude = models.DecimalField(
        max_digits=16,
        decimal_places=14, 
        blank=True,
        null=True
    )
    longitude = models.DecimalField(
        max_digits=16,
        decimal_places=14, 
        blank=True,
        null=True
     )
     status = models.NullBooleanField(null=True)

我为Shop模型创建了一个自定义管理器

class LocationManager(models.Manager):
    def nearby(self, latitude, longitude, proximity):
        """
        Return all object which distance to specified coordinates
        is less than proximity given in kilometers
        """
        # Great circle distance formula
        # acos will not work in sqlite
        gcd = """
            6371 * acos(
                cos(radians(%s)) * cos(radians(latitude))
                * cos(radians(longitude) - radians(%s)) +
                sin(radians(%s)) * sin(radians(latitude))
            )
        """
        queryset =  self.get_queryset().select_related(
            'address'
        ).exclude(
            latitude=None
        )
        .exclude(
            longitude=None
        )
        .annotate(
            distance=RawSQL(
                gcd,
                (
                    latitude,
                    longitude,
                    latitude
                )
            )
        ).filter(
            distance__lt=proximity
        ).order_by('distance')

        return queryset

现在我想使用自定义管理器找到附近的商店:

Shop.objects.nearby(13.244334,72.329832,20)

但是我收到了这个错误:

Cannot resolve keyword 'latitude' into field. Choices are: address, address_id, name

如何使用latitude过滤我的查询集来查找附近的商店?

1 个答案:

答案 0 :(得分:3)

您正在查询Shop模型,而不是Address模型。 您的Shop模型没有任何名为latitude的字段,如您的错误所述。

您应该使用字段查找按照链接对象Shopdocumentation)的属性过滤Address

由于Shop模型已按字段Address链接到您的address模型,要按Shop属性过滤Address,您可以执行此操作(即latitude字段):

Shop.objects.filter(address__latitude=<your_lookup_here>)

此外,您的两个exclude方法可以像这样重写(使用Q对象):

Shop.objects.exclude(
    Q(address__latitude__isnull=True)
    | Q(address__longitude__isnull=True)
)

我建议您阅读上面链接的有关queryset API的文档。