with queryset instalar framework español apiview django-rest-framework

django-rest-framework - queryset - django rest framework with django 2



¿Usando la API navegable de Django Rest Framework con APIViews? (5)

la documentación generada?

Hola David, primero no describiría la API navegable como ''documentación generada''.

Si necesita documentación estática, lo mejor es buscar una herramienta de terceros como django-rest-swagger .

La API navegable significa que las API que construye serán autodescriptivas, pero es un poco diferente de las herramientas convencionales de documentación estática. La API navegable garantiza que todos los puntos finales que cree en su API puedan responder tanto con representaciones legibles por máquina (es decir, JSON) como legibles por el ser humano (es decir, HTML). También garantiza que pueda interactuar por completo directamente a través del navegador; cualquier URL con la que normalmente interactúe con un cliente programático también podrá responder con una vista amigable del navegador a la API.

¿Cómo puedo incluir eso?

Solo agregue una docstring a la vista y se incluirá en la representación de la API navegable de las URL que dirija a esa vista.

De forma predeterminada, puede utilizar la notación de rebaja para incluir el marcado HTML en la descripción, pero también puede personalizar ese comportamiento , por ejemplo, si prefiere usar primero.

Específicamente, ¿cómo puedo incluirlo en la API Root?

Simplemente querrá agregar explícitamente la URL a la respuesta devuelta por cualquier vista que haya conectado a /api/ . Por ejemplo...

from rest_framework import renderers from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.reverse import reverse class APIRoot(APIView): def get(self, request): # Assuming we have views named ''foo-view'' and ''bar-view'' # in our project''s URLconf. return Response({ ''foo'': reverse(''foo-view'', request=request), ''bar'': reverse(''bar-view'', request=request) })

Si tengo una vista como:

class MyAPIView(APIView): def get(self, request, name=None): return {"hello": name or "world"}

¿Cómo puedo incluir eso en la documentación generada? Específicamente, ¿cómo puedo incluirlo en la API Root, por lo que aparece cuando visito " http://example.com/api/ "?

La documentación incluye un ejemplo de APIView con descripción, pero no describe el proceso para incluirlo realmente en el navegador API.


La solución de @imyousuf es agradable, pero no admite los espacios de nombres de url y está un poco desactualizada.

Aquí hay una actualización de esto:

class HybridRouter(routers.DefaultRouter): def __init__(self, *args, **kwargs): super(HybridRouter, self).__init__(*args, **kwargs) self._api_view_urls = {} def add_api_view(self, name, url): self._api_view_urls[name] = url def remove_api_view(self, name): del self._api_view_urls[name] @property def api_view_urls(self): ret = {} ret.update(self._api_view_urls) return ret def get_urls(self): urls = super(HybridRouter, self).get_urls() for api_view_key in self._api_view_urls.keys(): urls.append(self._api_view_urls[api_view_key]) return urls def get_api_root_view(self): # Copy the following block from Default Router api_root_dict = {} list_name = self.routes[0].name for prefix, viewset, basename in self.registry: api_root_dict[prefix] = list_name.format(basename=basename) # In addition to that: api_view_urls = self._api_view_urls class APIRoot(views.APIView): _ignore_model_permissions = True def get(self, request, *args, **kwargs): ret = OrderedDict() namespace = request.resolver_match.namespace for key, url_name in api_root_dict.items(): if namespace: url_name = namespace + '':'' + url_name try: ret[key] = reverse( url_name, args=args, kwargs=kwargs, request=request, format=kwargs.get(''format'', None) ) except NoReverseMatch: # Don''t bail out if eg. no list routes exist, only detail routes. continue # In addition to what had been added, now add the APIView urls for api_view_key in api_view_urls.keys(): namespace = request.resolver_match.namespace if namespace: url_name = namespace + ":" + api_view_key ret[api_view_key] = reverse(url_name, args=args, kwargs=kwargs, request=request, format=kwargs.get(''format'', None)) return response.Response(ret) return APIRoot.as_view()


Optimicé HybridRouter para mi caso de uso y eliminé algunos códigos. Echale un vistazo:

class HybridRouter(routers.DefaultRouter): def __init__(self, *args, **kwargs): super(HybridRouter, self).__init__(*args, **kwargs) self.view_urls = [] def add_url(self, view): self.view_urls.append(view) def get_urls(self): return super(HybridRouter, self).get_urls() + self.view_urls def get_api_root_view(self): original_view = super(HybridRouter, self).get_api_root_view() def view(request, *args, **kwargs): resp = original_view(request, *args, **kwargs) namespace = request.resolver_match.namespace for view_url in self.view_urls: name = view_url.name url_name = name if namespace: url_name = namespace + '':'' + url_name resp.data[name] = reverse(url_name, args=args, kwargs=kwargs, request=request, format=kwargs.get(''format'', None)) return resp return view

Y el uso:

router = routers.HybridRouter(trailing_slash=False) router.add_url(url(r''^me'', v1.me.view, name=''me'')) router.add_url(url(r''^status'', v1.status.view, name=''status'')) urlpatterns = router.urls

O:

router = routers.HybridRouter(trailing_slash=False) router.view_urls = [ url(r''^me'', v1.me.view, name=''me''), url(r''^status'', v1.status.view, name=''status''), ] urlpatterns = router.urls


Para mezclar con enrutadores y clases APIView o método basado de tal manera que la raíz de la API muestra ambos con vistas de código mínimas en la vista APIRoot escribí un enrutador personalizado que amplía DefaultRouter y anula get_urls y get_api_root_view; se ve así:

from rest_framework import routers, views, reverse, response class HybridRouter(routers.DefaultRouter): def __init__(self, *args, **kwargs): super(HybridRouter, self).__init__(*args, **kwargs) self._api_view_urls = {} def add_api_view(self, name, url): self._api_view_urls[name] = url def remove_api_view(self, name): del self._api_view_urls[name] @property def api_view_urls(self): ret = {} ret.update(self._api_view_urls) return ret def get_urls(self): urls = super(HybridRouter, self).get_urls() for api_view_key in self._api_view_urls.keys(): urls.append(self._api_view_urls[api_view_key]) return urls def get_api_root_view(self): # Copy the following block from Default Router api_root_dict = {} list_name = self.routes[0].name for prefix, viewset, basename in self.registry: api_root_dict[prefix] = list_name.format(basename=basename) api_view_urls = self._api_view_urls class APIRoot(views.APIView): _ignore_model_permissions = True def get(self, request, format=None): ret = {} for key, url_name in api_root_dict.items(): ret[key] = reverse.reverse(url_name, request=request, format=format) # In addition to what had been added, now add the APIView urls for api_view_key in api_view_urls.keys(): ret[api_view_key] = reverse.reverse(api_view_urls[api_view_key].name, request=request, format=format) return response.Response(ret) return APIRoot.as_view()

Entonces lo uso como -

router = routers.HybridRouter() router.register(r''abc'', views.ABCViewSet) router.add_api_view("api-view", url(r''^aview/$'', views.AView.as_view(), name=''aview-name'')) urlpatterns = patterns('''', url(r''^api/'', include(router.urls)),


Versión actualizada del código @imyousuf para trabajar con DRF 3.4.1.

class HybridRouter(routers.DefaultRouter): def __init__(self, *args, **kwargs): super(HybridRouter, self).__init__(*args, **kwargs) self._api_view_urls = {} def add_api_view(self, name, url): self._api_view_urls[name] = url def remove_api_view(self, name): del self._api_view_urls[name] @property def api_view_urls(self): ret = {} ret.update(self._api_view_urls) return ret def get_urls(self): urls = super(HybridRouter, self).get_urls() for api_view_key in self._api_view_urls.keys(): urls.append(self._api_view_urls[api_view_key]) return urls def get_api_root_view(self, api_urls=None): # Copy the following block from Default Router api_root_dict = OrderedDict() list_name = self.routes[0].name for prefix, viewset, basename in self.registry: api_root_dict[prefix] = list_name.format(basename=basename) view_renderers = list(self.root_renderers) schema_media_types = [] if api_urls and self.schema_title: view_renderers += list(self.schema_renderers) schema_generator = SchemaGenerator( title=self.schema_title, url=self.schema_url, patterns=api_urls ) schema_media_types = [ renderer.media_type for renderer in self.schema_renderers ] api_view_urls = self._api_view_urls class APIRoot(views.APIView): _ignore_model_permissions = True renderer_classes = view_renderers def get(self, request, *args, **kwargs): if request.accepted_renderer.media_type in schema_media_types: # Return a schema response. schema = schema_generator.get_schema(request) if schema is None: raise exceptions.PermissionDenied() return Response(schema) # Return a plain {"name": "hyperlink"} response. ret = OrderedDict() namespace = request.resolver_match.namespace for key, url_name in api_root_dict.items(): if namespace: url_name = namespace + '':'' + url_name try: ret[key] = reverse.reverse( url_name, args=args, kwargs=kwargs, request=request, format=kwargs.get(''format'', None) ) except NoReverseMatch: # Don''t bail out if eg. no list routes exist, only detail routes. continue # In addition to what had been added, now add the APIView urls for api_view_key in api_view_urls.keys(): url_name = api_view_urls[api_view_key].name if namespace: url_name = namespace + '':'' + url_name ret[api_view_key] = reverse.reverse(url_name, request=request, format=kwargs.get(''format'')) return response.Response(ret) return APIRoot.as_view()

Cómo utilizar:

mobile_router = HybridRouter() mobile_router.add_api_view("device", url(r''^device/register/$'', DeviceViewSet.as_view({''post'': ''register''}), name=''device-register''))