Search code examples
djangodjango-formsdjango-viewsdjango-allauth

"AttributeError: 'NoneType' object has no attribute 'session' " when override SignupForm in django allauth app


I tried to implement django allauth app with SignupForm override, my code almost works when entering data into the signup form and saves users, but after save, I redirected to a new page that showed me 'NoneType' object has no attribute 'session' AttributeError. How can I fix it?

urls.py

from django.urls import path
from .views import login, logout, AllauthSignUpView

app_name = 'register'
urlpatterns = [
    path('login/', login, name='login'),
    path('signup/', AllauthSignUpView.as_view(), name='signup'),
    path('logout/', logout, name='logout'),
]

views.py

override SignupView As follows as:

from django.shortcuts import render, HttpResponseRedirect
from .form import AllauthLoginForm, AllauthSignUpForm
from allauth.account.views import SignupView
from django.urls import reverse_lazy

class AllauthSignUpView(SignupView):
    template_name = 'register/signup.html'
    form_class = AllauthSignUpForm
    success_url = reverse_lazy('core:home')  #Redirect to home.html

    def form_valid(self, form):
        # This method is called when valid form data has been POSTed.
        if form.is_valid():
            form.save()
            form.clean()
            return HttpResponseRedirect('core:home')   #Redirect to home.html
        # It should return an HttpResponse.
        return super().form_valid(form)

    def get_context_data(self, **kwargs):
        context = super(AllauthSignUpView, self).get_context_data(**kwargs)
        signUpForm = AllauthSignUpForm(self.request.POST or None)
        context['form'] = signUpForm
        return context

form.py

override SignupForm As follows as:

from allauth.account.forms import LoginForm, SignupForm
from django import forms

class AllauthSignUpForm(SignupForm):
    def __init__(self, *args, **kwargs):
        super(AllauthSignUpForm, self).__init__(*args, **kwargs)
        self.fields['username'] = forms.CharField(
            label='',
            widget=forms.TextInput(
                attrs={
                    'class': 'signup_name_inp text-right mb-4 border-top-0 border-right-0 border-left-0',
                    'placeholder': 'نام کاربری',
                    'dir': 'rtl',
                }
            ),
        )
        self.fields['email'] = forms.EmailField(
            label='',
            widget=forms.EmailInput(
                attrs={
                    'class': 'signup_mail_inp text-right mb-4 border-top-0 border-right-0 border-left-0',
                    'placeholder': 'ایمیل (اختیاری)',
                    'dir': 'rtl',
                }
            )
        )
        self.fields['password1'] = forms.CharField(
            label='',
            widget=forms.PasswordInput(
                attrs={
                    'class': 'signup_pass_inp1 text-right mb-4 border-top-0 border-right-0 border-left-0',
                    'placeholder': 'کلمه عبور',
                    'dir': 'rtl',
                }
            )
        )
        self.fields['password2'] = forms.CharField(
            label='',
            widget=forms.PasswordInput(
                attrs={
                    'class': 'signup_pass_inp2 text-right mb-4 border-top-0 border-right-0 border-left-0',
                    'placeholder': 'تکرار کلمه عبور',
                    'dir': 'rtl'
                }
            )
        )
    def save(self, request=None):
        # Ensure you call the parent class's save.
        # .save() returns a User object.
        user = super(AllauthSignUpForm, self).save(request)

        # Add your own processing here.
        print(user.username)
        # You must return the original result.
        return user

signup.html

          <form dir='rtl' class="text-right border-0 p-5  bg-transparent" id="signup_form" method="post" action="{% url 'register:signup' %}" >
            {% csrf_token %}
              {{ form|crispy }}
            <div class="row">
              <div class="col-12">
                  <button class="btn btn-outline-info  btn-block z-depth-0 my-4 waves-effect rounded-pill" type="submit">{% trans "ثبت نام" %} &raquo;</button>
              </div>
              <div class="col-12">
                  <p class="float-right  mt-3" >آیا اکانت ساخته اید؟ <a class="font-weight-bold" href="{% url 'register:login' %}" style="color: #858585 !important;">وارد شوید</a>.</p>
              </div>
            </div>
          </form>

settings.py

ACCOUNTS_FORMS = {
    'login': 'registerations.form.AllauthLoginForm',
    'signup': 'registerations.form.AllauthSignUpForm',
    'add_email': 'allauth.account.forms.AddEmailForm',
    'change_password': 'allauth.account.forms.ChangePasswordForm',
    'set_password': 'allauth.account.forms.SetPasswordForm',
    'reset_password': 'allauth.account.forms.ResetPasswordForm',
    'reset_password_from_key': 'allauth.account.forms.ResetPasswordKeyForm',
    'disconnect': 'allauth.socialaccount.forms.DisconnectForm',
}

There are some useful link below: help-1


Solution

  • There look to be a few potential issues with your code but the main one that's likely causing your stated issue is that you're not passing the request object to your form.save() call in your views.py file.

    It should look something more like this:

    def form_valid(self, form):
    
        # Don't do this. form_valid() only gets called on a valid form anyway
        # if form.is_valid():
    
        form.save(self.request)
    
        # No need to call form.clean() again, especially after already saving the form
        # form.clean()
    
        return HttpResponseRedirect('core:home')   #Redirect to home.html
    

    So, in summary, you don't really seem to be doing anything "custom" in your custom form_valid() function, so you're probably better off completely removing it and just using the one defined in the parent class. You've already specified your success_url so you can let allauth's form_valid() do the work for you.