I'm trying to do cache_page with class based views (TemplateView) and i'm not able to. I followed instructions here:
Django--URL Caching Failing for Class Based Views
as well as here:
https://github.com/msgre/hazard/blob/master/hazard/urls.py
But I get this error:
cache_page has a single mandatory positional argument: timeout
I read the code for cache_page and it has the following:
if len(args) != 1 or callable(args[0]):
raise TypeError("cache_page has a single mandatory positional argument: timeout")
cache_timeout = args[0]
which means it wont allow more than 1 argument. Is there any other way to get cache_page to work?? I have been digging into this for sometime...
It seems like the previous solutions wont work any longer
According to the caching docs, the correct way to cache a CBV in the URLs is:
from django.views.decorators.cache import cache_page
url(r'^my_url/?$', cache_page(60*60)(MyView.as_view())),
Note that the answer you linked to is out of date. The old way of using the decorator has been removed (changeset).
You can simply decorate the class itself instead of overriding the dispatch method or using a mixin.
For example
from django.views.decorators.cache import cache_page
from django.utils.decorators import method_decorator
#method_decorator(cache_page(60 * 5), name='dispatch')
class ListView(ListView):
...
Django docs on decorating a method within a class based view.
yet another good example CacheMixin
from cyberdelia github
class CacheMixin(object):
cache_timeout = 60
def get_cache_timeout(self):
return self.cache_timeout
def dispatch(self, *args, **kwargs):
return cache_page(self.get_cache_timeout())(super(CacheMixin, self).dispatch)(*args, **kwargs)
usecase:
from django.views.generic.detail import DetailView
class ArticleView(CacheMixin, DetailView):
cache_timeout = 90
template_name = "article_detail.html"
queryset = Article.objects.articles()
context_object_name = "article"
You can add it as a class decorator and even add multiple using a list:
#method_decorator([vary_on_cookie, cache_page(900)], name='dispatch')
class SomeClass(View):
...
I created this little mixin generator to do the caching in the views file, instead of in the URL conf:
def CachedView(cache_time=60 * 60):
"""
Mixing generator for caching class-based views.
Example usage:
class MyView(CachedView(60), TemplateView):
....
:param cache_time: time to cache the page, in seconds
:return: a mixin for caching a view for a particular number of seconds
"""
class CacheMixin(object):
#classmethod
def as_view(cls, **initkwargs):
return cache_page(cache_time)(
super(CacheMixin, cls).as_view(**initkwargs)
)
return CacheMixin
Yet another answer, we found this to be simplest and is specific to template views.
class CachedTemplateView(TemplateView):
#classonlymethod
def as_view(cls, **initkwargs): ##NoSelf
return cache_page(15 * 60)(super(CachedTemplateView, cls).as_view(**initkwargs))
Would like to add this:
If you need to use multiple decorators for cache like vary_on_headers and cache_page together, here is one way I did:
class CacheHeaderMixin(object):
cache_timeout = int(config('CACHE_TIMEOUT', default=300))
# cache_timeout = 60 * 5
def get_cache_timeout(self):
return self.cache_timeout
def dispatch(self, *args, **kwargs):
return vary_on_headers('Authorization')(cache_page(self.get_cache_timeout())(super(CacheHeaderMixin, self).dispatch))(*args, **kwargs)
This way cache is stored and it varies for different Authorization header (JWT). You may use like this for a class based view.
class UserListAPIView(CacheHeaderMixin, ListAPIView):
serializer_class = UserSerializer
def get_queryset(self):
return CustomUser.objects.all()
I didn't found a good cache solution for class based views and created my own: https://gist.github.com/svetlyak40wt/11126018
It is a mixin for a class. Add it before the main base class and implement method get_cache_params like that:
def get_cache_params(self, *args, **kwargs):
return ('some-prefix-{username}'.format(
username=self.request.user.username),
3600)
Here's my variation of the CachedView() mixin - I don't want to cache the view if the user is authenticated, because their view of pages will be unique to them (e.g. include their username, log-out link, etc).
class CacheMixin(object):
"""
Add this mixin to a view to cache it.
Disables caching for logged-in users.
"""
cache_timeout = 60 * 5 # seconds
def get_cache_timeout(self):
return self.cache_timeout
def dispatch(self, *args, **kwargs):
if hasattr(self.request, 'user') and self.request.user.is_authenticated:
# Logged-in, return the page without caching.
return super().dispatch(*args, **kwargs)
else:
# Unauthenticated user; use caching.
return cache_page(self.get_cache_timeout())(super().dispatch)(*args, **kwargs)
Related
I'm using Class-based views where I would like to ensure that each view can be access by logged-in users and by one type of the users only (there are two groups of users - each group has different permissions).
I'm implementing this according to the docs with persmissions (I'm using Django 1.7.7) https://docs.djangoproject.com/en/1.7/topics/class-based-views/intro/#decorating-the-class, however using two parameters raises an error " method_decorator() takes exactly 1 argument (2 given)" .
Hence - how to do it such that those two factors(login and permissions) will be verified in a class-based view?
class PatientCreate(CreateView):
model = Patient
fields = '__all__'
#method_decorator(login_required, permission_required('patient.session.can_add_patient'))
def dispatch(self, *args, **kwargs):
return super(PatientCreate, self).dispatch(*args, **kwargs)
Thanks!
In your case, permission_required will redirect to the login page for users that are not logged in, so you don't need to use login_required at all.
#method_decorator(permission_required('patient.session.can_add_patient')
def dispatch(self, *args, **kwargs):
...
If you really did need to use multiple decorators, then you can use a list in Django 1.9+
decorators = [other_decorator, permission_required('patient.session.can_add_patient')]
class PatientCreate(CreateView):
model = Patient
fields = '__all__'
#method_decorator(decorators)
def dispatch(self, *args, **kwargs):
...
You can also shorten the code by decorating the class itself:
#method_decorator(decorators, name="dispatch")
class PatientCreate(CreateView):
model = Patient
fields = '__all__'
On Django 1.8 and earlier, you can't pass a list to method_decorator or decorate the class, so you have to stack the decorators
class PatientCreate(CreateView):
model = Patient
fields = '__all__'
#method_decorator(other_decorator)
#method_decorator(permission_required('patient.session.can_add_patient'))
def dispatch(self, *args, **kwargs):
...
The decorators will process the request in the order they are passed to method_decorator. So for the examples above, other_decorator will run before permission_required.
Essentially, I'm trying to find a good way to attach more views to a Router without creating a custom Router. What's a good way to accomplish this?
Here is something sort of equivalent to what I'm trying to accomplish. Variable names have been changed and the example method I want to introduce is extremely simplified for the sake of this question.
Router:
router = routers.SimpleRouter(trailing_slash=False)
router.register(r'myobjects', MyObjectViewSet, base_name='myobjects')
urlpatterns = router.urls
ViewSet
class MyObjectsViewSet(viewsets.ViewSet):
""" Provides API Methods to manage MyObjects. """
def list(self, request):
""" Returns a list of MyObjects. """
data = get_list_of_myobjects()
return Response(data)
def retrieve(self, request, pk):
""" Returns a single MyObject. """
data = fetch_my_object(pk)
return Response(data)
def destroy(self, request, pk):
""" Deletes a single MyObject. """
fetch_my_object_and_delete(pk)
return Response()
One example of another method type I need to include. (There are many of these):
def get_locations(self, request):
""" Returns a list of location objects somehow related to MyObject """
locations = calculate_something()
return Response(locations)
The end-result is that the following URL would work correctly and be implemented 'cleanly'.
GET example.com/myobjects/123/locations
The answer given by mariodev above is correct, as long as you're only looking to make GET requests.
If you want to POST to a function you're appending to a ViewSet, you need to use the action decorator:
from rest_framework.decorators import action, link
from rest_framework.response import Response
class MyObjectsViewSet(viewsets.ViewSet):
# For GET Requests
#link()
def get_locations(self, request):
""" Returns a list of location objects somehow related to MyObject """
locations = calculate_something()
return Response(locations)
# For POST Requests
#action()
def update_location(self, request, pk):
""" Updates the object identified by the pk """
location = self.get_object()
location.field = update_location_field() # your custom code
location.save()
# ...create a serializer and return with updated data...
Then you would POST to a URL formatted like:
/myobjects/123/update_location/
http://www.django-rest-framework.org/api-guide/viewsets/#marking-extra-actions-for-routing has more information if you're interested!
You can now do this with the list_route and detail_route decorators: http://www.django-rest-framework.org/api-guide/viewsets/#marking-extra-actions-for-routing
For example:
from rest_framework.decorators import list_route
from rest_framework.response import Response
...
class MyObjectsViewSet(viewsets.ViewSet):
...
#list_route()
def locations(self, request):
queryset = get_locations()
serializer = LocationSerializer(queryset, many=True)
return Response(serializer.data)
You define method like you do now, but you need to use the same url as method name and add link decorator, so for
/myobjects/123/locations/
You add method like this
#link(permission_classes=[...])
def locations(self, request, pk=None):
...
and router will pick it automatically.
From Routing to extra methods on a ViewSet:
I think you may need to route the method by hand, i.e. The Old-Fashioned Way™.
First pull the method out as a separate view:
set_password_view = UserViewSet.as_view({'post': 'set_password'})
(or such)
Then assign your URL:
url(r'^users/username_available/$', set_password_view, name-=...)
(Or such)
There's a related question on SO.
If you want to extend a viewset with a view that is or should not directly be written inside your viewset, you can write a “wrapper” action to pass the data through.
For example, with class based views:
from somewhere import YourExternalClassView
class SomeViewSet(viewsets.ReadOnlyModelViewSet):
# ...
#action(detail=True)
def your_action(self, request, pk):
return YourExternalClassView.as_view()(request, pk=pk)
How does it work?
On class based views, the as_view method returns a view function, to which we will pass the data we received from the action. The view will then hand over to process further.
For non-class based view, the views can be called/wrapped directly without .as_view(...)(...).
I have lots of class-based views in my app. Most of them should be accessible only by authentificated staff users. How can I easylly add user check for lot of class-based views?
For standart function views I added decorator like this:
def only_staff_allowed(fn):
'''decorator'''
def wrapped(request, *args, **kwargs):
if request.user.is_staff:
return fn(request, *args, **kwargs)
else:
return HttpResponseRedirect(reverse('moderator:login'))
return wrapped
#only_staff_allowed
def dashboard(request):
''' now accessible only by staff users '''
return render(request, 'moderator/dashboard.html', {})
How can I do somthing similar to class-based views like this?
class AddressesAddList(ListView):
template_name = 'moderator/addresses/add_list.html'
queryset = Address.objects.filter(need_moderating=True)
paginate_by = 100
Should I add some mixins or override some methods? Or can I decorate something?
Actually, there are at least three ways to avoid decorating the dispatch method of each and every view class you want to require login for.
If you only have a few such views, you can either use that decorator in the URLconf, like this:
url(r"^protected/$", login_required(ProtectedView.as_view()), name="protected_view"),
Alternatively, and better if you have a bit more views to protect, is to use the LoginRequiredMixin from django-braces:
from braces.views import LoginRequiredMixin
class ProtectedView(LoginRequiredMixin, TemplateView):
template_name = 'secret.html'
And, if you have a lot of views to protect, you should use a middleware to cover a bunch of views in one fell swoop; something along the lines of:
class RequireLoginMiddleware(object):
"""Requires login for URLs defined in REQUIRED_URLS setting."""
def __init__(self):
self.urls = tuple([re.compile(url) for url in REQUIRED_URLS])
self.require_login_path = getattr(settings, 'LOGIN_URL', '/accounts/login/')
def process_request(self, request):
if not request.user.is_authenticated() and request.path != self.require_login_path:
for url in self.urls:
if url.match(request.path):
return HttpResponseRedirect(u"{0}?next={1}".format(self.require_login_path, request.path))
You should decorate the dispatch method of the class-based view. See below.
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView
class ProtectedView(TemplateView):
template_name = 'secret.html'
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(ProtectedView, self).dispatch(*args, **kwargs)
See the docs here.
You can use LoginRequiredMixin. This will redirect unauthenticated users to the page set.
from braces.views import LoginRequiredMixin
class DashboardIndex(LoginRequiredMixin, TemplateView):
template_name = 'dashboard/index.html'
login_url = 'action:login' #Where you must set the page else will use default.
raise_exception = False
https://django-braces.readthedocs.org/en/latest/access.html#loginrequiredmixin
The situation is pretty simple:
I'm writing a multi-user blog system. The system should prevent non-owner to edit or delete a blog post. In my view I use generic view.
class BlogUpdateView(UpdateView):
...
I know I should use #method_decorator to decorate dispatch method. However, most example is just #method_decorator(login_required) or model level permission. How can apply object level permission to check whether request.user is the author of this blog post?
For example, I tried to use django-authority apps, and I have a BlogPermission class in this file. and I tried to define a method in this class e.g.
def blog_edit(self, ??, ??)
what should I put into this method?
And then call this like:
#method_decorator(permission_required('blog_permission.blog_edit(???)'))
What should I pass in here?
Update: After read method_decorator code, I find it can only accept function without argument. I think that's why permission_required doesn't work here. But what's the work around about this?
Update solution:
In dispatch method, I check the user permission and then return HttpResponseForbidden() if the user does not meet the permission.
You can do it using class-based-views:
class BlogEdit(UpdateView):
model = Blog
def dispatch(self, request, *args, **kwargs):
if not request.user.has_perm('blog_permission.blog_edit'):
return HttpResponseForbidden()
return super(BlogEdit, self).dispatch(request, *args, **kwargs)
# OR (for object-level perms)
def get_object(self, *args, **kwargs):
obj = super(BlogEdit, self).get_object(*args, **kwargs)
if not obj.user == self.request.user:
raise Http404 # maybe you'll need to write a middleware to catch 403's same way
return obj
Another option is to use UserPassesTestMixin (or user_passes_test for function-based).
class UserPassesTestMixin
When using class-based views, you can use the
UserPassesTestMixin to do this.
test_func()
You have to override the test_func() method of the class to
provide the test that is performed. Furthermore, you can set any of
the parameters of AccessMixin to customize the handling of
unauthorized users:
from django.contrib.auth.mixins import UserPassesTestMixin
class MyView(UserPassesTestMixin, View):
def test_func(self):
return self.request.user.email.endswith('#example.com')
We can now check if the self.request.user is allowed to process the details passed into the self.request.GET or self.request.POST.
class MyView(UserPassesTestMixin, View):
raise_exception = True # To not redirect to the login url and just return 403. For the other settings, see https://docs.djangoproject.com/en/3.2/topics/auth/default/#django.contrib.auth.mixins.AccessMixin
def test_func(self):
return (
self.request.user.is_staff
or self.request.user.has_perm('app.change_blog')
or self.request.user.email.endswith('#company.staff.com')
or is_requested_object_accessible(self.request.user, self.request.GET, self.request.POST) # If you have a custom checker
)
...
I'm having a bit of trouble understanding how the new CBVs work. My question is this, I need to require login in all the views, and in some of them, specific permissions. In function-based views I do that with #permission_required() and the login_required attribute in the view, but I don't know how to do this on the new views. Is there some section in the django docs explaining this? I didn't found anything. What is wrong in my code?
I tried to use the #method_decorator but it replies "TypeError at /spaces/prueba/ _wrapped_view() takes at least 1 argument (0 given)"
Here is the code (GPL):
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required, permission_required
class ViewSpaceIndex(DetailView):
"""
Show the index page of a space. Get various extra contexts to get the
information for that space.
The get_object method searches in the user 'spaces' field if the current
space is allowed, if not, he is redirected to a 'nor allowed' page.
"""
context_object_name = 'get_place'
template_name = 'spaces/space_index.html'
#method_decorator(login_required)
def get_object(self):
space_name = self.kwargs['space_name']
for i in self.request.user.profile.spaces.all():
if i.url == space_name:
return get_object_or_404(Space, url = space_name)
self.template_name = 'not_allowed.html'
return get_object_or_404(Space, url = space_name)
# Get extra context data
def get_context_data(self, **kwargs):
context = super(ViewSpaceIndex, self).get_context_data(**kwargs)
place = get_object_or_404(Space, url=self.kwargs['space_name'])
context['entities'] = Entity.objects.filter(space=place.id)
context['documents'] = Document.objects.filter(space=place.id)
context['proposals'] = Proposal.objects.filter(space=place.id).order_by('-pub_date')
context['publication'] = Post.objects.filter(post_space=place.id).order_by('-post_pubdate')
return context
There are a few strategies listed in the CBV docs:
Decorate the view when you instantiate it in your urls.py (docs)
from django.contrib.auth.decorators import login_required
urlpatterns = [
path('view/',login_required(ViewSpaceIndex.as_view(..)),
...
]
The decorator is applied on a per-instance basis, so you can add it or remove it in different urls.py routes as needed.
Decorate your class so every instance of your view is wrapped (docs)
There's two ways to do this:
Apply method_decorator to your CBV dispatch method e.g.,
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
#method_decorator(login_required, name='dispatch')
class ViewSpaceIndex(TemplateView):
template_name = 'secret.html'
If you're using Django < 1.9 (which you shouldn't, it's no longer supported) you can't use method_decorator on the class, so you have to override the dispatch method manually:
from django.contrib.auth.decorators import login_required
class ViewSpaceIndex(TemplateView):
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(ViewSpaceIndex, self).dispatch(*args, **kwargs)
Use a mixin like django.contrib.auth.mixins.LoginRequiredMixin outlined well in the other answers here:
from django.contrib.auth.mixins import LoginRequiredMixin
class MyView(LoginRequiredMixin, View):
login_url = '/login/'
redirect_field_name = 'redirect_to'
Make sure you place the mixin class first in the inheritance list (so Python's Method Resolution Order algorithm picks the Right Thing).
The reason you're getting a TypeError is explained in the docs:
Note:
method_decorator passes *args and **kwargs as parameters to the decorated method on the class. If your method does not accept a compatible set of parameters it will raise a TypeError exception.
Here is my approach, I create a mixin that is protected (this is kept in my mixin library):
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
class LoginRequiredMixin(object):
#method_decorator(login_required)
def dispatch(self, request, *args, **kwargs):
return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)
Whenever you want a view to be protected you just add the appropriate mixin:
class SomeProtectedViewView(LoginRequiredMixin, TemplateView):
template_name = 'index.html'
Just make sure that your mixin is first.
Update: I posted this in way back in 2011, starting with version 1.9 Django now includes this and other useful mixins (AccessMixin, PermissionRequiredMixin, UserPassesTestMixin) as standard!
Here's an alternative using class based decorators:
from django.utils.decorators import method_decorator
def class_view_decorator(function_decorator):
"""Convert a function based decorator into a class based decorator usable
on class based Views.
Can't subclass the `View` as it breaks inheritance (super in particular),
so we monkey-patch instead.
"""
def simple_decorator(View):
View.dispatch = method_decorator(function_decorator)(View.dispatch)
return View
return simple_decorator
This can then be used simply like this:
#class_view_decorator(login_required)
class MyView(View):
# this view now decorated
For those of you who use Django >= 1.9, it's already included in django.contrib.auth.mixins as AccessMixin, LoginRequiredMixin, PermissionRequiredMixin and UserPassesTestMixin.
So to apply LoginRequired to CBV(e.g. DetailView):
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic.detail import DetailView
class ViewSpaceIndex(LoginRequiredMixin, DetailView):
model = Space
template_name = 'spaces/space_index.html'
login_url = '/login/'
redirect_field_name = 'redirect_to'
It's also good to keep in mind GCBV Mixin order: Mixins must go on the left side, and the base view class must go in the right side. If the order is different you can get broken and unpredictable results.
I realise this thread is a bit dated, but here's my two cents anyway.
with the following code:
from django.utils.decorators import method_decorator
from inspect import isfunction
class _cbv_decorate(object):
def __init__(self, dec):
self.dec = method_decorator(dec)
def __call__(self, obj):
obj.dispatch = self.dec(obj.dispatch)
return obj
def patch_view_decorator(dec):
def _conditional(view):
if isfunction(view):
return dec(view)
return _cbv_decorate(dec)(view)
return _conditional
we now have a way to patch a decorator, so it will become multifunctional. This effectively means that when applied to a regular view decorator, like so:
login_required = patch_view_decorator(login_required)
this decorator will still work when used the way it was originally intended:
#login_required
def foo(request):
return HttpResponse('bar')
but will also work properly when used like so:
#login_required
class FooView(DetailView):
model = Foo
This seems to work fine in several cases i've recently come across, including this real-world example:
#patch_view_decorator
def ajax_view(view):
def _inner(request, *args, **kwargs):
if request.is_ajax():
return view(request, *args, **kwargs)
else:
raise Http404
return _inner
The ajax_view function is written to modify a (function based) view, so that it raises a 404 error whenever this view is visited by a non ajax call. By simply applying the patch function as a decorator, this decorator is all set to work in class based views as well
Use Django Braces. It provides a lot of useful mixins that is easily available.
It has beautiful docs. Try it out.
You can even create your custom mixins.
http://django-braces.readthedocs.org/en/v1.4.0/
Example Code:
from django.views.generic import TemplateView
from braces.views import LoginRequiredMixin
class SomeSecretView(LoginRequiredMixin, TemplateView):
template_name = "path/to/template.html"
#optional
login_url = "/signup/"
redirect_field_name = "hollaback"
raise_exception = True
def get(self, request):
return self.render_to_response({})
In my code I have written this adapter to adapt member functions to a non-member function:
from functools import wraps
def method_decorator_adaptor(adapt_to, *decorator_args, **decorator_kwargs):
def decorator_outer(func):
#wraps(func)
def decorator(self, *args, **kwargs):
#adapt_to(*decorator_args, **decorator_kwargs)
def adaptor(*args, **kwargs):
return func(self, *args, **kwargs)
return adaptor(*args, **kwargs)
return decorator
return decorator_outer
You can simply use it like this:
from django.http import HttpResponse
from django.views.generic import View
from django.contrib.auth.decorators import permission_required
from some.where import method_decorator_adaptor
class MyView(View):
#method_decorator_adaptor(permission_required, 'someapp.somepermission')
def get(self, request):
# <view logic>
return HttpResponse('result')
If it's a site where the majority of pages requires the user to be logged in, you can use a middleware to force login on all views except some who are especially marked.
Pre Django 1.10 middleware.py:
from django.contrib.auth.decorators import login_required
from django.conf import settings
EXEMPT_URL_PREFIXES = getattr(settings, 'LOGIN_EXEMPT_URL_PREFIXES', ())
class LoginRequiredMiddleware(object):
def process_view(self, request, view_func, view_args, view_kwargs):
path = request.path
for exempt_url_prefix in EXEMPT_URL_PREFIXES:
if path.startswith(exempt_url_prefix):
return None
is_login_required = getattr(view_func, 'login_required', True)
if not is_login_required:
return None
return login_required(view_func)(request, *view_args, **view_kwargs)
views.py:
def public(request, *args, **kwargs):
...
public.login_required = False
class PublicView(View):
...
public_view = PublicView.as_view()
public_view.login_required = False
Third-party views you don't want to wrap can be made excempt in the settings:
settings.py:
LOGIN_EXEMPT_URL_PREFIXES = ('/login/', '/reset_password/')
It has been a while now and now Django has changed so much.
Check here for how to decorate a class-based view.
https://docs.djangoproject.com/en/2.2/topics/class-based-views/intro/#decorating-the-class
The documentation did not include an example of "decorators that takes any argument". But decorators that take arguments are like this:
def mydec(arg1):
def decorator(func):
def decorated(*args, **kwargs):
return func(*args, **kwargs) + arg1
return decorated
return deocrator
so if we are to use mydec as a "normal" decorator without arguments, we can do this:
mydecorator = mydec(10)
#mydecorator
def myfunc():
return 5
So similarly, to use permission_required with method_decorator
we can do:
#method_decorator(permission_required("polls.can_vote"), name="dispatch")
class MyView:
def get(self, request):
# ...
I've made that fix based on Josh's solution
class LoginRequiredMixin(object):
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(LoginRequiredMixin, self).dispatch(*args, **kwargs)
Sample usage:
class EventsListView(LoginRequiredMixin, ListView):
template_name = "events/list_events.html"
model = Event
This is super easy with django > 1.9 coming with support for PermissionRequiredMixin and LoginRequiredMixin
Just import from the auth
views.py
from django.contrib.auth.mixins import LoginRequiredMixin
class YourListView(LoginRequiredMixin, Views):
pass
For more details read Authorization in django
If you are doing a project which requires variety of permission tests, you can inherit this class.
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import user_passes_test
from django.views.generic import View
from django.utils.decorators import method_decorator
class UserPassesTest(View):
'''
Abstract base class for all views which require permission check.
'''
requires_login = True
requires_superuser = False
login_url = '/login/'
permission_checker = None
# Pass your custom decorator to the 'permission_checker'
# If you have a custom permission test
#method_decorator(self.get_permission())
def dispatch(self, *args, **kwargs):
return super(UserPassesTest, self).dispatch(*args, **kwargs)
def get_permission(self):
'''
Returns the decorator for permission check
'''
if self.permission_checker:
return self.permission_checker
if requires_superuser and not self.requires_login:
raise RuntimeError((
'You have assigned requires_login as False'
'and requires_superuser as True.'
" Don't do that!"
))
elif requires_login and not requires_superuser:
return login_required(login_url=self.login_url)
elif requires_superuser:
return user_passes_test(lambda u:u.is_superuser,
login_url=self.login_url)
else:
return user_passes_test(lambda u:True)
Here the solution for permission_required decorator:
class CustomerDetailView(generics.GenericAPIView):
#method_decorator(permission_required('app_name.permission_codename', raise_exception=True))
def post(self, request):
# code...
return True