Для начала перейдем в командную строку и создадим приложение с названием accounts:
python manage.py startapp accounts
Модель
Открываем каталог с приложением и наполняем файл models.py:
from django.db import models
from django.contrib.auth.models import UserManager, AbstractUser
class ActiveUsersManager(UserManager):
def get_queryset(self):
return super(ActiveUsersManager, self).get_queryset().filter(is_active=True)
class InactiveUsersManager(models.Manager):
def get_queryset(self):
return super(InactiveUsersManager, self).get_queryset().filter(is_active=False, last_login__isnull=True)
class User(AbstractUser):
username = models.CharField('псевдоним или настоящее имя', max_length=255, unique=True)
email = models.EmailField('адрес электронной почты', blank=True, null=True, unique=True)
objects = UserManager()
active = ActiveUsersManager()
inactive = InactiveUsersManager()
Django уже содержит базовое приложение аутентификации и авторизации. Вдобавок поставляется с готовыми моделями. Которые позволяют либо использовать стандартного пользователя, либо абстрактный класс, дополняя или изменяя поля модели на свой вкус.
По умолчанию имя учетной записи пользователя не позволяет указывать пробел между словами. А в последнее время заметна тенденция в сторону отказа от псевдонимов и регистрация под "настоящим именем". При проектировании новой системы нет смысла ограничивать пользователя, предоставим ему право сделать осознанный выбор.
Ограничения вшиты непосредственно в само поле, поэтому мы его переопределим и заодно выставим максимальную длину имени — 255 символов.
Адрес электронной почты по умолчанию не является уникальным, поправим это, но сохраним стандартное поведение, оставим поле необязательным для заполнения. Например, в будущем, если мы будем проводить упрощенную регистрацию через социальные сети нам не всегда будет доступна информация об адресе электронной почты пользователя.
Менеджеры
По умолчанию используется менеджер объектов от стандартной модели пользователя. В результирующий набор данных поступят все пользователи без каких-либо ограничений. Например, сторонние приложения не могут предвидеть вновь разработанные менеджеры и используют менеджер с заранее установленным названием objects.
В модели пользователя есть поле активности, например, если пользователя необходимо заблокировать, надлежит выставить соответствующий статус.
Цель ActiveUsersManager очень проста, отфильтровать пользователей, по выставленному признаку активности, тем самым подтверждая, что эти пользователи не имеют каких-либо ограничений.
А вот InactiveUsersManager поинтереснее, после регистрации пользователя, нам необходимо подтверждение, что адрес электронный почты указан верно. Поэтому пользователь еще не активен, но необходимо установить причину: заблокирован или просто не подтвержден.
Можно добавить новое поле с четким указыванием причины или поступить изящнее и воспользоваться другой информацией о пользователе.
В модели пользователя присутствует поле с датой последнего входа, соответственно мы можем с легкостью определить причину неактивности аккаунта. Человек, который ни разу не заходил в систему, находится в статусе ожидания подтверждения адреса электронной почты.
Бэкэнд
Для аутентификации пользователей мы планируем использовать связку: адрес электронной почты и пароль, а стандартный бэкэнд ожидает ввода имени учетной записи.
Нам необходимо разработать свой бэкэнд аутентификации, в директории приложения создаем файл backends.py:
from django.contrib.auth.backends import ModelBackend
from .models import User
class EmailBackend(ModelBackend):
def authenticate(self, email=None, password=None, **kwargs):
if email and password:
try:
user = User.active.get(email=email)
except User.DoesNotExist:
return None
if user.check_password(password):
return user
def get_user(self, pk):
try:
return User.active.get(pk=pk)
except User.DoesNotExist:
return None
Бэкэнд имеет два обязательных метода: authenticate и get_user.
Первый анализирует есть ли среди активных пользователей аккаунт с введенным адресом электронной почты. И в случае успеха проверяет пароль через специальную функцию, поскольку все пароли в модели хранятся в зашифрованном виде.
Второй метод просто возвращает активного пользователя по его идентификационному номеру, но уже без процедуры аутентификации.
Настройки
Для внесения корректив открываем settings.py и добавляем приложение accounts:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'core.apps.CoreConfig',
'accounts.apps.AccountsConfig',
]
Далее мы указываем путь до нашей модели пользователей и добавляем разработанный бэкэнд в список аутентификаций:
AUTH_USER_MODEL = 'accounts.User'
ACCOUNTS_EMAILBACKEND = 'accounts.backends.EmailBackend'
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
ACCOUNTS_EMAILBACKEND,
]
Стандартный бэкэнд перечислен для совместимости с другими приложениями. Например, раздел администрирования будет ожидать стандартную пару аутентификационных данных.
Миграции
После любых изменений моделей, включая создание новых, необходимо создать файлы миграций командой makemigrations:
python manage.py makemigrations
Затем используем команду migrate:
python manage.py migrate
Выполняя все миграции, которые еще не были зафиксированы в базе данных на данный момент.
Администрирование
Для задач, связанных с администрированием справится стандартное приложение admin. Мы возьмем готовые формы: редактирование и добавление пользователей, просто изменив модель на нами разработанную.
Переходим в файл admin.py и приводим к следующему виду:
from django.contrib import admin
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from django.contrib.auth.admin import UserAdmin as _UserAdmin
from .models import User
class UserChangeAdminForm(UserChangeForm):
class Meta(UserChangeForm.Meta):
model = User
class UserCreationAdminForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = User
@admin.register(User)
class UserAdmin(_UserAdmin):
form = UserChangeAdminForm
add_form = UserCreationAdminForm
Укажем читабельное название для нашего приложения, отредактировав файл apps.py:
from django.apps import AppConfig
class AccountsConfig(AppConfig):
name = 'accounts'
verbose_name = 'Аккаунты'
Используя команду createsuperuser создаем супер-пользователя:
python manage.py createsuperuser
Указывая имя учетной записи, адрес электронной почты и пароль.
Далее запускаем отладочный сервер командой runserver:
python manage.py runserver 8000
И переходим к разделу администратора по локальной ссылке: http://127.0.0.1:8000/admin/.