Django check if superuser in class-based view - python

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

Related

How to authenticate session inside class based view django

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

Is it possible Django model filter by LogEntry by user added in ModelAdmin?

I am working with a blog site. I want to add some feature that like admin filter post can modify only that user added. I want to use Django builtin LogEntry model.
Any can help me?
You could override the ModelAdmin's get_queryset method along the following lines:
from django.contrib.admin.models import ADDITION
from django.contrib import admin
class MyModelAdmin(admin.ModelAdmin):
# ...
def get_queryset(self, request):
qs = super(MyModelAdmin, self).get_queryset(request)
ct = ContentType.objects.get_for_model(MyModel)
qs = qs.filter(id__in=list(
LogEntry.objects.filter(content_type=ct,
action_flag=admin.models.ADDITION,
user=request.user)\
.values_list('object_id', flat=True)))
return qs
This will narrow down the objects the admin has access to the ones created by the currently logged in user.

Django Rest Framework Permissions and Ownership

I have two simple models
class User(AbstractUser):
pass
class Vacation(Model):
id = models.AutoField(primary_key=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
I am not really sure what is the scalable way of doing user permissions for Django Rest Framework. In particular:
Users should only be able to see their own vacations
On the /vacation endpoint, user would see a filtered list
On the /vacation/$id endpoint, user would get a 403 if not owner
Users should only be able to Create/Update vacations as long as they are the owners of that object (through Foreign Key)
What is the best way to achieve this in a future-proof fashion. Say if further down the line:
I add a different user type, which can view all vacations, but can only create/update/delete their own
I add another model, where users can read, but cannot write
Thank you!
From the docs:
Permissions in REST framework are always defined as a list of permission classes. Before running the main body of the view each permission in the list is checked. If any permission check fails an exceptions.PermissionDenied or exceptions.NotAuthenticated exception will be raised, and the main body of the view will not run.
REST framework permissions also support object-level permissioning. Object level permissions are used to determine if a user should be allowed to act on a particular object, which will typically be a model instance.
For your current need you can define your own Permission class:
class IsVacationOwner(permissions.BasePermission):
# for view permission
def has_permission(self, request, view):
return request.user and request.user.is_authenticated
# for object level permissions
def has_object_permission(self, request, view, vacation_obj):
return vacation_obj.owner.id == request.user.id
And add this permission to your view. For example on a viewset:
class VacationViewSet(viewsets.ModelViewSet):
permission_classes = (IsVacationOwner,)
One thing is important to notice here, since you will respond with a filtered list for '/vacations', make sure you filter them using the request.user. Because object level permission will not be applicable for lists.
For performance reasons the generic views will not automatically apply object level permissions to each instance in a queryset when returning a list of objects.
For your future requirement, you can always set the permissions conditionally with the help of get_permissions method.
class VacationViewSet(viewsets.ModelViewSet):
def get_permissions(self):
if self.action == 'list':
# vacations can be seen by anyone
# remember to remove the filter for list though
permission_classes = [IsAuthenticated]
# or maybe that special type of user you mentioned
# write a `IsSpecialUser` permission class first btw
permission_classes = [IsSpecialUser]
else:
permission_classes = [IsVacationOwner]
return [permission() for permission in permission_classes]
DRF has great documentation. I hope this helps you to get started and helps you to approach different use cases according to your future needs.
I would suggest you to use drf-viewsets link. We are going to use vacation viewset to do this work.
our urls.py
from your_app.views import VacationViewSet
router.register('api/vacations/', VacationViewSet)
our serializers.py
from rest_framework import serializers
from your_app.models import Vacation
class VacationSerializer(serializers.ModelSerializer):
class Meta:
model = Vacation
fields = ('id', 'owner',)
read_only_fields = ('id',)
our views.py
Here we are going to overwrite viewset's retrive and list method. There are other possible way to do that but i like this most as i can able to see what is happening in code. Django model viewset inherited link of drf-mixins retrive and list method.
from rest_framework import viewsets, permissions, exceptions, status
from your_app.models import Vacation, User
from your_app.serializers import VacationSerializer
class VacationViewSet(viewsets.ModelViewSet):
queryset = Vacation.objects.all()
permission_classes = [IsAuthenticated]
serializer = VacationSerializer
# we are going to overwrite list and retrive
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
# now we are going to filter on user
queryset = queryset.filter(owner=self.request.user)
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
# not permitted check
if instance.owner is not self.request.user:
raise exceptions.PermissionDenied()
serializer = self.get_serializer(instance)
return Response(serializer.data)
Django rest framework provides in-build settings for this
Just import the required permission and add it to you class variable permission_classes
in my_name.api.views
from rest_framework.permissions import ( AllowAny, IsAuthenticated, IsAdminUser, IsAuthenticatedOrReadOnly,)
class Vacation(ListAPIView):
serializer_class = VacationListSerializer
permission_classes = [IsAuthenticated]
You can add multiple permission classes as a list
Furthur, in case this is not helpful, you can always filter the model objects as
Mymodel.objects.filter(owner = self.request.user)

Updating User Password in Django with Class Based Views

I'm tring write a view to administrator update a password of another user, using Class Based Views and model SetPasswordForm of Django.
My views.py
class UserSetPasswordUpdateView(GroupRequiredMixin, FormView):
form_class = forms.SetPasswordForm
model = User
template_name = 'app/admin/object_update.html'
success_url = reverse_lazy('portal:admin_user')
group_required = u"Administrator"
def get_form_kwargs(self):
kwargs = super(UserSetPasswordUpdateView, self).get_form_kwargs()
kwargs['user'] = User.objects.filter(pk=self.kwargs['pk'])
return kwargs
update_change_password = UserSetPasswordUpdateView.as_view()
My urls.py
url(r'^app/admin/update-user-pass/(?P<pk>[0-9]+)$', update_views.update_change_password, name='update_change_password'),
And don't show any errors, just go to success_url, but the password don't updated.
Your view is based on FormView. This doesn't have any knowledge of model forms, and doesn't do anything with the data other than check that it is valid. SetPasswordForm changes the password when the form is saved, but this view never does this.
You could override form_valid to call form.save() explicitly, but it would be better to use a more appropriate base class such as UpdateView which will do that for you.

Django Login Required to view

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

Categories