Class-based view delegate to another view - django

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

Related

#permission_required decorator returns no user attribute in View error

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.

Customize PasswordResetConfirmView

I'm trying to set a user is_active state to True when the user have clicked on the reset-password link I've emailed them. However, I don't understand how to get access to the PasswordResetConfirmView, the code below don't do any prints when I go to the related URL.
Any ideas on how I should do this?
I've read the source code over here: https://github.com/django/django/blob/main/django/contrib/auth/views.py
But I don't really understand how I should "intercept" the view and add the operations I want to do and then let it keep going.
from django.contrib.auth import views as auth_views
class PasswordResetConfirmView(auth_views.PasswordResetConfirmView):
print("Request view")
def get(self, request, *args, **kwargs):
print(request)
print(request.user)
return super().get(request, *args, **kwargs)
This is the related URL
path('reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(template_name="main/password/password_reset_confirm.html"), name='password_reset_confirm'),
EDIT:
Also tried adjusting the loginview, but got the same problem. I think I'm mistunderstand how things work behind the hood.
class LoginUser(auth_views.LoginView):
print("test")
def get(self, request, *args, **kwargs):
print("test")
return super(LoginUser, self).get(request, *args, **kwargs)
def get_success_url(self):
return resolve_url('accounts:login')
You can override the SetPasswordForm, and activate the user object:
from django.contrib.auth.forms import SetPasswordForm
class MySetPasswordForm(SetPasswordForm):
def save(self, *args, commit=True, **kwargs):
user = super().save(*args, commit=False, **kwargs)
user.is_active = True
if commit:
user.save()
return user
Then we can use this as our MySetPasswordForm:
path(
'reset/<uidb64>/<token>/',
views.PasswordResetConfirmView.as_view(form_class=MySetPasswordForm),
name='password_reset_confirm'
),

How can perform a task from superuser in django

I am trying to perform an action from superuser accept/reject the task, but after login from superuser it show the error. even if i logged in from non superuser if show the same error
403 Forbidden
i am trying first time perform action from superuser i don't know how can i fix this issue
View.py
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
class Approval(LoginRequiredMixin, UserPassesTestMixin, TemplateView):
def test_func(self):
if self.request.user == User.is_superuser:
return True
else:
return False
template_name = 'approve.html'
def get(self, request, *args, **kwargs):
return render(request, self.template_name)
def post(self, request):
Urls.py
urlpatterns = [
path('approve',Approval.as_view(), name='approve')
]
You check if the user is a superuser with:
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
class Approval(LoginRequiredMixin, UserPassesTestMixin, TemplateView):
template_name = 'approve.html'
def test_func(self):
return self.request.user.is_superuser
def get(self, request, *args, **kwargs):
return render(request, self.template_name, {'all_saloon': all_saloon})
The all_saloon is however strange: it means that if it is a list or QuerySet it will each time work with the same data, and thus if later a new Saloon is constructed, it will not take that into account.
You can alter the handle_no_permission function to determine what to do in case the test fails:
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.shortcuts import redirect
class Approval(LoginRequiredMixin, UserPassesTestMixin, TemplateView):
template_name = 'approve.html'
def test_func(self):
return self.request.user.is_superuser
def handle_no_permission(self):
return redirect('name-of-some-view')
def get(self, request, *args, **kwargs):
return render(request, self.template_name, {'all_saloon': all_saloon})
Likely you want to work with a ListView [Django-doc] instead.

DRF, caching for as_view()?

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)

Use custom function as a view function in Class Based Views in django

I have a class-based view like this:
class MyView(View):
def dispatch(self, request, *args, **kwargs):
return super(MyView, self).dispatch(request, *args, **kwargs)
def get(self, request):
return HttpResponse('Get method')
And in urls.py I refer to this view like this:
urlpatterns = [
url(r'^$', MyView.as_view(), name='index'),
]
Now, I want to create a custom view function within MyView and use it in urlpatterns. Something like this:
class MyView(View):
def dispatch(self, request, *args, **kwargs):
return super(MyView, self).dispatch(request, *args, **kwargs)
def get(self, request):
return redirect(reverse('auth:index'))
def custom(self, request):
return HttpResponse('Custom')
And in urls.py:
urlpatterns = [
url(r'^$', MyView.as_view(), name='index'),
url(r'^/custom/$', MyView.custom(), name='custom'),
]
Is it possible to do?