我想使用自定义网址实现资源删除。因此,我没有在默认资源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
代码,这很奇怪。有没有更好的方法呢?
在一篇文章中感谢和抱歉这两个问题,但我觉得它们是相关的。
答案 0 :(得分:0)
所以我终于找到了一个解决方案,即使我不确定它是最好的方法,所以如果有人想评论它,我会非常高兴。我已经实现了一个自定义授权类,其中包括以下方法:
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
课程中,由于资源的删除发生在自定义网址上,因此我覆盖了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.")