3

このようなマネージャー モデルを持つ 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 パラメーターを介して within_box 関数を公開しようとしています。

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 URL にメソッドを公開することは可能ですか?

編集 - 次の解決策でこれを解決しました。

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&point__within_box=51.623349,-3.25362,51.514195,-3.4754133が境界ボックス内のすべての結果をフィルタリングするようになったことを意味します。

4

1 に答える 1

4

上記のコードにはいくつかの問題があります。

まず、はい、tastypie を使用しているかどうかに関係なく、任意のカスタム マネージャーを何にでも公開できます。上記で定義した AdvertManager は、デフォルトのマネージャーを独自のバージョンに置き換えた場合にのみ、Advert.objects を介してアクセスできます。

第 2 に、AdvertResource で Tastypie フィルタリングを公開する方法は、フィルタリングが実際にどのように機能するかと直交しています。

すべてのフィルターは、実質的に ORM フィルターとしてフォームに適用され<field_name>__<filter_name>=<value_or_values>ます。あなたの例では、box=<number>,<number>,...,<number>tastypieを使用しているため、AdvertResource 内のフィールドbox__exact=...を検索して検索しようboxとし、期待どおりに失敗します。

広告に というフィールドがある場合は、そのフィールドのフィルターとしてlocation追加し、次の条件でフィルターできます。withinboxlocation__withinbox=<values>

元のアプローチを維持したい場合は、request.GET ディクショナリから自分でボックス フィルターを解析し、AdvertResource の独自のオーバーライドされたバージョンに渡す必要がありobj_getますobj_get_list

最後に、拡張するときbuild_filtersは、Tastypie フィルターと ORM フィルターの間のマッピングを作成するだけです。あなたの例では、オブジェクトをフィルターとして返しています。代わりに、次のように定義します。

{ 'withinbox' : 'point__within' }

実際のフィルターメソッドに渡される前にPolygon、値のリストを内部に変換します。apply_filters

于 2012-07-23T05:28:10.867 に答える