Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to have the default parameter name in urls. #180

Open
trevorphillipscoding opened this issue Jul 3, 2020 · 2 comments
Open

Ability to have the default parameter name in urls. #180

trevorphillipscoding opened this issue Jul 3, 2020 · 2 comments

Comments

@trevorphillipscoding
Copy link

trevorphillipscoding commented Jul 3, 2020

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.
Screen Shot 2020-07-02 at 9 54 28 PM

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

@gongul
Copy link

gongul commented Jan 27, 2021

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.

@matthewsheeran
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants