编程语言
首页 > 编程语言> > Python TastyPie-自定义管理器方法作为过滤器?

Python TastyPie-自定义管理器方法作为过滤器?

作者:互联网

我有一个GeoDjango项目,该项目具有这样的管理器模型;

class AdvertManager(models.GeoManager):

    def within_box(self, x0, y0, x1, y1):
        geometry = Polygon.from_bbox((x0, y0, x1, y1,))
        return self.filter(point__within=geometry)

我正在尝试获取我的资源模型(AdvertResource),以通过GET参数来公开内部框函数,例如:

http://127.0.0.1:8000/api/v1/advert/?format=json&box=51.623349,-3.25362,51.514195,-3.4754133

我开始像这样在资源模型上编写一个build_filters方法.

def build_filters(self, filters=None):
        if not filters:
            filters = {}
        orm_filters = super(AdvertResource, self).build_filters(filters)

        if 'box' in filters:
            points = [float(p.strip()) for p in filters['box'].split(',')]
            orm_filters = {'box': Advert.objects.within_box(*points).all()}

        return orm_filters

但这会引发错误“无法将关键字’box’解析为字段…”.

是否可以将方法从自定义管理器公开到api网址?

编辑-我现在用以下解决方案解决了这个问题.

class AdvertResource(ModelResource):

    longitude = fields.FloatField(attribute='longitude', default=0.0)
    latitude = fields.FloatField(attribute='latitude', default=0.0)
    author = fields.ForeignKey(UserResource, 'author')

    def build_filters(self, filters=None):
        """
        Build additional filters
        """
        if not filters:
            filters = {}
        orm_filters = super(AdvertResource, self).build_filters(filters)

        if 'point__within_box' in filters:
            points = filters['point__within_box']
            points = [float(p.strip()) for p in points.split(',')]
            orm_filters['within_box'] = points

        return orm_filters

    def apply_filters(self, request, applicable_filters):
        """
        Apply the filters
        """
        if 'within_box' in applicable_filters:
            area = applicable_filters.pop('within_box')
            poly = Polygon.from_bbox(area)
            applicable_filters['point__within'] = poly
        return super(AdvertResource, self).apply_filters(request, 
                                                        applicable_filters)

现在,这意味着请求http://127.0.0.1:8000/api/v1/advert/?format=json\u0026amp;point__within_box=51.623349,-3.25362,51.514195,-3.4754133现在可以过滤边界框中的所有结果.

解决方法:

上面的代码有几个问题.

首先,是的,您可以将任何自定义管理器暴露给任何对象,无论您是否正在使用它.仅当您用自己的版本替换默认管理器后,才能通过Advert.objects访问上面定义的AdvertManager.

其次,您要在AdvertResource上公开“美味”过滤的方式与过滤的实际工作方式正交.

实际上,所有过滤器都以< field_name> __< filter_name> ==< value_or_values>的形式作为ORM过滤器应用.由于在您的示例中,您使用box =< number>,< number>,…,< number> tastypie将其爆炸到box__exact = …并尝试在AdvertResource中查找box字段,但未按预期失败.

如果您的广告中有一个名为location的字段,则可以将insidebox添加为该字段的过滤器,并通过以下方式过滤:location__withinbox =< values>.

如果要保留原始方法,则必须从request.GET字典中解析框过滤器,然后将其传递给AdvertResource中自己的obj_get和obj_get_list覆盖版本.

最后,在扩展build_filters时,您仅在Tastypie过滤器和ORM过滤器之间进行映射.在您的示例中,您将返回对象作为过滤器;相反,只需将其定义为:

{ 'withinbox' : 'point__within' }

并将值列表转换为apply_filters内​​的Polygon,然后再移交给实际的过滤器方法.

标签:geodjango,tastypie,python,django
来源: https://codeday.me/bug/20191101/1980760.html