I keep getting a reverse error when i try to redirect from a DetailView and CreateView. I keep getting object has no attribute pk. I have equally tried using : args=[str(self.id)]) but i still get the error.
class check (DetailView)
def get(self, request, *args, **kwargs):
if...:
return reverse('no_edit', kwargs={"pk": self.pk})
self is the DetailView object, which indeed has no primary key. If you want to access the object, you normally can use self.object, but since you have overwritten the get method itself, that will not work either.
You can fix it by calling self.get_object() here, like:
from django.shortcuts import redirect
class CheckView(DetailView):
# …
def get(self, request, *args, **kwargs):
self.object = self.get_object()
if …:
return redirect('no_edit', pk=self.object.pk)
We can here make use of redirect(..) [Django-doc]. This will construct a HttpResponseRedirect with the result of a reverse call.
You're not returning a redirect, just an URL, try doing something like
return HttpResponseRedirect(reverse(...))
I'm trying to override the render_to_response method in TemplateView to include an additional parameter for the reponse_class for the HTTP status, but having trouble using:
class ErrorView(TemplateView):
''' Inserts http status code into response '''
status = None
def render_to_response(self, context, **response_kwargs):
if self.status is None:
raise ImproperlyConfigured("ErrorView requires definition of status")
return super(ErrorView,self).render_to_response(context,{'status': self.status})
class Error404View(ErrorView):
template_name = '404.html'
status = 404
The render_to_response method (from TemplateResponseMixin) is defined with three parameters:
def render_to_response(self, context, **response_kwargs)
However, when TemplateView calls it from the get method, it only passes the context:
return self.render_to_response(context)
How can I pass response_kwargs to render_to_response?
Why not create your own ErrorTemplateView and override get method. Since you cannot reuse get method from TemplateView for your use case.
class ErrorTemplateView(TemplateView):
status = None
def get(self, request, *args, **kwargs):
if self.status is None:
raise ImproperlyConfigured("ErrorTemplateView requires definition of status")
context = self.get_context_data(**kwargs)
return self.render_to_response(context, status=self.status)
By the way if you need to customize error views, did you check this from docs?
Suppose I have a url pattern
url(r'^/my_app/class/(?P<class_id>\d+)/$', my_class.my_class, name='my_class')
For a given url
http://example.com/my_app/class/3/, I'd like to get class_id.
I can do this with regex myself.
I am wondering if there's a utility function for this since Django is already doing this to resolve url to a view.
There is an example of using resolve() function in Django docs. Value of next variable has HTTP url to be parsed with urlparse() / resolve():
https://docs.djangoproject.com/en/1.11/ref/urlresolvers/#resolve
from django.urls import resolve
from django.http import HttpResponseRedirect, Http404
from django.utils.six.moves.urllib.parse import urlparse
def myview(request):
next = request.META.get('HTTP_REFERER', None) or '/'
response = HttpResponseRedirect(next)
# modify the request and response as required, e.g. change locale
# and set corresponding locale cookie
view, args, kwargs = resolve(urlparse(next)[2])
kwargs['request'] = request
try:
view(*args, **kwargs)
except Http404:
return HttpResponseRedirect('/')
return response
If you are using generic views or just views, you can do something like this:
class myView(View): # or UpdateView, CreateView, DeleteView
template_name = 'mytemplate.html'
def get(self, request, *args, **kwargs):
context = {}
class_id = self.kwargs['class_id']
# do something with your class_id
return render(request, self.template_name, context)
# same with the post method.
Yes, you can do like this
def my_class(request, class_id):
# this class_id is the class_id in url
# do something;
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
What I'm trying to do is Django boilerplate for functional views. Any help here is very much appreciated, as the docs show examples for the template view and list view, but I've found very little for the model-based generic views. Am I missing an example in the docs?
I have a model that represents an entry in a calendar. There's a foreign key to another object (not a user) that owns the entry. What I want to do is simply to create the entry, ensuring that the entry's foreign key is properly set and then return the user to the appropriate calendar page.
I don't know, though, how class-based generic views receive their URL arguments and I'm not clear on how to set the success_url so that it reuses the id that was originally passed to the creation URL. Again, thank you in advance for your help.
What I'm asking, essentially, is, what is the class-based generic view equivalent of the following:
def create_course_entry(request, class_id):
'''Creates a general calendar entry.'''
if request.method == 'POST':
form = CourseEntryForm(request.POST)
if form.is_valid():
new_entry = form.save(commit=False)
new_entry.course = Class.objects.get(pk=class_id)
new_entry.full_clean()
new_entry.save()
return HttpResponseRedirect('/class/%s/calendar/' % class_id)
else:
form = CourseEntryForm()
return render_to_response('classes/course_entry_create.html',
{ 'class_id': class_id, 'form': form, },
context_instance=RequestContext(request))
You could subclass the edit.CreateView generic view, set the class/course in the dispatch() method, and save this by overriding the form_valid() method:
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.views.generic.edit import CreateView
class CourseEntryCreateView(CreateView):
form_class = CourseEntryForm
model = CourseEntry
def dispatch(self, *args, **kwargs):
self.course = get_object_or_404(Class, pk=kwargs['class_id'])
return super(CourseEntryCreateView, self).dispatch(*args, **kwargs)
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.course = self.course
self.object.save()
return HttpResponseRedirect(self.get_success_url())
If you're not customising the CourseEntryForm ModelForm, then you can leave out the form_class property.
Unfortunately, it is not possible to call super() in the form_valid() method - due to the way it has been written would mean the object would be saved again.
If you need the Class (course?) instance in the template context, then you can add this in the get_context_data() method:
def get_context_data(self, *args, **kwargs):
context_data = super(CourseEntryCreateView, self).get_context_data(
*args, **kwargs)
context_data.update({'course': self.course})
return context_data
An alternative to Matt Austin's answer might be to override the get_form method:
from django.shortcuts import get_object_or_404
from django.views.generic import CreateView
class CourseEntryCreateView(CreateView):
form_class = CourseEntryForm
model = CourseEntry
def get_form(self, form_class):
form = super(CustomCreateView, self).get_form(form_class)
course = get_object_or_404(Class, pk=self.kwargs['class_id'])
form.instance.course = course
return form
This way, .course is on the CourseEntry instance in the context, and on the instance created when the form is saved upon POST.