django-ninja icon indicating copy to clipboard operation
django-ninja copied to clipboard

[BUG] django's `@non_atomic_requests` decorator does not work with ninja views

Open ajalt opened this issue 2 years ago • 3 comments

Describe the bug

When using ATOMIC_REQUESTS, django has a decorator, @non_atomic_requests, to opt-out on a specific view. This is necessary e.g. when you want to mix sync and async views, since async views don't support transactions.

Applying this decorator to a ninja view doesn't work:

@api.post("/foo/bar")
@non_atomic_requests
async def foo_bar(request):
    pass

That will fail with RuntimeError: You cannot use ATOMIC_REQUESTS with async views. if using ATOMIC_REQUESTS.

The decorator doesn't work on sync views either. The decorator works by setting a property on the view function itself, and since Ninja uses its own view functions, that property isn't preserved.

There is a very hacky workaround:

@api.post("/foo/bar")
@non_atomic_requests
async def foo_bar(request):
    pass


transaction.non_atomic_requests(
    api.path_operations["/foo/bar"]._async_view.__func__ # or _sync_view
)

Versions (please complete the following information):

  • Python version: 3.10
  • Django version: 4.1
  • Django-Ninja version: 0.19.1
  • Pydantic version: 1.10.2

ajalt avatar Feb 22 '23 22:02 ajalt

@vitalik Hi! Could i look into this issue? this issue is still valid?

baidoosik avatar Dec 27 '23 09:12 baidoosik

Hi @baidoosik

I think this decorator works on the view level.. try this (in django ninja 1.x):

from ninja.decorators import decorate_view


@api.post("/foo/bar")
@decorate_view(non_atomic_requests)
async def foo_bar(request):
    pass

vitalik avatar Dec 27 '23 09:12 vitalik

@vitalik Thanks! I just ask this because this issue has help wanted tag. If there is any issue i can contribute, please share!

baidoosik avatar Dec 27 '23 10:12 baidoosik