I am new to Django
I am trying to convert my function-based views to class-based views. Here I ran into a problem.
I don't know whether the user is logged in or not. I can't call the user.is_authenticated inside my class-based view.
My Code:
class UserLoginView(FormView):
template_name = 'login.html'
form_class = UserLoginForm
success_url = reverse_lazy('login')
def form_valid(self, form):
user = authenticate(username=form.cleaned_data['username'], password=form.cleaned_data['password'])
if user is not None:
login(request=self.request, user=user)
print('Login Successfull')
return HttpResponseRedirect(self.success_url)
def form_invalid(self, form):
print('Login Failed')
return HttpResponseRedirect(self.success_url)
How can I check whether the user is already logged in and send him directly to the home page.
Thanks in advance.
As your requirement, you want to authenticate a user and send them to the home page after logged-in in a class-based view.
Here is what we can do. We can use the LoginRequiredMixin in your class-based home page view to help us to check is a user logged-in. If a user is not logged-in, they will be redirected to a login page we specified. Otherwise, execute the view normally and the user will be free to access the home page.
Example:
In views.py
from django.contrib.auth.mixins import LoginRequiredMixin
class HomeView(LoginRequiredMixin): # Add the LoginRequiredMixin
template_name = 'index.html'
login_url = '/login/' # Replace '/login/' with your login URL, an un-logged-in user will be redirect to this URL
One thing must care about while using the LoginRequiredMixin is the ordering.
Mostly we put the LoginRequiredMixin in the first position of inheritance if our class-based view inherited multiple classes. Because it makes sure the user is logged-in before the view does anything further for the user.
class HomeView(LoginRequiredMixin, ClassA, ClassB):
pass
You can get more information about LoginRequiredMixin in this page
Related
I am converting my project from function-based view to class-based view. In a view function, I can check if a user is a superuser using request.user.is_superuser() function. I can check if a user is logged in by inheriting LoginRequiredMixin in a View class, I want to know if there is any similar way that can be used for checking if the user is a superuser in a View class. I want a Django app only accessible by the superusers of the site.
You can create your own :
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
class SuperUserRequiredMixin(LoginRequiredMixin, UserPassesTestMixin):
def test_func(self):
return self.request.user.is_superuser
and then instead of using LoginRequiredMixin in your ClassBasedView you use your SuperUserRequiredMixin
Now your view will only allow logged-in superuser.
He is an example use case of what you are trying to accomplish. You need self.request.user.is_superuser.
class ExampleClassView(LoginRequiredMixin,TemplateView):
template_name = "core/index.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["is_super"] = self.request.user.is_superuser
return context
I'm trying to implement class Based views with permissions and they do not seem to connect, although I believe I strictly followed Django User's guide.
First: set up of a Custom User model, based on Proxies, in accounts.models
class CustomUser(AbstractUser):
some_fields...
Then, I created a Manager:
class EmployeeManager(models.Manager):
def get_queryset(self, *args, **kwargs):
return super().get_queryset(*args, **kwargs).filter(status_type=CustomUser.StatusType.EMPLOYEE)
Followed by the type of profile:
class Employee(CustomUser):
objects = EmployeeManager()
class Meta:
proxy = True
permissions = [("communities.view_region", "Can view region")]
Where I set a permission, make the migrations and migrate.
After, I create the view:
import communities.models as comms
class RegionsListView(ListView):
model = comms.Region
Then, configuration of the url and its view:
rom django.urls import path, include
import communities.views as views
from django.contrib.auth.decorators import permission_required
app_name = 'communities'
urlpatterns = [
path("regions/list/", permission_required("communities.view_region")(views.RegionsListView.as_view()))
Then I log in as an employee and I get an error 403 when calling this url.
What did I miss ?
Remarks:
using permission_required = 'communities.view_region' in the view.py file produces the same result.
when logging as a superuser, I get of course the right page.
In order to implement the permissions, it had to be done programmatically, while creating a new user.
In the workflow,
the new User gets an activation e-mail with a unique link,
the click gives him access to the website and he is required to immediately change his password,
the validation implements the permission (in this case, a Group)
Here is the code.
from django.contrib import messages
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.forms import PasswordChangeForm
from django.shortcuts import redirect, render
from django.contrib.auth.models import Group
#login_required
def change_password(request):
if request.method == "POST":
form = PasswordChangeForm(user=request.user, data=request.POST)
if form.is_valid():
user = form.save()
# Attributes to a user a group depending on his status.
user.groups.add(Group.objects.get(name=user.status_type))
update_session_auth_hash(request, user) # Important!
messages.success(request, 'Your PWD has been changed')
return redirect('change_password')
else:
messages.error(request, 'Please Correct the Error')
else:
form = PasswordChangeForm(request.user)
return render(request, 'accounts/change_password.html', {'form': form})
I am using Django Generic view, DetailView.
But I'd like to block users to access to detail post who did not email_confirmed yet.
I have a email_confirmed field in User model.
My code is :
#method_decorator(login_required(login_url='/login/'), name='dispatch')
class RecruitView(generic.DetailView):
model = Recruit
template_name = 'recruit.html'
and I want to add :
if not request.user.email_confirmed:
error_message = "you did not confirmed yet. please check your email."
return render(request, 'info.html', {'error_message': error_message})
else: pass
How can I add this condition to DetailView?
(I tried to override 'as_view' but I don't know how to do it)
I would use the PermissionRequiredMixin. With this you can specify specific permissions users need to have or override the has_permission method.
from django.contrib.auth.mixins import PermissionRequiredMixin
class RecruitView(PermissionRequiredMixin, generic.DetailView):
...
login_url = '/login/'
permission_denied_message = 'you did not confirmed yet. please check your email.'
def has_permission(self):
return self.request.user.email_confirmed
This will redirect users without the email_confirmed to the login_url where you can display the error message. In order to use the index.html template instead you might need to override the handle_no_permission method.
I'm new to Django and writing an application in Django 1.11.
I want to create a Profile update page.
I have created an app accounts to manage all profile related activities and created a class
from django.contrib.auth.models import User
# Create your views here.
from django.views.generic import TemplateView, UpdateView
class ProfileView(TemplateView):
template_name = 'accounts/profile.html'
class ChangePasswordView(TemplateView):
template_name = 'accounts/change_password.html'
class UpdateProfile(UpdateView):
model = User
fields = ['first_name', 'last_name']
template_name = 'accounts/update.html'
and in myapp/accounts/urls.py
from django.conf.urls import url
from . import views
app_name = 'accounts'
urlpatterns = [
url(r'^$', views.ProfileView.as_view(), name='profile'),
url(r'^profile/', views.ProfileView.as_view(), name='profile'),
url(r'^change_password/', views.ChangePasswordView.as_view(), name='change_password'),
url(r'^update/', views.UpdateProfile.as_view(), name='update'),
url(r'^setting/', views.SettingView.as_view(), name='setting')
]
When I access 127.0.0.1:8000/accounts/update, It gives
AttributeError at /accounts/update/
Generic detail view UpdateProfile must be called with either an object pk or a slug.
Since, I want the logged in user to edit his/her profile information. I don't want to pass pk in the url.
How to create profile update page in Django 1.11?
class UpdateProfile(UpdateView):
model = User
fields = ['first_name', 'last_name']
template_name = 'accounts/update.html'
def get_object(self):
return self.request.user
As the error told you, you have to return a pk or slug if you're not precising the object. So by overridding the get_object method, you can tell to django which object you want to update.
If you prefer to do it on another way, you can send the pk or slug of the object in the url :
url(r'^update/(?P<pk>\d+)', views.UpdateProfile.as_view(), name='update')
Here the default get_object method will catch the pk in the args and find the user you want to update.
Note that the first method works only (as i wrote it) if a user want to update his profile and is authenticated (self.request.user) and the second way allows you to actually update whatever user you want, as soon as you have the pk of this user (accounts/update/1, will update user with the pk=1, etc...).
Some doc here, get_object() section
Returns the object the view is displaying.
By default this requires self.queryset and a pk or slug argument
in the URLconf, but subclasses can override this to return any object.
I am building a small application which needs user profiles, I've used the build in user system from Django. But I have a problem regarding that even if you are not logged in you can still view the profile also another thing is that each user should only see his profile not others I need some tips on this
views.py
class UserProfileDetailView(DetailView):
model = get_user_model()
slug_field = "username"
template_name = "user_detail.html"
def get_object(self, queryset=None):
user = super(UserProfileDetailView, self).get_object(queryset)
UserProfile.objects.get_or_create(user=user)
return user
class UserProfileEditView(UpdateView):
model = UserProfile
form_class = UserProfileForm
template_name = "edit_profile.html"
def get_object(self, queryset=None):
return UserProfile.objects.get_or_create(user=self.request.user)[0]
def get_success_url(self):
return reverse("profile", kwargs={"slug": self.request.user})
Since you are using the Class Based Generic View, you need to add decorator #login_required in your urls.py
#urls.py
from django.contrib.auth.decorators import login_required
from app_name import views
url(r'^test/$', login_required(views.UserProfileDetailView.as_view()), name='test'),
Have you checked out the login_required decorator? Docs are here.
Since it seems you are using Class Based Views, you need to decorate in the urlconf, see here for more info.
At this moment you can add LoginRequiredMixin for your custom view.
Example:
class MyListView(LoginRequiredMixin, ListView): # LoginRequiredMixin MUST BE FIRST
pass
Doc: https://docs.djangoproject.com/en/4.1/topics/auth/default/#the-loginrequiredmixin-mixin
The below is what you should typically do
#login_required
def my_view(request, uid):
# uid = user id taken from profile url
me = User.objects.get(pk=uid)
if me != request.user:
raise Http404