You want to set up Django users, groups and integrate them with permission management in a Django application.
To create a superuser you can use the
python manage.py createsuperuser command line utility, use the
User.objects.create_superuser() method or use the Django admin to change a user's superuser status. To create a regular user you can use the
User.objects.create_user() method or user the Django admin. You can manage a user's properties (e.g. superuser, staff, password ) directly manipulating his
User model record or through the Django admin.
You can create and manage a group in the Django admin. It's possible to assign Create-Update-Delete permissions for individual Django models to a user or group in the Django admin. You can create a permission check in the body of a view method directly accessing a user's properties available in
if request.user.is_anonymous()). It's also possible to apply a permission check directly to a view method or URL definition using the
@permission_required decorators. In addition, you can also apply a permission check in a Django template accessing the
Django has a very robust built-in mechanism to manage users and restrict an application's access based on various rules. By default, Django only enforces permission management on the Django admin which provides full access to the database connected to an application. Permission management on the Django application itself (i.e. the one accessed by end-users) needs to be integrated and is described toward the end of this recipe.
There are two main types of Django users:
AnonymousUser. If a user authenticates himself (i.e. provides a valid username/password) Django recognizes him as a
User. On the other hand, if a user just surfs an application without any authentication, Django recognizes him as an
User can be further classified into one of various sub-types:
superuser.- The most powerful user with permissions to create, read, update and delete data in the Django admin, which includes model records and users.
staff.- A user marked as staff can access the Django admin. But permissions to create, read, update and delete data in the Django admin must be given explicitly to a user. By default, a
superuseris marked as
active.- All users are marked as active if they're in good standing. Users marked as inactive aren't able to authenticate themselves, a common state if there's a pending post-registration step (e.g. confirm email) or a user is banned and you don't want to delete his data.
Django also offers the concept of a
Group to grant a set of users the same set of permissions without having to assign them individually. For example, you can grant permissions to a group and then assign users to the group to make permission management easier. In this manner, you can revoke or add permissions in a single step to a set of users, as well quickly give new users the same permissions.
In addition, you can assign Django permissions granularly to a
Group in order for them to Create-Update-Delete records on Django models, a process which is done through
Permission model records. Or you can also assign coarser grained Django permissions on URL/view methods or template content to grant access to a
Group or even
Now that you know the basic concepts behind Django's user system, let's explore the more common operations in detail.
The first user you'll want to create is a superuser. If you already followed the Set up the Django admin site recipe, then you'll already have a superuser. Either way, I'll recap the process here since you can have any number of superusers. Listing 1 illustrates the various ways in which you can create a superuser.
|A Django username must be unique|
Django enforces user uniqueness through the username value, so it's not possible to create two users with the same username.
As you can see in listing 1, you can create a superuser with the
createsuperuser command of the
manage.py utility, where you're asked for a username, email and password. You can also see that it's possible to create a superuser with the inline arguments
In addition, it's also possible to create a superuser through the Django shell using the
User model class with the
create_superuser() method. Notice how the
create_superuser() method requires the
When you create a superuser in any of the previous ways, the user is also automatically set as a staff member and active, so you don't need to make any additional updates to access the Django admin or proceed with authentication.
Sometimes you just want to create a regular user, in which case you can use Django's shell utility and create a user directly through the
User model. This process is illustrated in listing 2.
As you can see in listing 2, after you gain access to the Django shell you import the
User model class and invoke the
create_user() method with the
password arguments. The result of the
create_user() method contains the newly created user.
To confirm the
create_user() method generates a regular user, you can see in listing 2 a call to the various
User model attributes, confirming the user is neither staff or superuser and is just marked as active.
Finally, it's also possible to create users through the Django admin. To do this you'll first need to make sure you have a superuser to access the Django admin. Once you access the Django admin, you'll see a screen like the one Figure 1, click on the 'Users' link. The 'Users' link takes you to a screen like the one in Figure 2, click on the button 'Add User+' in the top right. The 'Add User+' button takes you to a screen like the one in Figure 3 where you can introduce the credentials for a new user.
If you wish to change the sub-type (i.e. superuser, staff) of a user created in this manner, you can also do it in the Django admin, a process that's described in the next section.
Once a user is in a Django application, you'll end up managing him, this could be either revoking his privileges, adding to his privileges or even editing his profile information. You can manage Django users in two ways, in the Django admin or by manipulating a
User model in the Django shell or directly in your application.
The easiest way to manage users is directly in the Django admin. Once you access the Django admin you'll see a screen like the one in Figure 1, if you click on the 'Users' link you'll be taken to a screen like the one in Figure 2 which contains a list of Django users. Each Django user presented in Figure 2 has his username as a link, if you click on this link you'll be taken to the user's page which is illustrated in Figure 4, Figure 5 & Figure 6 where you can edit a user's profile.
The first part of a user's profile you can edit is illustrated in Figure 4, where you can edit his username, his password -- by clicking on the 'small form' link at the end of the small text -- his first name, his last name, as well as his email. In addition, you can see there are three check-boxes where it's possible to change a user's active, staff and superuser status.
If you scroll down, you'll see the second part of a user's profile you can edit which is illustrated in Figure 5. Here you can assign a user to different groups, as well as assign a user individual CRUD permissions over the various Django models. Note I would advise you to carefully evaluate the need to assign individual CRUD permissions to a user, a more flexible approach is to create a group and assign it CRUD permissions and then assign users to this group as needed, this way the permissions become easier to track and reusable for other users.
And if you scroll to the end, you'll see the third part of a user's profile you can edit which is illustrated in Figure 6. Here you can view and update a user's last login, as well as the date a user was created. At the bottom right of the page, you can see the various save buttons to store any changes made to the page. And in addition, at the bottom left there's a 'Delete' button to remove a user completely, however, I would advise you to consider just unchecking a user's active status to restrict access. This last step is sufficient to block a user from accessing an application again and it keeps his other data untouched in case you want to undo the action.
Another option to modify a user's profile is to directly manipulate his
User model record. As illustrated in listing 3, you first make a query for the desired user and then modify the model attributes or execute one of the
User model helper methods.
As you can see in listing 3, you can modify the same
User profile values as those presented in the Django admin in Figures 4, 5 & 6. Just be aware that because you're making a query, any changes made to fields must be followed by a call to the
save() method on the reference for fields to be persisted. Table 1 and table 2 contain a full list of fields and methods available on the
|(Required) 30 characters or fewer and can contain alphanumeric, _, @, +, . and - characters.|
|(Optional) 30 characters or fewer.|
|(Optional) 30 characters or fewer.|
|(Optional) Email address.|
|(Required) A hash of, and metadata about, the password. Note that Django doesn't store the raw password.|
|A many-to-many relationship to |
|A many-to-many relationship to |
|(Boolean) Designates whether a user can access the admin site.|
|(Boolean) Designates whether a user is considered active.|
|(Boolean) Designates whether a user has all permissions without explicitly assigning them.|
|A datetime of the user's last login, set to |
|A datetime designating when the account was created. Is set to the current date/time by default when the account is created.|
|Returns the username for the user. Since the |
|For a |
|For a |
|Returns the |
|Returns the first_name.|
|Sets the user's password to the given raw string, taking care of the password hashing. Note that when the |
|Marks the user as having no password set. Note this isn't the same as having a blank string for a password. |
|Returns a set of group permission strings for the user. If the |
|Returns a set of group and user permission strings for the user. If the |
|Sends an email to the user. If |
|User data under the hood|
Django groups can be created in the Django admin. With a superuser account access the Django admin and you'll see a screen like the one Figure 1, click on the 'Groups' link. The 'Groups' link takes you to a screen like the one in Figure 7, click on the button 'Add Group+' in the top right. The 'Add Group+' button takes you to a screen like the one in Figure 8 where you can create a new group introducing its name.
As you can see in figure 8, all that's need to create a group is a name and you can optionally specify permissions given to the group to Create-Delete-Update Django models in the application.
The management of groups is simpler than users and can also be completely done from the Django admin. What you'll end up doing most of the time is assigning users to groups. To assign a user to a group, when you're editing a user you'll see a selection grid for just this purpose, which is illustrated in Figure 5. To edit a group's properties -- name & Create-Delete-Update Django model permission -- you can do so from the same page where you created it illustrated in Figure 8. To delete a group from the Groups list illustrated in Figure 7, you select the group you wish to delete and select the action from the drop-down list, as illustrated in figure 9.
|Group data under the hood|
One type of permission you've already come in contact in previous sections is the one associated with the ability to Create, Delete or Update Django model records. In the user's section, you can see in Figure 5 a selection grid to assign these types of permissions on an individual basis, as well as in the group's section, you can see in Figure 8 the same selection grid to assign these types of permissions to a group.
This type of Create, Delete or Update permission is managed at the database level through
Permission model records, records which are automatically created when a Django model is installed. Managing this type of permission is very straightforward, as the assignment is made directly on a
User -- illustrated in Figure 5 -- or
Group illustrated in Figure 8.
|Permission data under the hood|
The other type of permission available in Django is to block access to resources (e.g. a URL/view method or template content) based on
Group properties or inclusively
Permission properties assigned to a user or group.
Listing 4 illustrates a series of examples to make permission checks inside the logic of a view method or outright restrict a whole view method based on a permission check. Note that it's thanks to Django's
AuthenticationMiddleware which is enabled by default -- see the recipe Use Django middleware to modify requests & responses if you've never heard of Django middleware -- the
User model record is available on all application requests.
The first example in listing checks if the user is anonymous or not -- using the
is_anonymous() method of the
User model -- which is helpful for cases when you want to execute different workflows based on the requesting user. Note that you can use any
User model field or method -- presented in Table 1 or Table 2 -- to perform a check (e.g.
The second example uses the
@login_required decorator to restrict the execution of a method to those users that are logged in, a process that's common for view methods that generate user-specific or premium content.
The third example uses the
@user_passes_test decorator and defines an in-line test. The snippet
lambda u: Group.objects.get(name='Baristas') in u.groups.all() fetches the
Group model record with the name
Baristas and checks that its part of the requesting user's groups. If the requesting user does not belong to the
Barista group then the test fails and access is denied, otherwise the user is allowed to execute the view method.
The fourth example also uses the
@user_passes_test decorator, but instead of defining an inline test it relies on the
user_of_stores() method to perform the test logic. This is particularly helpful if the test is complex, which can make it hard to follow inline logic, compared to having a regular method. As you can also see in listing 4, the
user_of_stores() verifies if the user is authenticated and also if he has update permissions on the
Store model -- note the string
stores.change_store is the syntax used by Django's
Permission model records.
The last example in listing 4 uses the
@permission_required decorator which is designed to validate if a user has a given
Permission record. In this case, notice the decorator has the input string
stores.add_store which indicates that only users that have permission to add a
Store model can execute the view method.
|What happens when a user fails a permission check ?|
For inline validation checks (e.g.
For the decorator validation checks
In certain circumstances you can have a Djano workflow which doesn't involve a view method and simply sends control from a URL directly to a static template. In such cases, it's also possible to enforce a permission check directly in the URL definition. Listing 5 illustrates similar validation checks like the ones in listing 4 but applied to URL definitions in
As you can see in listing 5, after you import the required decorators you just need to integrate the validation tests in the URL definition. The
permission_required methods are declared as standalone methods followed by the URL definition (e.g.
login_required method though takes the
TemplateView statement as its input. It should be pointed out the behavior for failed tests in listing 5 is the same as those in listing 4, described in the sidebar 'What happens when a user fails a permission check ?'
Another possibility that can arise for validation checks is to perform them on a group of view methods/URLs, so that instead of adding a decorator to each individual view method -- as illustrated in listing 4 -- you only do it once for a whole group. This view method/URL grouping process is particularly common when defining URLs in
urls.py through the
include() method. Listing 6 illustrates how to enforce validation checks on sets of URLs that use the
Because Django doesn't have built-in support for permissions checks in
include() definitions, you can see in listing 6 we first define two custom classes followed by the custom method
decorated_includes. If you follow the sequence in listing 6, you can see the
decorated_includes() method accepts two input arguments, first the permission test (e.g.
permission_required) and then the standard
include() method with the URL definitions. It should also be pointed out the behavior for failed tests in listing 6 is the same as those in listing 5 and 4, described in the sidebar 'What happens when a user fails a permission check ?'
Finally, one last option that's available for permissions checks is in Django templates, a process that's helpful if you want to show/hide content (e.g. links) based on a user's permissions. Listing 7 illustrates a series of Django template syntax examples.
You can see in listing 7 all of the examples directly access the
perms variables. These variables are available on all Django templates thanks to Django's
auth context processor which is enabled by default -- see the recipe Use data provided by default Django context processors if you've never heard of context processors.
The first example in listing 7 checks to see if the user is authenticated through the
is_authenticate field. The second example verifies if
perms -- which holds a user's permissions -- has access to create
Store model records, using Django's
And the third example in listing 7 loops over the users groups, checking to see if one of them is the
Baristas group, if it's it outputs content for users that belong to this group.
|Loops in Django templates to check a property are very inefficient|
Although the last example in listing 7 works, it's a very inefficient mechanism. A better solution is to create a custom filter and perform a direct query in the filter (e.g.
In this case I opted for the syntax in listing 7 to keep everything in one place, but be aware the more efficient solution for this type of logic is to use a custom filter.