【问题标题】:Tastypie: implement resouce DELETE on custom urlTastypie:在自定义 url 上实现资源删除
【发布时间】:2016-07-05 18:03:29
【问题描述】:

我想使用自定义 url 实现资源的删除。因此,我没有在默认资源 Tastypie url 上允许 DELETE,而是定义了一个新的。删除有效,但我仍然收到错误,因为我确定我的代码中缺少某些内容。执行删除的函数是cancel_ride_request

class DemandResource(ModelResource):
"""
Handles ride requests resources. In particular:
    - Offers information about the logged user's ride requests
    - Allows new ride requests creation
"""

user = fields.ForeignKey(UserResource, 'passenger')
origin = fields.ForeignKey(NodeResource, 'origin', full=True)
destination = fields.ForeignKey(NodeResource, 'destination', full=True)

potential_drivers = fields.ListField(readonly=True)

class Meta:
    queryset = api.models.Demand.objects.all()
    resource_name = _Helpers.demand_resource_name
    list_allowed_methods = ['get']
    detail_allowed_methods = ['get', 'put', 'patch']
    authentication = BasicAuthentication()

def prepend_urls(self):
    return [
            url(r"^(?P<resource_name>%s)/register%s" % (self._meta.resource_name, trailing_slash()),
                self.wrap_view('register_ride_request'), name="api_ask_ride"),
            url(r"^(?P<resource_name>%s)/(?P<pk>.*?)/cancel%s" % (self._meta.resource_name, trailing_slash()),
                self.wrap_view('cancel_ride_request'), name="api_cancel_ride_request"),
            ]

@classmethod
def dehydrate_potential_drivers(cls, bundle):
    return _Helpers.serialise_passengerships_passenger(bundle.obj.passengership_set.select_related().all())

def hydrate(self, bundle):
    bundle.data['user'] = bundle.request.user

    #extract orign and destination ID
    bundle.data['origin'] = api.models.Node.objects.get(id=bundle.data['origin']['id'])
    bundle.data['destination'] = api.models.Node.objects.get(id=bundle.data['destination']['id'])

    bundle.data['arrival_time'] = datetime.strptime(bundle.data['arrival_time'], _Helpers.date_time_format)
    tz = pytz.timezone('Europe/Brussels') #TODO get the user time zone
    bundle.data['arrival_time'] = tz.localize(bundle.data['arrival_time'])
    bundle.data['arrival_time_tolerance_early'] = timedelta(minutes=int(bundle.data['arrival_time_tolerance_early']))
    bundle.data['arrival_time_tolerance_late'] = timedelta(minutes=int(bundle.data['arrival_time_tolerance_late']))

    return bundle

def register_ride_request(self, request, **kwargs):
    self.method_check(request, ['post', ])
    self.is_authenticated(request)
    data = json.loads(request.body)
    bundle = self.build_bundle(data=data, request=request)
    bundle = self.hydrate(bundle)
    demand = api.models.Demand(passenger=bundle.request.user,
                               origin=bundle.data['origin'],
                               destination=bundle.data['destination'],
                               arrival_time=bundle.data['arrival_time'],
                               arrival_time_tolerance_early=bundle.data['arrival_time_tolerance_early'],
                               arrival_time_tolerance_late=bundle.data['arrival_time_tolerance_late'])
    demand.save()
    return HttpResponse(status=201)

"""
Handling demand deletion, making sure the request type is a DELETE and the user is authenticated
"""
def cancel_ride_request(self, request, **kwargs):
    self.method_check(request, ['delete', ])
    self.is_authenticated(request)
    return api.models.Demand.objects.filter(pk=kwargs['pk']).delete()

"""
Makes sure that only the owner of a demand is able to delete it
"""
def delete_detail(self, object_list, bundle):
    return bundle.obj.passenger == bundle.request.user

我还认为我使用函数register_ride_request 实现资源创建的方式不是最佳的。它确实有效,但奇怪的是我必须手动返回HTTPResponse 代码。难道没有更好的方法吗? 对一篇文章中的两个问题表示感谢和抱歉,但我觉得它们是相关的。

【问题讨论】:

    标签: python django tastypie


    【解决方案1】:

    所以我终于找到了一个解决方案,即使我不确定这是最好的方法,所以如果有人想评论它,我会非常高兴。我已经实现了一个自定义的 Authorization 类,其中包括以下方法:

    class UserObjectsOnlyAuthorization(Authorization)
    
        def delete_detail(self, bundle):
            return self.request_is_from_owner(bundle)
    
        def request_is_from_owner(self, bundle):
            if hasattr(bundle.obj, "passenger"):
                return bundle.obj.passenger.pk == bundle.request.user.member.pk 
            elif hasattr(bundle.obj, "driver"):
                return bundle.obj.driver == bundle.request.user.member
            return bundle.obj.user == bundle.request.user.member
    

    该类用于确保只允许对象的所有者删除它。 然后,在我的 DemandResource 类中,由于资源的删除发生在自定义 URL 上,因此我覆盖了 obj_delete 方法。下面我展示了自定义 URL 的代码、响应请求的函数和覆盖的 obj_delete 方法,该方法使用自定义 Authorization 类来确保请求被授权(一切都在类 DemandResource 中):

    def prepend_urls(self):
        return [
                url(r"^(?P<resource_name>%s)/register%s" % (self._meta.resource_name, trailing_slash()),
                    self.wrap_view('register_ride_request'), name="api_ask_ride"),
                url(r"^(?P<resource_name>%s)/(?P<pk>.*?)/cancel%s" % (self._meta.resource_name, trailing_slash()),
                    self.wrap_view('cancel_ride_request'), name="api_cancel_ride_request"),
                ]
    
    def cancel_ride_request(self, request, **kwargs):
        """
        Handling demand deletion, making sure the request type is a DELETE and the user is authenticated
        :param request: the HTTP request data
        """
        self.method_check(request, ['delete', ])
        self.is_authenticated(request)
        # call the delete, deleting the obj from the database
        try:
            # get an instance of the bundle.obj that will be deleted
            obj = api.models.Demand.objects.get(pk=kwargs['pk'])
        except ObjectDoesNotExist:
            raise NotFound("The object does not exist.")
        bundle = Bundle(request=request, obj=obj)
        if self._meta.authorization.delete_detail(bundle):
            try:
                print "Entered"
                self.obj_delete(bundle, **kwargs)
                return http.HttpNoContent()
            except NotFound:
                return http.HttpNotFound()
        else: return HttpResponse(status=401) #unauthorized
    
    def obj_delete(self, bundle, **kwargs):
        try:
            # get an instance of the bundle.obj that will be deleted
            api.models.Demand.objects.get(pk=kwargs['pk']).delete()
        except ObjectDoesNotExist:
            raise NotFound("The object does not exist.")
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-13
      • 1970-01-01
      • 2020-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多