I am using Django Rest Framework and its class-based view, with database connection set to ATOMIC_REQUESTS=True.
To optimize the application, I would like to have it so that only PUT and POST requests are under transaction, but not GET. Since I have ATOMIC_REQUESTS on, the documentation says to use the decorator on the dispatch() method in the view. So this is what I tried:
class MyView(APIView):
def get():
print("I am in a transaction:", not transaction.get_autocommit())
return Response({})
def post():
print("I am in a transaction:", not transaction.get_autocommit())
return Response({})
def put():
print("I am in a transaction:", not transaction.get_autocommit())
return Response({})
def dispatch(self, request, *args, **kwargs):
"""Override dispatch method and selectively apply non_atomic_requests"""
if request.method.lower() == "get":
return self.non_atomic_dispatch(request, *args, **kwargs)
else:
return super().dispatch(request, *args, **kwargs)
#transaction.non_atomic_requests
def non_atomic_dispatch(self, request, *args, **kwargs):
"""Special dispatch method decorated with non_atomic_requests"""
return super().dispatch(request, *args, **kwargs)
This does not work, since the get method still reports itself as under transaction, however, if I switch the decorator to look like this:
...
#transaction.non_atomic_requests
def dispatch(self, request, *args, **kwargs):
if request.method.lower() == "get":
return self.non_atomic_dispatch(request, *args, **kwargs)
else:
return super().dispatch(request, *args, **kwargs)
def non_atomic_dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
...
This works, though obviously it's not what I want.
My questions are:
Why does the placement of the decorator matter, if I am merely returning the same thing?
How do I make this work the way I want?
Related
Env: Python 3.6, Django 3.0, DRF 3.11, JWT Authorization
Hello everybody.
I have a simple class in my API where I want to check user permissions in each method get, post etc. I planned to check user privileges at dispatch but it doesn't work. Simplify code, my current class looks more or less like this:
class ExampleClassName(APIView):
can_do_sth = False
def dispatch(self, request, *args, **kwargs):
print(request.user) # Here is AnonymousUser
if request.user.username == "GreatGatsby":
self.can_do_sth = True
return super(ExampleClassName, self).dispatch(request, *args, **kwargs)
def get(self, request):
print(request.user) # Here is correctly Logged user
if self.can_do_sth:
return Response("You can do it")
return Response("You can't")
def post(self, request):
print(request.user) # Here is correctly Logged user
if self.can_do_sth:
return Response("You can do it")
return Response("You can't")
How can I pass request.user to dispatch method?
ok solved
initialize_request - is doing what I expected. so right dispatch should be:
def dispatch(self, request, *args, **kwargs):
req = self.initialize_request(request, *args, **kwargs)
print(req.user) # Now I have logged user data
if req.user.username == "GreatGatsby":
self.can_do_sth = True
return super(ExampleClassName, self).dispatch(request, *args, **kwargs)
Task closed unless you have any other idea how to do it in different way. If you do - please share :)
I've got a UpdateView in Django that I need to restrict to only the author. I having trouble grabbing the Author off of the request.
class MyPermissionMixin(LoginRequiredMixin, UserPassesTestMixin):
def dispatch(self, request, *args, **kwargs):
user_test_result = self.get_test_func()()
if request.user != ????.user: #How do I grab the user('Author')??
return self.handle_no_permission()
return super().dispatch(request, *args, **kwargs)
Get Autor instance user through self.get_object()
class MyPermissionMixin(object):
def dispatch(self, request, *args, **kwargs):
if request.user != self.get_object().author:
return HttpResponseForbidden()
return super().dispatch(request, *args, **kwargs)
Is it even possible?
I can't find anything or figure it out by myself since I'm a beginner, so I turn to you guys.
Here's an example (don't worry about the use case, I just want to know if it's possible and how):
When I run this code I get that *args is not defined. What's wrong?
views.py:
class MyCreateView(CreateView):
def get(self, request, *args, **kwargs):
slug = kwargs['slug']
helper_method(self, slug)
helpers.py:
def helper_method(self, slug):
if slug == "random":
return super(self.__class__, self).get(request, *args, **kwargs)
You have to define args and kwargs, you just need to add them to your method parameters like this:
def helper_method(self, slug, *args, **kwargs):
if slug == "random":
return super(self.__class__, self).get(request, *args, **kwargs)
class MyCreateView(CreateView):
def get(self, request, *args, **kwargs):
slug = kwargs['slug']
helper_method(self, slug, *args, **kwargs)
I have a class based view, and from the get and post request I have been calling a method, to obtain information from information in the HttpResponseRedirect kwargs.
code:
class View1(View):
def get(self, request, *args, **kwargs):
... stuff ...
return render(request, self.template_name, self.context)
def post(self, request, *args, **kwargs):
... stuff ...
return HttpResponseRedirect(
reverse('results:report_experiment',
kwargs={
'sample_id': current_sample_id
}
))
class View2(CustomView):
def obtainInformation(self, kwargs):
sample_id = kwargs.get('sample_id', None)
self.sample_obj = Sample.objects.get(id=sample_id)
def dispatch(self, request, *args, **kwargs):
self.obtainInformation(kwargs)
return super(View2, self).dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
... stuff ...
return render(request, self.template_name, self.context)
def post(self, request, *args, **kwargs):
... stuff ...
return HttpResponseRedirect(
reverse('results:report_experiment',
kwargs={
'sample_id': current_sample_id
}
))
My question is, when I call self.obtainInformation(kwargs) in the dispatch method, I can access any class variables I define in BOTH the get and post methods. Previously I was calling self.obtainInformation(kwargs) in both the get and post methods of view2 (so calling the method twice).
Is this a sensible way to use the dispatch method?
Yes, overriding dispatch() as you have done looks ok, and prevents the duplication of having to call obtainInformation in get() and post().
In Django 2.2+ there is a new setup() method that you could use.
class View2(CustomView):
def setup(self, request, *args, **kwargs):
super().setup(request, *args, **kwargs)
self.obtainInformation(kwargs)
I want to override get method in templateview:
class ...
def get(self, request, *args, **kwargs):
if request.is_ajax():
#do and return something
return super(self, Clasname).get(request, *args, **kwargs) #when not ajax
This is giving error.
Swap the arguments to super, i.e.,
return super(Clasname, self).get(request, *args, **kwargs)