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

Support for decorators #422

Open
robd003 opened this issue Jun 13, 2019 · 9 comments
Open

Support for decorators #422

robd003 opened this issue Jun 13, 2019 · 9 comments

Comments

@robd003
Copy link

robd003 commented Jun 13, 2019

I've seen in the past people were talking about having support for decorators instead of being stuck with just CORS_URLS_REGEX

I'd like to re-open the request to support decorators so that it's very easy to limit CORS responses to specific views.

@adamchainz
Copy link
Owner

Thanks. This requires quite a re-imagination of the way the library works and I'd like to engage in this but don't have time right now. What's your use case, do you have something you can't achieve with CORS_URLS_REGEX, and how do you imagine the syntax working?

Thanks,

Adam

@danlamanna
Copy link

Coming from the flask world I feel the same. Working with a single regular expression to convey your rules is a bit clunky, I would much rather decorate an endpoint with specific options.

This is the decorator I typically use with flask-cors: https://flask-cors.readthedocs.io/en/latest/api.html#decorator. It enables setting any of those options per endpoint.

@simonw
Copy link

simonw commented Mar 8, 2021

Another vote for this here: I run the Django admin on a domain that also hosts a couple of API endpoints. I want to allow CORS for those endpoints, and I was hoping I could do it with a view decorator rather than having to add a middleware that affects every request to my site.

I'll use CORS_URLS_REGEX for the moment (somehow I didn't spot that when scanning the README earlier but it turns out it's documented there, I just missed it).

@matclayton
Copy link

Another request here as well. We run a subdomain and need to adjust some of the cors headers in various ways on the per api basis. Unfortunately these are public apis so can't be moved about now :(

@jaap3
Copy link
Contributor

jaap3 commented May 2, 2022

I had to apply CORS to exactly one view and came up with this solution:

class CustomCorsMiddleware(CorsMiddleware):
    def process_request(self, request):
        response = super().process_request(request)
        if response is not None:
            # Force process_response to run
            return super().process_response(request, response)
        else:
            return None


@method_decorator(decorator_from_middleware(CustomCorsMiddleware), name='dispatch')
class SomeView(View):
    ...

This is comparable to how Django does it for the CSRF decorators (https://github.com/django/django/blob/236e6cb5881168a79a194b43c2d8dff7a14c3f03/django/views/decorators/csrf.py#L1)

By adding a init method to the middleware class that takes extra configuration (overrides of defaults/settings) would make this even more flexible (using decorator_from_middleware_with_args to pass these arguments). This might need some reworking on how the settings wrapper works, but it looks like a feasible solution.

@kbakk
Copy link

kbakk commented Apr 10, 2023

Similarly to @jaap3's solution, but for function based views:

from corsheaders.middleware import CorsMiddleware
from django.utils.decorators import decorator_from_middleware
from django.views.decorators.csrf import csrf_exempt

cors = decorator_from_middleware(middleware_class=CorsMiddleware)

@cors
@csrf_exempt
def some_function(request):
    ...

It will read settings.py, so the CORS_* config values must be set there, but it does not require setting MIDDLEWARE.

@martinberoiz
Copy link

+1 for the decorators. I work on legacy code where the API is scattered across many different url's that don't have any sensible regex pattern. A view decorator would be very useful.

@jaap3
Copy link
Contributor

jaap3 commented Oct 4, 2023

[decorator_from_middleware] assumes middleware that’s compatible with the old style of Django 1.9 and earlier [...]

https://docs.djangoproject.com/en/4.2/ref/utils/#django.utils.decorators.decorator_from_middleware

Turns out that PR #852 converted the CorsMiddleware from "old style" to "new style". This means it is no longer possible to selectively decorate views with CorsMiddleware using decorator_from_middleware.

Sadly there seem to be no plans to make decorator_from_middleware work with new style middleware (https://code.djangoproject.com/ticket/26626). Currently trying to come up with another way to decorate a select set of views.

@jaap3
Copy link
Contributor

jaap3 commented Oct 4, 2023

I was able to get decorator_from_middleware working again by wrapping the new middleware and implementing process_request/process_response:

class CustomCorsMiddleware(CorsMiddleware):
    def process_request(self, request):
        response = self.check_preflight(request)
        if response is not None:
            # Add the CORS headers to the preflight response
            response = self.process_response(request, response)
        return response

    def process_response(self, request, response):
        return self.add_response_headers(request, response)

Use at your own risk. It basically re-implements the __call__ implementation of the CorsMiddleware, so if future versions change how that works this wrapper could stop working correctly (or at all).

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

8 participants