As a very short introduction for those who are not familiar with Django, its a powerful Python web application framework. It provides a well defined MVC structure for web applications in Python and support many things that you need. From Djnago’s website:
Django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design. Built by experienced developers, it takes care of much of the hassle of Web development, so you can focus on writing your app without needing to reinvent the wheel. It’s free and open source.
Django uses a application driven method to provide modularity and promote development of reusable applications as components of an application. This promoted development of numerous packages that you can use in your project.
Allauth is a Djang user authentication/registration package that supports login/signup and many related features additional to social authentication features for different websites such as Google, Facebook, Linkedin, Twitter and etc using the OAuth 1.0 and 2.0 protocols.
Django-allauth app is a significant help if you know how to use it, however, its not well documented at all. There are some few nice tutorials that I found and I’m sharing them here. But, still you can’t find detailed instructions for it. Here I will explain how one can customize a LoginView of this plugin to obtain both signup and signin at the same time.
Here, I’m assuming that you have some knowledge about Django and are trying to use Django-allauth so you what it is and how it works. The first thing that you need is to copy the templates from the source code on their Github repository here to be able to change them. copy the template files in your template directory. Make sure that you copy the folders directly into your templates directory. DO NOT CREATE A ALLAUTH DIRECTORY AT ALL. If you are not familiar with creating templates directory on Django read here.
Now from account directory open login.html and signup.html template files. The login.html template is the one you need to change. What I will explain in the next few paragraphs is the way you can bring the signup template codes to this file. The design and css codes are not explained in this tutorial. I recommend using the bootstrap platform.
Copy the signup.html template codes into login.html. Your login.html should look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
{% extends "account/base.html" %} {% load i18n %} {% load account %} {% load url from future %} {% block head_title %}{% trans "Sign In" %}{% endblock %} {% block content %} <div> <h1>{% trans "Sign In" %}</h1> {% if socialaccount.providers %} <p>{% blocktrans with site.name as site_name %}Please sign in with one of your existing third party accounts. Or, <a href="{{ signup_url }}">sign up</a> for a {{site_name}} account and sign in below:{% endblocktrans %}</p> <div class="socialaccount_ballot"> <ul class="socialaccount_providers"> {% include "socialaccount/snippets/provider_list.html" with process="login" %} </ul> <div class="login-or">{% trans 'or' %}</div> </div> {% include "socialaccount/snippets/login_extra.html" %} {% else %} <p>{% blocktrans %}If you have not created an account yet, then please <a href="{{ signup_url }}">sign up</a> first.{% endblocktrans %}</p> {% endif %} <form class="login" method="POST" action="{% url 'account_login' %}"> {% csrf_token %} {{ form.as_p }} {% if redirect_field_value %} <input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" /> {% endif %} <a class="button secondaryAction" href="{% url 'account_reset_password' %}">{% trans "Forgot Password?" %}</a> <button class="primaryAction" type="submit">{% trans "Sign In" %}</button> </form> </div> <div> <h1>{% trans "Sign Up" %}</h1> <p>{% blocktrans %}Already have an account? Then please <a href="{{ login_url }}">sign in</a>.{% endblocktrans %}</p> <form class="signup" id="signup_form" method="post" action="{% url 'account_signup' %}"> {% csrf_token %} {{ form.as_p }} {% if redirect_field_value %} <input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" /> {% endif %} <button type="submit">{% trans "Sign Up" %} »</button> </form> </div> {% endblock %} |
If you notice I have simply just copied the code from signup.html to login.html and wrapped both into separate div tags. If you now try this you will see that it will work but will show the login form twice. The problem is that the form variable in
1 |
{{ form.as_p }} |
has the login form in both cases. One when we are displaying the login form and once when we are displaying the signup form. To solve this, we will have to pass on a new variable/parameter to the template for the signup form. But, this is done in the LoginView implemented within the allauth app. To solve this we have to implement a new LoginView class which inherits all of the LoginView features and adds on to it. Create a new JointLoginSignupView class in your app’s views.py file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
from allauth.account.views import * # Create your views here. class JointLoginSignupView(LoginView): form_class = LoginForm signup_form = SignupForm def __init__(self, **kwargs): super(JointLoginSignupView, self).__init__(*kwargs) def get_context_data(self, **kwargs): ret = super(JointLoginSignupView, self).get_context_data(**kwargs) ret['signupform'] = get_form_class(app_settings.FORMS, 'signup', self.signup_form) return ret login = JointLoginSignupView.as_view() |
This new class is extending the LoginView, which is also extending the abstract FormView in Django. FormView uses variables defined in the returned dictionary from get_content_data function as parameters which are pass to the template. Therefore, we have to add a new singupform parameter which holds the signup form and fix our template accordingly. The new template will look like:
1 2 3 4 5 6 7 8 9 10 11 12 |
... ... <form class="signup" id="signup_form" method="post" action="{% url 'account_signup' %}"> {% csrf_token %} {{ signupform.as_p }} {% if redirect_field_value %} <input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" /> {% endif %} <button type="submit">{% trans "Sign Up" %} »</button> </form> ... ... |
Here you go. Have fun customizing the allauth app for yourself.
9 comments On Joint login and signup Django-allauth view
Really helpful!!
I was having a hard time trying to figure this out alone.
You can also use the @login_required(login_url) to redirect to custom login forms for specific matters.
Could you also have form_class=SignupForm or does it work only this way around?
I used a combination of this post of yours and this Stack Overflow post to get what I needed: http://stackoverflow.com/questions/29499449/django-allauth-login-signup-form-on-homepage
Thank you!
P.S. I’m getting a NameError with the get_form_class line you suggested (“File “./members/views.py”, line 209, in get_context_data
context[‘login_form’] = get_form_class(app_settings.FORMS, ‘login’, self.login_form)
NameError: global name ‘get_form_class’ is not defined
“). Any ideas why?
http://stackoverflow.com/questions/30588379/django-allauth-joint-signup-login-view-throwing-global-name-get-form-class-is
Sorry, I abandoned my blog for a while for personal reasons. I hope this was resolved for you but I will be looking into it.
Mmm, I actually tried to do that but it wasn’t straight forward what to change if you didn’t want to hard code it
Can you please give complete customization idea??
Hey, sorry just noticed this comment. Can you give me some detail?
Hey Salim,
Do you know how I can display a Facebook login button instead of having Facebook as a list item?
I think this code makes it into a bullet point.
{% include “socialaccount/snippets/provider_list.html” with process=”login” %}
thank god … now i can try this.. but is there any Allauth with custom templates complete application available so that we can actually study it to get some info