In my view, I often use APIView's as_view() to generate json.
I'd like to cache the response and tried the following but it won't work
def some_complex_view(self, request, *args, **kwargs):
pass
#method_decorator(cache_page(60, key_prefix='drf'))
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
Then, I call
def my_view(request, *args, **kwargs):
json_data = MyViewSet.as_view({'get': 'some_complex_view'})(request, format='json')
data = {
'my_data': json_data
}
return render(request, 'my_template.html', data)
It correctly caches when I request the view using browser, but it won't when using as_view()
There are a few strategies listed in the CBV docs:
Add the decorator in your urls.py route, e.g., login_required(ViewSpaceIndex.as_view(..))
Decorate your CBV's dispatch method with a method_decorator e.g.,
from django.utils.decorators import method_decorator
#method_decorator(login_required, name='dispatch')
class MyViewSet(TemplateView):
template_name = 'secret.html'
Before Django 1.9 you can't use method_decorator on the class, so you have to override the dispatch method:
class MyViewSet(TemplateView):
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(MyViewSet, self).dispatch(*args, **kwargs)
Related
Suppose I have 2 view classes
class View1(LoginRequiredMixin, UserPassesTestMixin, View):
def get(self, request, *args, **kwargs):
#Do something and render a page
def test_func(self):
#Validation logic
class View2(LoginRequiredMixin, UserPassesTestMixin, View):
def get(self, request, *args, **kwargs):
#Do something and response with JsonResponse
def test_func(self):
#The exact same validation logics as the test_func for View1
How can I in my Django code don't repeat the same test_func twice?
I found the answer
class MyPermissionRules(LoginRequiredMixin, UserPassesTestMixin):
def test_func(self):
#my rules here
class View1(MyPermissionRules, View):
def get(self, request, *args, **kwargs):
#Do something and render a page
class View2(MyPermissionRules, View):
def get(self, request, *args, **kwargs):
#Do something and response with JsonResponse
In this way the same rule can be reused
I'm working with Django-admin panel. I have created a custom view file to add a file manager.
To make file uploading safe, I just added permission_required decorator. But it throws an error 'FileBrowser' object has no attribute 'user'.
Here is my code.
class FileBrowser(ListView):
model = File
paginate_by = 30
template_name = "file_manager/browser.html"
extra_context = {
'file_type': type,
'title': "Media Browser",
}
#permission_required('file_manager.view_file')
def dispatch(self, request, *args, **kwargs):
file_type = request.GET.get('type')
self.queryset = File.objects.filter(type=file_type)
self.extra_context['value_to'] = request.GET.get('value_to')
self.extra_context['image_to'] = request.GET.get('image_to')
self.extra_context['form'] = FileForm()
return super().dispatch(request, *args, **kwargs)
You can not decorate the method like that, since such decorator does not expect self as first parameter. It thus sees self as the request parameter.
What you can do is work with a #method_decorator decorator, like:
from django.utils.decorators import method_decorator
#method_decorator(permission_required('file_manager.view_file'), name='dispatch')
class FileBrowser(ListView):
# …
def dispatch(self, request, *args, **kwargs):
# …
For a class-based view however, you can work with the PermissionRequiredMixin [Django-doc]
from django.contrib.auth.mixins import PermissionRequiredMixin
class FileBrowser(PermissionRequiredMixin, ListView):
permission_required = 'file_manager.view_file'
# …
def dispatch(self, request, *args, **kwargs):
# …
There was a small mistake in my code. But I didn't noticed that. I simply forgot to use #method_decorator and directly wrote #permission_required decorator.
This was what I wrote.
#permission_required('file_manager.view_file')
def dispatch(self, request, *args, **kwargs):
.......
.......
return super().dispatch(request, *args, **kwargs)
This is what I changed to:
#method_decorator(permission_required('file_manager.view_file'))
def dispatch(self, request, *args, **kwargs):
.......
.......
return super().dispatch(request, *args, **kwargs)
Now it's working fine.
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)
Is it possible to have a class based view delegate to a particular class-based view? Specifically what I'd like to do is have / point to a view called 'home' and the home view with delegate to View A if the user is logged in, or View B if no user is logged in. Alternatively I could do a redirect to a different URL. I'm not sure what would be the best practice here.
You can call another view from within a view in the same manner used in urls
class HomeView( TemplateView ):
template_name="index.html"
def dispatch( self, request, *args, **kwargs ):
if request.user.is_authenticated():
view=UserHomeView.as_view()
return view( request, *args, **kwargs )
return super( HomeView, self ).dispatch( request, *args, **kwargs )
class UserHomeView( TemplateView ):
template_name="user.html"
You can just redirect to a different url and that url is also served by a class based view.
urls.py
url(r'^$', HomeView.as_view(), name='home'),
url(r'^login/', LoginView.as_view(), name='login'),
url(r'^welcome/$', WelcomeView.as_view(), name='welcome')
views.py
class HomeView(TemplateView):
def get(self, request, *args, **kwargs):
if request.user.is_authenticated():
return HttpResponseRedirect(reverse('welcome'))
else:
return HttpResponseRedirect(reverse('login'))
class WelcomeView(TemplateView):
def get(self, request, *args, **kwargs):
#do something
class LoginView(TemplateView):
def get(self, request, *args, **kwargs):
#show login page
Best practice to ensure that user must be authenticated is use Mixin:
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView
class LoginRequiredMixin(object):
u"""Ensures that user must be authenticated in order to access view."""
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(LoginRequiredMixin, self).dispatch(*args, **kwargs)
class MyView(LoginRequiredMixin, TemplateView):
def get(self, request, *args, **kwargs):
#do something