Django Template Context Processor with Class Based Views - django

I have a Login Class Based View which I want to include in all my pages.
Is there a way to include Class Based View as template context processor, or do we have any other way to include in all pages ?
class LoginView(RedirectAuthenticatedUserMixin, FormView):
form_class = LoginForm
template_name = "account/login.html"
success_url = None
redirect_field_name = "next"
def form_valid(self, form):
success_url = self.get_success_url()
return form.login(self.request, redirect_url=success_url)
def get_success_url(self):
# Explicitly passed ?next= URL takes precedence
ret = (get_next_redirect_url(self.request,
self.redirect_field_name)
or self.success_url)
return ret
def get_context_data(self, **kwargs):
ret = super(LoginView, self).get_context_data(**kwargs)
signup_url = passthrough_next_redirect_url(self.request,
reverse("account_signup"),
self.redirect_field_name)
redirect_field_value = self.request.REQUEST \
.get(self.redirect_field_name)
ret.update({"signup_url": signup_url,
"site": Site.objects.get_current(),
"redirect_field_name": self.redirect_field_name,
"redirect_field_value": redirect_field_value})
return ret
login = LoginView.as_view()

You can decorate the view:
Either in urls.py:
from django.contrib.auth.decorators import login_required, permission_required
from django.views.generic import TemplateView
from .views import VoteView
urlpatterns = patterns('',
(r'^about/', login_required(TemplateView.as_view(template_name="secret.html"))),
(r'^vote/', permission_required('polls.can_vote')(VoteView.as_view())),
)
Or in views.py:
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)
Or, you can inherit from LoginRequiredMixin from django-braces:
from braces.views import LoginRequiredMixin
class Index(LoginRequiredMixin, TemplateView):
template_name = 'sekret.html'
All these examples show how to require authentication for class based views (which I believe is what you are trying to do). The first two are directly from the documentation.
Once you implement either of the above examples, your application will behave like this:
A user enters a URL that maps to one of the above views.
django middleware checks if the user is logged in.
If not, django will redirect to LOGIN_URL, by default its /accounts/login/, and add a ?next parameter, pointing to the original URL from #1.
The view from #3 will display a login form.
Once the user successfully authenticates, the view from #3 will update the session, and redirect the user to the URL from the next parameter.
If the user is logged in, then the decorated view will be executed as normal.

Related

superuser authenticate in class based view

I am working on blog project in which I added an add post which add post now I want only the superuser can add post and that page is visible only to superuser.
1st Method
Views.py
class AddPostView(CreateView):
model = Post
template_name = 'MainSite/add_post.html'
fields = '__all__'
this is my current view I am able to achieve authenticate for superuser using 2nd method
2nd Method
class AddPostView(View):
def get(self,request):
if request.user.is_superuser == True:
return render(...)
else:
pass
How can I achieve the same result using 1st method.I tried using LoginRequiredMixin but nothing is happening . I just import LoginRequiredMixin and use it like this .
class Addpost(CreateView,LoginRequiredMixin):
...
Thanks in advance and advice will be helpful.
You can work with a UserPassesTestMixin mixin [Django-doc]:
from django.contrib.auth.mixins import UserPassesTestMixin
class AddPostView(UserPassesTestMixin, CreateView):
# …
def test_func(self):
return self.request.user.is_superuser
# …
You can encapsulate this in a mixin:
from django.contrib.auth.mixins import UserPassesTestMixin
class AdminRequiredMixin(UserPassesTestMixin):
def test_func(self):
return self.request.user.is_superuser
and then use this mixin:
class AddPostView(AdminRequiredMixin, CreateView):
# …
def test_func(self):
return self.request.user.is_superuser
# …
Mixins should be put before the actual view in the inheritance hierarchy: otherwise these appear after the view in the method resolution order (MRO), and thus likely will not override the behavior (correctly).
class AddPostView(CreateView,LoginRequiredMixin):
model = Post
template_name = 'MainSite/add_post.html'
fields = '__all__'
def dispatch(self, request, *args, **kwargs):
if request.user.is_anonymous:
return redirect_to_login(self.request.get_full_path(), self.get_login_url(), self.get_redirect_field_name())
elif request.user.is_superuser:
return render(.....)
else
return super(AddPostView, self).dispatch(request, *args, **kwargs)
Use method_decorator and user_passes_test to achieve this
from django.views.generic import View
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import user_passes_test
class AddPostView(View):
#method_decorator(user_passes_test(lambda u: u.is_superuser))
def post(self, *args, **kwargs):
pass

how do I add template conditions in the ListView class?

I have a ListView class in views.py, I want to add a condition if the authenticated user displays another template
urls.py
from django.urls import path, include
from django.contrib.auth import views as auth_views
from .views import (
PostListView,
)
urlpatterns = [
path('', PostListView.as_view(), name='index'),
]
Views.py
from django.shortcuts import render, get_object_or_404
from django.views.generic import (
ListView,
)
from .models import Post
from django.contrib.auth.models import User
from django.contrib.auth import authenticate
class PostListView(ListView):
model = Post
template_name = 'page/index.html'
context_object_name = 'posts'
ordering = ['-date_posted']
paginate_by = 7
i want to add
if self.request.user.is_authenticated:
template_name = 'page/index.html'
else:
template_name = 'page/home.html'
Django 2.2.x
You can override the get_template_names function [Django-doc]:
class PostListView(ListView):
model = Post
context_object_name = 'posts'
ordering = ['-date_posted']
paginate_by = 7
def get_template_names(self):
if self.request.user.is_authenticated:
return ['page/index.html']
else:
return ['page/home.html']
As the documentation says, this function:
Returns a list of template names to search for when rendering the template. The first template that is found will be used.
If template_name is specified, the default implementation will return a list containing template_name (if it is specified).
That being said, if you do not plan to render the list on your home.html page, it might be better to perform a redirect to another page, instead of just rendering a page. Otherwise, if you later want to add more content to your home.html page, you will each time need to update all the views that render this.
The basic implementation [GitHub] in the TemplateResponseMixin [Django-doc] is thus:
def get_template_names(self):
"""
Return a list of template names to be used for the request. Must return
a list. May not be called if render_to_response() is overridden.
"""
if self.template_name is None:
raise ImproperlyConfigured(
"TemplateResponseMixin requires either a definition of "
"'template_name' or an implementation of 'get_template_names()'")
else:
return [self.template_name]

Django - Sending emails using class based view

I have been making a website containing a listview and formview. I have a form.py which looks like this :
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(required=True)
email = forms.EmailField(required=True)
message = forms.CharField(required=True)
and the views.py :
from django.shortcuts import render
from .forms import ContactForm
from django.views.generic import ListView
from django.views.generic.edit import FormMixin
from blog.models import Post
from django.core.mail import EmailMessage
class PostListAndFormView(FormMixin,ListView):
queryset = Post.objects.all().order_by("-date")[:2]
template_name = 'personal/index.html'
form_class = ContactForm
success_url = 'personal/index.html'
This view also deals with a Listview functionality which you can ignore.
My HTML template is:
<form action="/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="SEND MESSAGE" />
</form>
Finally urls.py :
from django.conf.urls import url,include
from . import views
from homepage.views import PostListAndFormView
urlpatterns = [
url(r'^$', PostListAndFormView.as_view(), name='PostListAndFormView'),
]
What I want to do here is take the data from the form and send an email to my address with the entered data. Someone help me do this.
Don't know why you mixed up listview with formview. From your model it's kind a blog app. Normally in a blog app the articles/posts list page doesn't contain any form with email field, except for article detail or Contact Us page. I prefer to split it into different class than using mixin.
My answer based on Daniel Greenfeld's example here with little bit modification.
In yourapp/forms.py:
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
import floppyforms as forms
class ContactForm(forms.Form):
name = forms.CharField(required=True)
email = forms.EmailField(required=True)
subject = forms.CharField(required=True)
message = forms.CharField(widget=forms.Textarea)
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.add_input(Submit('submit', 'Submit'))
super(ContactForm, self).__init__(*args, **kwargs)
In yourapp/views.py:
from django.views.generic.list import ListView
from django.views.generic.edit import FormView
from django.conf import settings
from django.core.mail import send_mail
from yourapp.models import Post
from yourapp.forms import ContactForm
class PostListView(ListView):
model = Post
def get_context_data(self, **kwargs):
context = super(ArticleListView, self).get_context_data(**kwargs)
context['latest_articles'] = Post.objects.all()[:5]
return context
class ContactFormView(FormView):
form_class = ContactForm
template_name = "myapp/email_form.html"
success_url = '/email-sent/'
# this is what you want
def form_valid(self, form):
message = "{name} / {email} said: ".format(
name=form.cleaned_data.get('name'),
email=form.cleaned_data.get('email'))
message += "\n\n{0}".format(form.cleaned_data.get('message'))
send_mail(
subject=form.cleaned_data.get('subject').strip(),
message=message,
from_email='contact-form#myapp.com',
recipient_list=[settings.LIST_OF_EMAIL_RECIPIENTS],
)
return super(ContactFormView, self).form_valid(form)
Have a look at the documentation, check the methods of the FormMixin and pick the one that fits.
form_valid() might be an option.
in python3:
def form_valid(self, form):
# do your stuff
# call the parents class method
return super().form_valid(form)
This is a quite common approach when using class based views. They usually provide a bunch of attributes and methods - sometimes it is enough to just change some attributes, which change the behavior of the methods (e.g. success_url). But often you will need to override some of there methods. It is always a good idea to read their code in this case, cause you need to decide whether you want to call the mixins implementation at the beginning, at the end (as in the example) or if you really want to override it and provide their logic on your own...

Django #login_required for class views

I inherited a Django(1.5.1) project and I need to put one view behind a #login_required decorator. Here is what i have in views.py:
I got this snippet of code from here and it looks like its purpose is to allow someone to apply the #login_requireddecorator to a class
class LoginRequiredMixin(object):
"""
View mixin which verifies that the user has authenticated.
NOTE:
This should be the left-most mixin of a view.
"""
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(LoginRequiredMixin, self).dispatch(*args, **kwargs)
class PermissionRequiredMixin(object):
login_url = settings.LOGIN_URL
permission_required = None
raise_exception = False
redirect_field_name = '/workers/'
def dispatch(self, request, *args, **kwargs):
# Verify class settings
if self.permission_required == None or len(
self.permission_required.split(".")) != 2:
raise Error("'PermissionRequiredMixin' requires "
"'permission_required' attribute to be set.")
has_permission = request.user.has_perm(self.permission_required)
if not has_permission:
if self.raise_exception:
return HttpResponseForbidden()
else:
path = urlquote(request.get_full_path())
tup = self.login_url, self.redirect_field_name, path
return HttpResponseRedirect("%s?%s=%s" % tup)
return super(PermissionRequiredMixin, self).dispatch(
request, *args, **kwargs)
I then apply this to the view i want to add permissions to like so:
class RootWorkerView(LoginRequiredMixin, PermissionRequiredMixin, APIView):
renderer_classes = (WorkersJSONRenderer, JSONRenderer,
BrowsableAPIRenderer)
def get(self, request):
worker_list = rest_models.WorkerList(request)
serializer = WorkerListSerializer(worker_list)
return Response(serializer.data)
The APIView argument is a carry over, as before it was the only argument. Is this correct?
When run, I get nothing. The template for the view I want to secure shows up with no login prompt.
Relevant snippet from urls.py:
url(r'^workers/$', views.RootWorkerView.as_view(),
name='root_worker_view'),
url(r'^login/$', 'django.contrib.auth.views.login',
{'template_name': 'dashboard/login.html'}),
/login/ does work, and I can login successful, so that's not the issue.
I feel like #method_decorator(login_required) isnt doing its job. Any ideas?
You can add the decorator in the urls.py
from django.contrib.auth.decorators import login_required
url(r'^workers/$', login_required(views.RootWorkerView.as_view()))
This worked for me.
now you can use Django builtin LoginRequiredMixin
from django.contrib.auth.mixins import LoginRequiredMixin
class MyView(LoginRequiredMixin, View):
login_url = '/login/'
redirect_field_name = 'redirect_to'
https://docs.djangoproject.com/en/3.2/topics/auth/default/#the-loginrequired-mixin

Problems importing mixin into another app for apply to Class Based View

I have the file userprofiles/mixins.py in which I've created this mixin
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
class LoginRequiredMixin(object):
#method_decorator(login_required(login_url = '/login/'))
def dispatch(self, request, *args, **kwargs):
return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)
In my file userprofiles/views.py I have the following class based view named ProfileView of this way:
from .mixins import LoginRequiredMixin
class ProfileView(LoginRequiredMixin,TemplateView):
template_name = 'profile.html'
def get_context_data(self, **kwargs):
context = super(ProfileView, self).get_context_data(**kwargs)
if self.request.user.is_authenticated():
context.update({'userprofile': self.get_userprofile()})
return context
def get_userprofile(self):
return self.request.user.userprofile
In this class based view named ProfileView I could inherit from LoginRequiredMixin without any trouble
These mixin LoginRequiredMixin I also applied to the class based view named AlbumListView which is located in other module or app artists/views.py.
The class based view AlbumListView is this:
from sfotipy.userprofiles.mixins import LoginRequiredMixin
class AlbumListView(LoginRequiredMixin,ListView):
model = Album
template_name = 'album_list.html'
def get_queryset(self):
if self.kwargs.get('artist'):
queryset = self.model.objects.filter(artist__slug__contains=self.kwargs['artist'])
else:
queryset = super(AlbumListView, self).get_queryset()
return queryset
The unique way for my IDE don't mark error when I import the LoginRequiredMixin for I inherit from it is of this way:
from sfotipy.userprofiles.mixins import LoginRequiredMixin
I know that this import way is not correct, because is a absolute import and the right way is doing a relative import.
Other way in where should work is this:
from userprofiles.mixins import LoginRequiredMixin
But, when I want test I get the following error message...
How to can I do this import and that works?
Thanks for the orientation :D