Search code examples
djangodjango-allauthdjango-class-based-views

Django not redirecting for email verification


Note: I am new to django
I have been trying to build an application similar to blog posts. I am using the allauth for social login and auth_views.LoginView.as_view for custom login.

When someone creates an account, their email is not verified and I used the @verified_email_required decorator in function based views.

Now when I am using class based views, I want the user to be verified to add or update posts..

Below is my code in views.py

class LogUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
    model = Log
    fields = ['title', 'content', 'image']
    slug_url_kwarg = 'question'
    slug_field = 'slug'
    
    def form_valid(self, form):
        form.instance.author = self.request.user
        return super().form_valid(form)

    def test_func(self):
        post = self.get_object()
        if self.request.user == post.author:
            if EmailAddress.objects.get(user=self.request.user).verified == True:
                return True
            else:
                print('Not verified')
                send_email_confirmation(self.request, self.request.user)
                return redirect('log-detail', question=post.slug)
        else:
            return False

When the user is not verified. I get the email as per the send_email_confirmation function, but I am not redirected to the log-detail page.. I am still able to update the post without verification.

urls.py:

from django.urls import path
from .views import LogListView, LogDetailView, LogCreateView, LogUpdateView, SolutionDetailView, SolutionsCreateView

urlpatterns = [
    path('', LogListView.as_view(), name='home'),
    path('new-question', LogCreateView.as_view(), name='log-create'),
    path('question/<slug:question>', LogDetailView.as_view(), name='log-detail'),
    path('question/update/<slug:question>', LogUpdateView.as_view(), name='log-update'),
    path('add-solution/<slug:question>', SolutionsCreateView.as_view(), name='log-solution-create'),
    path('solution/<slug:solution>', SolutionDetailView.as_view(), name='log-solution'),

]

send_email_confirmation function is provided by allauth.

edit:

the solution given worked.. But it raised a new error:

AttributeError at /new-question Generic detail view LogCreateView must be called with either an object pk or a slug in the URLconf.

The add-question class

class LogCreateView(LoginRequiredMixin, VerificationRequiredMixin, CreateView):
    model = Log
    fields = ['title', 'content', 'image']
    
    def form_valid(self, form):
        form.instance.author = self.request.user
        return super().form_valid(form)

Solution

  • The test_func is only supposed to return whether the user passes the test or not. But you return a redirect (which returns a HttpResponseRedirect) the value of which is truthy and it is considered that your user passed the test. Instead you should simply write a mixin of your own to do this:

    from django.core.exceptions import PermissionDenied
    
    
    class VerificationRequiredMixin:
        def get_verification_redirect(self):
            raise NotImplementedError(
                '{} is missing the implementation of the get_verification_redirect() method.'.format(self.__class__.__name__)
            )
        
        def dispatch(self, request, *args, **kwargs):
            if EmailAddress.objects.get(user=self.request.user).verified:
                return super().dispatch(request, *args, **kwargs)
            print('Not verified')
            send_email_confirmation(self.request, self.request.user)
            return self.get_verification_redirect()
    
    
    class LogUpdateView(LoginRequiredMixin, UserPassesTestMixin, VerificationRequiredMixin, UpdateView):
        model = Log
        fields = ['title', 'content', 'image']
        slug_url_kwarg = 'question'
        slug_field = 'slug'
        
        def form_valid(self, form):
            form.instance.author = self.request.user
            return super().form_valid(form)
        
        def test_func(self):
            post = self.get_object()
            return self.request.user == post.author
        
        def get_verification_redirect(self):
            post = self.get_object()
            return redirect('log-detail', question=post.slug)
    
    
    class LogCreateView(LoginRequiredMixin, VerificationRequiredMixin, CreateView):
        model = Log
        fields = ['title', 'content', 'image']
        
        def form_valid(self, form):
            form.instance.author = self.request.user
            return super().form_valid(form)
        
        def get_verification_redirect(self):
            return redirect('some_view')