The purpose of the Pinax Hangouts is to engage more with the Pinax community. We want to let you know what we are working on, answer your questions, and present demos of old and new apps and starter projects. Our host last month was Brian Rosner, who was supported by our co-host Patrick Altman.
As a follow up to our first Pinax Hangout about the
pinax-project-account starter project, Brian talked about the django-user-accounts app, which Eldarion uses for a lot of their projects, and which is integrated in most Pinax starter projects.
django-user-accounts is just a Django app and can be used in any Django project that needs the functionality it provides. The Pinax starter projects are a good example on how to integrate
django-user-accounts into your Django app.
Some of the features
django-user-accounts offers are:
- Email and username authentication (username authentification is the default)
- Sign up
- Email confirmation
- Sign up tokens for private betas
- Password resets
- Account management (updating your account settings, changing your password, account deletion, etc.)
- Extensible class-based views (enables you to easily customize
django-user-accountsfor your business logic)
- Custom user model support
- Supports Django 1.7 and 1.8, and Python 2.7 and 3
History of django-user-accounts
django-user-accounts came out of the Pinax Project in the earlier days of Pinax. Its original location was
pinax.apps.account. It was tightly integrated with other components inside of Pinax and later pulled out of the Pinax ecosystem and made a better member of the Django ecosystem and can now be used on its own.
django-user-accounts was originally created because back then a lot of the existing Django user management functionality was a bit scattered. A lot of websites nowadays use user accounts and
django-user-accounts provides a solid base to get your site running quickly with user accounts.
Dive in and Demo
Brian demonstrated how
django-user-accounts works and what it looks like. You can also find all the steps in the django-user-accounts documentation.
First create a virtual environment, then
pip install pinax-cli, which simplifies the creation of a starter project on your own computer. Next create a new directory for your project and run
pinax start account mysite, which creates a new project locally called
mysite based on the account project app, which will install Django for you. Then
Follow these steps next:
pip install -r requirements.txt python manage.py migrate python manage.py loaddata sites python manage.py runserver
Customizing the Sign Up Process
To customize the sign up process, create a
views.py file in your
mysite app. Then create a new sign up view which will inherit from the view, which exists in
import account.views class SignupView(account.view): pass
Make sure to import your new view into
urls.py. Add the import statement on line 8:
from.views import SignupView
We want to override just one URL, not all of them so we need to define a URL pattern that comes before the “include URL pattern” since the way URLs are loaded is in the order they are listed in
urls.py. On line 15, add the following URL pattern:
url(r“^account/signup/$“, SignupView.as_view(), name="account_signup“)
Start your server again to make sure everything works.
views.py add the following code:
def update_profile(self, form): pass def after_signup(self, form): self.update_profile(form) super(SignupView, self).after_signup(form)
We’re overriding the
after_signup function. When
django-user-accounts does the sign up process, this function gets called after everything has been signed up but right before things get saved to the database.
Create a new model in
def update_profile(self,form): UserProfile.objects.create( user=self.created_user )
We would like to ask our users to tell us their date of birth before they sign up. In order to do this we need to create a new file called
forms.py and add a new field called birth date:
from django import forms from django.forms.extras.widgets import SelectDateWidget import account.forms class SignupForm(account.forms.SignupForm): birthdate = forms.DateField(widget=SelectDateWidget(years=range(1910, 1991)))
We import our form in
from .forms import SignupForm
To hook this into our view, we simply assign
form_class = SignupForm
In a new file called
models.py, create a
UserProfile model for it to work:
from django.conf import settings from django.db import models class UserProfile(models.Model): user = models.OneToOneField(settings.AUTH_USER_MODEL) birthdate = models.DateField()
We’re pulling the date data directly from the form object that’s passed in.
Import your model into
from .models import UserProfile
and add this line:
birthdate = form.cleaned_data["birthdate“],
Since we made some changes to our models, we need to migrate them before we continue:
python manage.py makemigrations mysite python manage.py migrate
Start the server again. Now you can see the birthdate field in the sign up form on your website.
In order to test if everything works, sign up. After signing up you will get a notification that the user was signed up on the site.
In your console you’ll also see that an email was printed out. By default projects have email configured for the console so you can see the email that would have been sent to the user.
Copy the URL and paste it into your browser to confirm your email address. All of this functionality is provided through
Customizing Confirmation Emails
You can customize all of these emails with the hooksets (default behavior for things that
django-user-accounts provides), which are integrated into
In your project you can provide your own hooks object class that overrides these methods to form the behavior based on your own business logic.
If you want to customize the behavior around how
django-user-accounts sends out email confirmations you can easily do that by overriding the
First add hooksets to your project settings:
ACCOUNT_HOOKSET = "account.hooks.AccountDefaultHookSet“
This is the default value. We can also point the path to something in our own project. For our project we’ll use
ACCOUNT_HOOKSET = "mysite.hooks.AccountHookSet“
Then create a new file in your project called
hooks.py and add the following code:
from account.hooks import AccountDefaultHookSet class AccountHookSet(AccountDefaultHookSet): pass
The code we just added now provides you with the ability to override these methods. If you have suggestions for other methods you’d like us to integrate into
django-user-accounts, please join our Pinax Project Slack channel and let us know!
django-user-accounts lets you either log in with a username or an email address. Username authentication is the default but we want to change it to email authentication.
Before we start making changes, please note that all account email addresses, meaning all email addresses in your database, should be unique. If they are not all unique, this could cause trouble.
Add the following code to your
ACCOUNT_EMAIL_UNIQUE = True ACCOUNT_EMAIL_CONFIRMATION_REQUIRED = True
This will require the user to confirm their email address before they can login to the site. We therefore assume that users can access their email.
Next we need to override the login view in
views.py. Create your own
login view and then redefine the form class that’s used for the login view to be the login email form. This is provided out of the box by
django-user-accounts but if you have any other requirements this can be changed.
Add the following code to
class LoginView(account.views.LoginView): form_class = account.forms.LoginEmailForm
urls.py and import your
from .views import SignupView, LoginView
Create your URL:
url(r“^account/login/$“, LoginView.as_view(), name="account_login“),
Ensure that you’re using the email authentication backend. If you only want email authentication, you can remove the username authentication, if you leave in both, you have the ability to do both.
The order in which they are listed in the
AUTHENTIFICATION_BACKENDS list in
settings.py is important because the first one will be tried first so if you want to fall back to email address, you should list email address after username, but if you want to fall back to username you would list username last.
For our app we can remove the username authentication so our line of code should look like this:
AUTHENTIFICATION_BACKENDS = [ "account.auth_backends.EmailAuthenticationBackend“, ]
To get completely rid of usernames you will have to do a few extra steps, which you can find in the documentation.
In our case we’ll do a little bit of magic, by magic meaning we’re going to assume that only one person is ever going to sign up for our site.
def generate_username (self, form): username = "<magic>“ return username
def ACCOUNT_USER_DISPLAY(user): return user.email
Please note that
ACCOUNT_USER_DISPLAY needs to be defined in your settings.
Next migrate the database and run the server.
It will still ask you for a username during sign up and we might not want that so we will override the sign up constructor in
forms.py and then just delete the username. You might also want to change the order of things (we’re not gonna worry about that):
def __init__(self, *args*, **kwargs**): super(SignupForm, self).__init__(*args, **kwargs) del.self.fields["username“]
Sign up on your website again, confirm your email address (the confirmation email will be printed in the console again). We now have the ability to only login with our email address.
When you want to override templates the first thing you need to do is to figure out where the template is because the templates you see on your Pinax website are provided through a theme app, by default it’s the pinax-theme-bootstrap app. It provides all of the templates for interacting with
django-user-accounts. If you want to integrate
django- user-accounts into your existing Django app, you’ll probably need to provide these templates yourself. Inside of
pinax-theme-bootstrap we provide the templates for you and also created the ability to override a template, for example if you want to be able to make your login page or email confirmation page look different.
If you want to override a template, you need to find where the template is in your virtual environment, copy the template file, and put it inside your own project, inside your templates settings underneath account. When Django loads templates it goes in order of the specific loaders that are defined. It uses your project’s template directory first before it goes to the
APP_DIRS, which gives you the ability to override any templates at your project level that match the similar naming at an app level.
To make this easier we provided a command called
python manage.py copy_from_theme so if you want to customize the login template for example, you would type in
python manage.py copy_from_theme —path=account/login.html.
Our documentation shows you all the templates that the views in
django-user-accounts call. If you needed to override anyone of these you can pass it in like shown above or override the whole project account by typing in
python manage.py copy_from_theme —path=account/*.
We should now have all the account templates inside our project, which enables you to modify any of the template code as you desire.
If you missed our September Pinax Hangout, you can watch the video here
If you have any questions, please post them in our Pinax project Slack channel. No matter if beginner, or experienced, we want to help everyone!
We would also love contributions to
django-user-accounts. You can find the GitHub repo here. Please file issues, make pull requests, etc.
Our next Pinax Hangout will take place on Thursday, October 22nd at noon Eastern time. The topic will be pinax-project-blog. We hope that you will join us for our October Hangout!