2013-09-23 7 views
22

Im Wesentlichen versuche ich eine gute Möglichkeit zu finden, weitere Ansichten an einen Router anzuhängen, ohne einen benutzerdefinierten Router zu erstellen. Was ist ein guter Weg, dies zu erreichen?Hinzufügen weiterer Ansichten zu einem Router oder Viewset (Django-Rest-Framework)

Hier ist etwas, das dem entspricht, was ich zu erreichen versuche. Variablennamen wurden geändert und die Beispielmethode, die ich einführen möchte, ist für diese Frage extrem vereinfacht.

Router:

router = routers.SimpleRouter(trailing_slash=False) 
router.register(r'myobjects', MyObjectViewSet, base_name='myobjects') 
urlpatterns = router.urls 

Viewset

class MyObjectsViewSet(viewsets.ViewSet): 
""" Provides API Methods to manage MyObjects. """ 

def list(self, request): 
    """ Returns a list of MyObjects. """ 
    data = get_list_of_myobjects() 
    return Response(data) 

def retrieve(self, request, pk): 
    """ Returns a single MyObject. """ 
    data = fetch_my_object(pk) 
    return Response(data) 

def destroy(self, request, pk): 
    """ Deletes a single MyObject. """ 
    fetch_my_object_and_delete(pk) 
      return Response() 

Ein Beispiel eines anderen Verfahrens Typ I umfassen müssen. (Es gibt viele davon):

def get_locations(self, request): 
    """ Returns a list of location objects somehow related to MyObject """ 
    locations = calculate_something() 
    return Response(locations) 

Das Endergebnis ist, dass die folgende URL korrekt funktionieren und "sauber" implementiert werden würde.

GET example.com/myobjects/123/locations 

Antwort

23

Die answer given by mariodev oben ist korrekt, solange Sie nur GET Anfragen zu machen.

Wenn Sie POST auf eine Funktion möchten Sie zu einem Viewset sind anhängt, müssen Sie den action Dekorateur verwenden:

from rest_framework.decorators import action, link 
from rest_framework.response import Response 

class MyObjectsViewSet(viewsets.ViewSet): 

    # For GET Requests 
    @link() 
    def get_locations(self, request): 
     """ Returns a list of location objects somehow related to MyObject """ 
     locations = calculate_something() 
     return Response(locations) 

    # For POST Requests 
    @action() 
    def update_location(self, request, pk): 
     """ Updates the object identified by the pk """ 
     location = self.get_object() 
     location.field = update_location_field() # your custom code 
     location.save() 

     # ...create a serializer and return with updated data... 

Dann würden Sie POST auf eine URL formatiert wie: /myobjects/123/update_location/

http://www.django-rest-framework.org/api-guide/viewsets/#marking-extra-actions-for-routing hat mehr Informationen, wenn Sie interessiert sind!

+1

Ich versuche, eine Datei auf eine benutzerdefinierte Methode hochzuladen. Weißt du, wie ich das erreichen kann? – psychok7

+7

Ist '@ action' veraltet? Die Verknüpfung schlägt Methoden als Argumente für den Dekorateur' @ detail_route' vor. – rtindru

8

Sie definieren Methode, wie Sie jetzt tun, aber Sie müssen die gleiche URL als Methodennamen verwenden und Link Dekorateur hinzufügen, so dass für

/myobjects/123/locations/ 

Sie Methode hinzufügen wie folgt

@link(permission_classes=[...]) 
def locations(self, request, pk=None): 
    ... 

und Router wird es automatisch auswählen.

+1

Schnelle und sehr präzise Antwort. Die einzige Sache, die ich hinzufügen würde, ist "from rest_framework.decorators import link". Vielen Dank! – Kurtis

+0

Wenn möglich, könnten Sie (oder jemand anderes) mir auch ein Beispiel für das Hinzufügen einer Methode zum Router zeigen, die nicht in meinem ViewSet enthalten ist? – Kurtis

3

Von Routing to extra methods on a ViewSet:

Ich glaube, du ™ die Methode von Hand, das heißt die altmodische Art und Weise zu routen benötigen.

zuerst die Methode herausziehen als separate Ansicht:

set_password_view = UserViewSet.as_view({'post': 'set_password'}) 

(oder so)

dann Ihre URL zuweisen:

url(r'^users/username_available/$', set_password_view, name-=...) 

(Oder so)

Es gibt eine related question on SO.

14

Sie können dies jetzt tun mit der list_route und detail_route Dekorateure: http://www.django-rest-framework.org/api-guide/viewsets/#marking-extra-actions-for-routing

Zum Beispiel:

from rest_framework.decorators import list_route 
from rest_framework.response import Response 
... 

class MyObjectsViewSet(viewsets.ViewSet): 
    ... 

    @list_route() 
    def locations(self, request): 
     queryset = get_locations() 
     serializer = LocationSerializer(queryset, many=True) 
     return Response(serializer.data) 
+0

Hallo ich bin neu im Django, was wäre der Endpunkt dafür? Vielen Dank! –

+0

@ ShiftN'Tab Wenn Sie 'myobjects-list' und' myobjects-detail' haben, dann wird dies 'myobjects-locations' sein. – cezar

Verwandte Themen