web-dev-qa-db-fra.com

Ajouter plus de vues à un routeur ou à un ensemble de vues (Django-Rest-Framework)

Essentiellement, j'essaie de trouver un bon moyen d'attacher plus de vues à un routeur sans créer de routeur personnalisé. Quelle est la bonne façon d'y parvenir?

Voici quelque chose d'équivalent à ce que j'essaie d'accomplir. Les noms de variables ont été modifiés et l'exemple de méthode que je veux introduire est extrêmement simplifié pour cette question.

Routeur:

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()

Un exemple d'un autre type de méthode que je dois inclure. (Il y en a beaucoup):

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

Le résultat final est que l'URL suivante fonctionnerait correctement et serait implémentée "proprement".

GET example.com/myobjects/123/locations
24
Kurtis

La réponse donnée par mariodev ci-dessus est correcte, tant que vous ne cherchez qu'à faire GET demandes.

Si vous voulez POST à une fonction que vous ajoutez à un ViewSet, vous devez utiliser le décorateur action:

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...

Vous devez alors POST vers une URL au format comme: /myobjects/123/update_location/

http://www.Django-rest-framework.org/api-guide/viewsets/#marking-extra-actions-for-routing a plus d'informations si vous êtes intéressé!

24
piercebot

Vous pouvez maintenant le faire avec les décorateurs list_route et detail_route: http://www.Django-rest-framework.org/api-guide/viewsets/#marking-extra-actions-for-routing

Par exemple:

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)
14
seddonym

Vous définissez la méthode comme vous le faites maintenant, mais vous devez utiliser la même URL que le nom de la méthode et ajouter un décorateur de liens, donc pour

/myobjects/123/locations/

Vous ajoutez une méthode comme celle-ci

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

et le routeur le choisira automatiquement.

8
mariodev

De Routage vers des méthodes supplémentaires sur un ViewSet :

Je pense que vous devrez peut-être acheminer la méthode à la main, c'est-à-dire The Old-Fashioned Way ™.

Tirez d'abord la méthode dans une vue distincte:

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

(ou tel)

Attribuez ensuite votre URL:

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

(Ou tel)

Il y a une question connexe sur SO .

3
Setheron