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
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é!
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)
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.
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 .