简体   繁体   中英

How to expose non-model module methods via Django Rest Framework?

I am using Django Rest Framework to create an API. There are model classes such as City which are exposed via the API. Now I created a utils module with a few useful methods:

# city/utils.py

def distance_between_cities(city1, city2):
    return city1.distance(city2)

I want to expose the example method distance_between_cities as an API endpoint. So I started off by creating a view:

# city/views.py
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from . import utils

class DistanceView(APIView):

    def get(self, request, format=None):
        city1 = request.query_params.get('city1', None)
        city2 = request.query_params.get('city2', None)
        distance = utils.distance_between_cities(city1, city2)
        distance_hash = {'distance': distance}
        return Response(distance_hash, status=status.HTTP_200_OK)

Then I tried to register a route:

# city/urls.py
from rest_framework.routers import DefaultRouter
from . import views

router = DefaultRouter()
router.register(r'distance', views.DistanceView)

When I visit the website the following error is shown:

base_name argument not specified, and could not automatically determine the name from the viewset, as it does not have a .queryset attribute.

I would like to see the endpoint in the website rendered by DRF similar to other (model related) endpoints.

DRF API网站

Finally, I would like to access the endpoint via:

http://localhost:8000/api/cities/distance.json?city1=23&city1=42

I tried to inspect the API via curl :

$ curl -X HEAD -i http://localhost:8000/api/cities/distance.json?city1=23&city2=42

This is the response header:

HTTP/1.0 404 NOT FOUND
Date: Fri, 09 Oct 2015 16:45:06 GMT
Server: WSGIServer/0.2 CPython/3.4.3
X-Frame-Options: SAMEORIGIN
Content-Type: application/json
Vary: Accept, Cookie
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS

Useful links

If you need the new entry point to be listed, you'll need to inherit from a ViewSet (note that I'm not speaking about ModelViewSet).

I wrote a short guide + sample project on how to do that here: https://medium.com/@linovia/django-rest-framework-viewset-when-you-don-t-have-a-model-335a0490ba6f

You won't need all the ViewSet methods, probably just the list one according to your comments.

in your urls.py, you're giving router.register() a DistanceView, which is of type APIView, But you'll have to specify a ViewSet for that.

django-rest-framework can only determine url mapping for ViewSets. So instead you can manually map the url, like you would do with default django apps.

urls.py

urlpatterns = [
    url(r'distance', views.DistanceView),
]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM