2012-07-22 2 views
3

저는 이런 매니저 모델을 가진 GeoDjango 프로젝트를 가지고 있습니다.Python TastyPie - 사용자 지정 관리자 메서드를 필터로 사용 하시겠습니까?

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) 

나는 GET 매개 변수를 통해 within_box 기능을 노출하는 내 자원 모델 (AdvertResource)을 얻으려고, 같은;

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

이와 같이 자원 모델에 build_filters 메소드를 쓰기 시작했습니다.

하지만 '키워드'상자 '를 입력란으로 해결할 수 없습니다 ...'라는 오류가 발생합니다.

맞춤 관리자의 메소드를 api urls에 표시 할 수 있습니까?

수정 - 이제 다음 해결책으로이 문제를 해결했습니다.

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

위 코드에 몇 가지 문제가 있습니다.

먼저, tastypie를 사용하는지 여부에 관계없이 모든 사용자 정의 관리자를 모든 것으로 노출시킬 수 있습니다. 위에서 정의한 AdvertManager는 기본 관리자를 자신의 버전으로 바꾼 경우에만 Advert.objects를 통해 액세스 할 수 있습니다.

두 번째로, AdvertResource에서 tastypie 필터링을 노출하려는 방법은 필터링이 실제로 작동하는 방식에 직각입니다.

모든 필터는 <field_name>__<filter_name>=<value_or_values> 형태의 실제 ORM 필터로 적용됩니다. 귀하의 예에서 box=<number>,<number>,...,<number> tastypie를 사용하고 있기 때문에 box__exact=...에 해당 내용이 폭발하고 box 필드가 AdvertResource에서 발견되어 예상대로 실패합니다.

광고에 location이라는 필드가있는 경우 해당 필드의 필터로 withinbox을 추가하고 location__withinbox=<values>으로 필터링 할 수 있습니다. 당신이 당신의 원래의 접근 방식을 유지하려면

, 당신은 상자가 request.GET 사전에서 자신을 필터링 구문 분석하고 AdvertResource에 obj_getobj_get_list의 자신의 재정의 된 버전을 통과해야합니다.

마지막으로 build_filters을 확장하면 Tastypie 필터와 ORM 필터 만 매핑됩니다. 귀하의 예제에서는 개체를 필터로 반환합니다. 대신 단순히로 정의 :

{ 'withinbox' : 'point__within' } 

그리고 그것은 실제 필터 방법에 넘겨지기 전에 apply_filtersPolygon에 값 목록을 변환합니다.

관련 문제