Customize PasswordResetConfirmView - django

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'
),

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.

Pass request.user to dispatch method

Env: Python 3.6, Django 3.0, DRF 3.11, JWT Authorization
Hello everybody.
I have a simple class in my API where I want to check user permissions in each method get, post etc. I planned to check user privileges at dispatch but it doesn't work. Simplify code, my current class looks more or less like this:
class ExampleClassName(APIView):
can_do_sth = False
def dispatch(self, request, *args, **kwargs):
print(request.user) # Here is AnonymousUser
if request.user.username == "GreatGatsby":
self.can_do_sth = True
return super(ExampleClassName, self).dispatch(request, *args, **kwargs)
def get(self, request):
print(request.user) # Here is correctly Logged user
if self.can_do_sth:
return Response("You can do it")
return Response("You can't")
def post(self, request):
print(request.user) # Here is correctly Logged user
if self.can_do_sth:
return Response("You can do it")
return Response("You can't")
How can I pass request.user to dispatch method?
ok solved
initialize_request - is doing what I expected. so right dispatch should be:
def dispatch(self, request, *args, **kwargs):
req = self.initialize_request(request, *args, **kwargs)
print(req.user) # Now I have logged user data
if req.user.username == "GreatGatsby":
self.can_do_sth = True
return super(ExampleClassName, self).dispatch(request, *args, **kwargs)
Task closed unless you have any other idea how to do it in different way. If you do - please share :)

Django:How can I prevent authenticated user from both register and login page in Django-registration-redux

I am currently using Django-registration-redux for my authentication system.
Already logged in user can visit the login and registration page again; which is not good enough. How can I prevent them from this since the views.py comes by default in Django-registration-redux
I think that should be done in the views.py that come with Django-registration-redux
Here is the views.py
"""
Views which allow users to create and activate accounts.
"""
from django.shortcuts import redirect
from django.views.generic.base import TemplateView
from django.views.generic.edit import FormView
from django.conf import settings
from django.utils.decorators import method_decorator
from django.views.decorators.debug import sensitive_post_parameters
try:
from django.utils.module_loading import import_string
except ImportError:
from registration.utils import import_string
from registration import signals
# from registration.forms import RegistrationForm
REGISTRATION_FORM_PATH = getattr(settings, 'REGISTRATION_FORM', 'registration.forms.RegistrationFormUniqueEmail')
REGISTRATION_FORM = import_string( REGISTRATION_FORM_PATH )
class _RequestPassingFormView(FormView):
"""
A version of FormView which passes extra arguments to certain
methods, notably passing the HTTP request nearly everywhere, to
enable finer-grained processing.
"""
def get(self, request, *args, **kwargs):
# Pass request to get_form_class and get_form for per-request
# form control.
form_class = self.get_form_class(request)
form = self.get_form(form_class)
return self.render_to_response(self.get_context_data(form=form))
def post(self, request, *args, **kwargs):
# Pass request to get_form_class and get_form for per-request
# form control.
form_class = self.get_form_class(request)
form = self.get_form(form_class)
if form.is_valid():
# Pass request to form_valid.
return self.form_valid(request, form)
else:
return self.form_invalid(form)
def get_form_class(self, request=None):
return super(_RequestPassingFormView, self).get_form_class()
def get_form_kwargs(self, request=None, form_class=None):
return super(_RequestPassingFormView, self).get_form_kwargs()
def get_initial(self, request=None):
return super(_RequestPassingFormView, self).get_initial()
def get_success_url(self, request=None, user=None):
# We need to be able to use the request and the new user when
# constructing success_url.
return super(_RequestPassingFormView, self).get_success_url()
def form_valid(self, form, request=None):
return super(_RequestPassingFormView, self).form_valid(form)
def form_invalid(self, form, request=None):
return super(_RequestPassingFormView, self).form_invalid(form)
class RegistrationView(_RequestPassingFormView):
"""
Base class for user registration views.
"""
disallowed_url = 'registration_disallowed'
form_class = REGISTRATION_FORM
http_method_names = ['get', 'post', 'head', 'options', 'trace']
success_url = None
template_name = 'registration/registration_form.html'
#method_decorator(sensitive_post_parameters('password1', 'password2'))
def dispatch(self, request, *args, **kwargs):
"""
Check that user signup is allowed before even bothering to
dispatch or do other processing.
"""
if not self.registration_allowed(request):
return redirect(self.disallowed_url)
return super(RegistrationView, self).dispatch(request, *args, **kwargs)
def form_valid(self, request, form):
new_user = self.register(request, form)
success_url = self.get_success_url(request, new_user)
# success_url may be a simple string, or a tuple providing the
# full argument set for redirect(). Attempting to unpack it
# tells us which one it is.
try:
to, args, kwargs = success_url
return redirect(to, *args, **kwargs)
except ValueError:
return redirect(success_url)
def registration_allowed(self, request):
"""
Override this to enable/disable user registration, either
globally or on a per-request basis.
"""
return True
def register(self, request, form):
"""
Implement user-registration logic here. Access to both the
request and the full cleaned_data of the registration form is
available here.
"""
raise NotImplementedError
class ActivationView(TemplateView):
"""
Base class for user activation views.
"""
http_method_names = ['get']
template_name = 'registration/activate.html'
def get(self, request, *args, **kwargs):
activated_user = self.activate(request, *args, **kwargs)
if activated_user:
success_url = self.get_success_url(request, activated_user)
try:
to, args, kwargs = success_url
return redirect(to, *args, **kwargs)
except ValueError:
return redirect(success_url)
return super(ActivationView, self).get(request, *args, **kwargs)
def activate(self, request, *args, **kwargs):
"""
Implement account-activation logic here.
"""
raise NotImplementedError
def get_success_url(self, request, user):
raise NotImplementedError
Here is my main/project urls.py
urlpatterns = [
url( 'admin/', admin.site.urls),
url(r'^$', views.home, name='homepage'),
url(r'^user/', include('User.urls')),
#url(r'^accounts/register/$', MyRegistrationView.as_view(),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Thanks, any help will be appreciated
Below are the file showing identation error
indentaion error
views file
In the dispatch method of your views you can check if the user is authenticated and redirect them to another page, for example:
class RegistrationView(_RequestPassingFormView):
...
#method_decorator(sensitive_post_parameters('password1', 'password2'))
def dispatch(self, request, *args, **kwargs):
"""
Check that user signup is allowed before even bothering to
dispatch or do other processing.
"""
if request.user.is_authenticated:
return redirect('some_url')
if not self.registration_allowed(request):
return redirect(self.disallowed_url)
return super(RegistrationView, self).dispatch(request, *args, **kwargs)
The if user.is_authenticated prevents both logged-in and not-logged-in user from accessing the registration page.
class RegistrationView(_RequestPassingFormView):
"""
Base class for user registration views.
"""
disallowed_url = 'registration_disallowed'
form_class = REGISTRATION_FORM
http_method_names = ['get', 'post', 'head', 'options', 'trace']
success_url = None
template_name = 'registration/registration_form.html'
#method_decorator(sensitive_post_parameters('password1', 'password2'))
def dispatch(self, request, *args, **kwargs):
"""
Check that user signup is allowed before even bothering to
dispatch or do other processing.
"""
if self.request.user.is_authenticated:
return redirect('/')
if not self.registration_allowed(request):
return redirect(self.disallowed_url)
return super(RegistrationView, self).dispatch(request, *args, **kwargs)
def form_valid(self, request, form):
new_user = self.register(request, form)
success_url = self.get_success_url(request, new_user)
# success_url may be a simple string, or a tuple providing the
# full argument set for redirect(). Attempting to unpack it
# tells us which one it is.
try:
to, args, kwargs = success_url
return redirect(to, *args, **kwargs)
except ValueError:
return redirect(success_url)
def registration_allowed(self, request):
"""
Override this to enable/disable user registration, either
globally or on a per-request basis.
"""
return True
def register(self, request, form):
"""
Implement user-registration logic here. Access to both the
request and the full cleaned_data of the registration form is
available here.
"""
raise NotImplementedError

Django: ProtectedError exception handling is not working

I am trying to handle ProtectedError exception and try to post a custom error message in my template.
def delete(self, request, *args, **kwargs):
obj = self.get_object()
get_success_url = self.get_success_url()
try:
obj.delete()
messages.success(self.request, self.success_message % obj.__dict__)
except ProtectedError:
messages.success(self.request, "can't delete")
return super().delete(request, *args, **kwargs)
without ProtectedError it is sending me back to my list page with delete successfully message but for ProtectedError it is sending me to some generic error page with ProtectedError at /settings/currency/1/delete/ message.
Thanks.
As I see it, on both cases your return is the same:
return super().delete(request, *args, **kwargs)
Instead you on except, raise the error:
raise ProtectedError('Cannot remove meta user instances', None)
or something like:
try:
obj.delete()
return JsonResponse({})
except ProtectedError as e:
return self.status_msg(e[0], status=405)
Take a look at those examples
Another optional, you can also handle it by creating new decorator:
from functools import wraps
from django.utils.translation import gettext_lazy as _
from django.db.models.deletion import ProtectedError
from rest_framework.exceptions import PermissionDenied
def protected_error_as_api_error():
"""
Decorator to handle all `ProtectedError` error as API Error,
which mean, converting from error 500 to error 403.
"""
def decorator(func):
#wraps(func)
def wrapper(request, *args, **kwargs):
try:
return func(request, *args, **kwargs)
except ProtectedError as error:
raise PermissionDenied(_('Action Denied: The selected object is being used '
'by the system. Deletion not allowed.'))
return wrapper
return decorator
Usage example:
from django.utils.decorators import method_decorator
from yourapp.decorators.protected_error_as_api_error import protected_error_as_api_error
#method_decorator(protected_error_as_api_error())
def delete(self, request, *args, **kwargs):
....
# OR
#method_decorator(protected_error_as_api_error())
def destroy(self, request, *args, **kwargs):
....
# OR
#action(methods=['delete'], ...):
#method_decorator(protected_error_as_api_error())
def your_view_name(self, request, *args, **kwargs):
....
CBV DeleteView uses a form (http://ccbv.co.uk/projects/Django/4.0/django.views.generic.edit/DeleteView/) which is recommended way to run validation and handle errors.
def post(self, request, *args, **kwargs):
# Set self.object before the usual form processing flow.
# Inlined because having DeletionMixin as the first base, for
# get_success_url(), makes leveraging super() with ProcessFormView
# overly complex.
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
Just define a custom form class with custom clean method and only field with id to retrieve the object:
https://docs.djangoproject.com/en/4.0/ref/forms/api/#django.forms.Form.clean

Class-based view delegate to another view

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