Ability to have the default parameter name in urls.
Just want to start off by saying, what a great library. I love it!
I was wondering if there is a way currently, or maybe implement here in the future, have the default parameter catchers in the URL. For example...
Here are some URLs that I generated using the django-extensions library.
/api/v1/users/
/api/v1/users/<pk>/
/api/v1/users/<pk>/deductions/
/api/v1/users/<user_pk>/businesses/
/api/v1/users/<user_pk>/businesses/<pk>/
/api/v1/users/<user_pk>/reports/
/api/v1/users/<user_pk>/reports/<pk>/
/api/v1/users/<user_pk>/vehicles/
/api/v1/users/<user_pk>/vehicles/<pk>/
and here is what my urls.py file looks like with the nested routing.
router = routers.SimpleRouter()
router.register("", UserViewSet)
user_router = routers.NestedSimpleRouter(router, "", lookup="user")
user_router.register("businesses", BusinessViewSet)
user_router.register("reports", ReportViewSet)
user_router.register("vehicles", VehicleViewSet)
urlpatterns = [
path("/", include(router.urls)),
path("", include(user_router.urls)),
]
Obviously I could change the lookup key to something else but I want it to be the same as the 'default' way that I think DRF/Django uses?
I also use the library drf_yasg to generate a schema API page and my URLs look like so.

Anyone have an idea how I could accomplish this?
Edit:
I want to elaborate more since I don't think I explained super well. I want to be able to put the default pk in the URL which then would make it {id} in the API webpage that I generated with drf_yasg
drf_yasg.generators.OpenAPISchemaGenerator must be overridden
this method is {pk} Force translation of path arguments into model field names. https://drf-yasg.readthedocs.io/en/stable/drf_yasg.html#drf_yasg.generators.OpenAPISchemaGenerator.coerce_path
from drf_yasg.generators import OpenAPISchemaGenerator
class CustomOpenAPISchemaGenerator(OpenAPISchemaGenerator):
def get_endpoints(self, request):
"""Iterate over all the registered endpoints in the API and return a fake view with the right parameters.
:param request: request to bind to the endpoint views
:type request: rest_framework.request.Request or None
:return: {path: (view_class, list[(http_method, view_instance)])
:rtype: dict[str,(type,list[(str,rest_framework.views.APIView)])]
"""
enumerator = self.endpoint_enumerator_class(self._gen.patterns, self._gen.urlconf, request=request)
endpoints = enumerator.get_api_endpoints()
view_paths = defaultdict(list)
view_cls = {}
for path, method, callback in endpoints:
view = self.create_view(callback, method, request)
# path = self.coerce_path(path, view)
view_paths[path].append((method, view))
view_cls[path] = callback.cls
return {path: (view_cls[path], methods) for path, methods in view_paths.items()}
settings.py
SWAGGER_SETTINGS = {
'DEFAULT_GENERATOR_CLASS': 'doc.schemas.CustomOpenAPISchemaGenerator'
}
But pk It is clearer to use the model field name instead.
I ported this to drf-spectacular but still don't understand what to do with it...!? :-(
from collections import defaultdict
# from drf_yasg.generators import OpenAPISchemaGenerator
from drf_spectacular.generators import SchemaGenerator
from rest_framework import views
from .views import VideoViewSet, FrameViewSet, AnnotationViewSet #,...
class CustomSchemaGenerator(SchemaGenerator):
def get_endpoints(self, request):
"""Iterate over all the registered endpoints in the API and return a fake view with the right parameters.
:param request: request to bind to the endpoint views
:type request: rest_framework.request.Request or None
:return: {path: (view_class, list[(http_method, view_instance)])
:rtype: dict[str,(type,list[(str,rest_framework.views.APIView)])]"""
enumerator = self.endpoint_enumerator_class(self._gen.patterns, self._gen.urlconf, request=request)
endpoints = enumerator.get_api_endpoints()
view_paths = defaultdict(list)
view_cls = { views.APIView } #?
for path, method, callback in endpoints:
logger.debug(f"*** path, method, callback = {path}, {method}, {callback}")
view = self.create_view(callback, method, request)
path = self.coerce_path(path, view) #?
view_paths[path].append((method, view))
view_cls[path] = callback.cls
return {path: (view_cls[path], methods) for path, methods in view_paths.items()}