2016-07-05 26 views
0

Ich möchte das Löschen einer Ressource mit einer benutzerdefinierten URL implementieren. Also, anstatt die DELETE auf der Standard-Ressource Tastypie URL zuzulassen, habe ich eine neue definiert. Das Löschen funktioniert, aber ich bekomme immer noch einen Fehler, weil ich sicher bin, dass etwas in meinem Code fehlt. Die Funktion zum Löschen ist cancel_ride_request.Tastypie: Implementierung resoce DELETE auf benutzerdefinierte URL

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 

Ich denke, auch die Art, wie ich die Ressourcenerstellung mit der Funktion implementiert haben register_ride_request nicht optimal ist. Es funktioniert, aber es ist seltsam, dass ich den Code HTTPResponse manuell zurückgeben muss. Gibt es keinen besseren Weg, es zu tun? Danke und Entschuldigung für die zwei Fragen in einem Beitrag, aber ich fühle sie sind verwandt.

Antwort

0

Also habe ich endlich eine Lösung gefunden, obwohl ich mir nicht sicher bin, ob es die beste Herangehensweise ist, also bin ich mehr als glücklich, wenn jemand es kommentieren möchte. Ich habe eine benutzerdefinierte Berechtigungsklasse implementiert, die unter dem anderen hat, die folgenden Methoden:

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 

Diese Klasse verwendet wird, um sicherzustellen, dass nur der Eigentümer des Objekts ist erlaubt, es zu löschen. Dann in meiner DemandResource Klasse, da das Löschen der Ressource bei einer benutzerdefinierten URL auftritt, habe ich die obj_delete Methode überschrieben. Im Folgenden werde ich den Code für die benutzerdefinierte URL zeigen, die Funktion die Anforderung und die überschrieben obj_delete Verfahren zu beantworten, die die benutzerdefinierte Berechtigungsklasse verwendet die Anforderung, um sicherzustellen, ist berechtigt, (alles in der Klasse ist 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.")