Django расширение модели User
Если вы создаете новый проект на Django , то я рекомендую использовать пользовательскую модель User , которая расширяется от подкласса AbstractBaseUser. Вы конечно , можете этого не делать и использовать другие стратегии , такие как:
Но по моему личному мнению расширение от подкласса AbstractBaseUser является самым гибким способом, хоть и вначале требует определенных усилий для его реализации.
Вначале я вкратце расскажу о других стратегиях расширения модели User. Об их достоинствах и недостатках. А потом мы реализуем создание пользовательской модели с помощью расширения от подкласса AbstractBaseUser
Использование прокси-модели
Эта стратегия используется в том случае , когда нам не нужны новые поля для модели User или переопределения существующих полей, но нужны поведенческие изменения , такие как переопределение сортировки по умолчанию, добавление новых методов для работы с моделью ,использование пользовательских менеджеров.
class CustomUser(User):
objects = PersonManager()
class Meta:
proxy = True
ordering = ('first_name', )
Тут мы создаем прокси-модель Person , которая наследуется от User.Внутри Meta мы указываем proxy=True , чтобы указать , что это модель является прокси. И для этой модели в базе данных не создается таблица.
Достоинством этой стратегии является простота реализации.И эту стратегию вы можете использовать не только при создании проекта , но на любом этапе жизненнего цикла вашего проекта.
Недостатком - ограниченность, так как мы не можем создавать новые поля или переопределять существующие поля.
Использование связи один-к-одному с пользовательской моделью
Если нам нужно хранить дополнительную информацию о существующей модели пользователя и которая не связана с аутентификацией , то мы можем создать новую модель , которая будет связана с существующим моделем User c помощью связи один-к-одному.
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
avatar = models.TextField(max_length=500, blank=True)
bith_date = models.TextField(max_length=500, blank=True)
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
Достоинством данной стратегии является то , что мы можем создать новые поля и это можно сделать не только при создании проекта , но в любой момент времени когда вам это понадобится.
Недостатком данной стратегии является то , что у нас будет еще одна таблица с полями для пользователя и создаются лишние запросы при обращении к связанным данным. Это можно в определенной мере решить с использованием selected_related
Расширение от подкласса AbstractUser
Этот способ в отличие от предыдущих , нужно реализовывать вначале создания проекта перед применением миграций.
Этот метод используется в том случае если вас устраивает аутентификация в том виде , которая предоставляется стандартно , но вам нужно добавить новые данные , но в отличие от прокси-модели не создаете новый класс или создание новой модели с таблицей , как при использовании стратегии использование связи один-к-одному с пользовательской моделью.
Класс django.contrib.auth.models.AbstractUser обеспечивает полную реализацию пользователя по умолчанию как абстрактную модель
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
birth_date = models.DateField(null=True, blank=True)
AUTH_USER_MODEL = 'users.User'
Расширение от подкласса AbstractBaseUser
Ну и в конце я создам пользовательскую модель путем расширения от класса AbstractBaseUser. Этот способ считается сложным , а некоторые советуют его применять в крайнем случае, но по мне для сложных проектов этот способ является самым предпочитаемым. Но это дело вкуса.
Часто в моих проектах в качестве логина используется либо email или номер телефона. А поле username нам вообще не нужен. Так что мы при создании модели , который наследуются от AbstractBaseUser , можем указать поле , который используется в качестве логина. Хотя , я видел статью где это можно сделать и при расширении от класса AbstractUser.
Ну довольно теории. Создадим виртуальное окружение , установим Django и создадим новый проект.
Создадим новое приложение users и в файле models.py создадим модель User , который будет наследоваться от AbstractBaseUser и от миксина PermissionsMixin
import os
import datetime
import os.path
from django.db import models
from django.conf import settings
from django.utils import timezone
from django.core.validators import RegexValidator
from django.contrib.auth.models import (
BaseUserManager, AbstractBaseUser, PermissionsMixin
)
class UserManager(BaseUserManager):
def create_user(self, email, password=None,**kwargs):
if not email:
raise ValueError('Users must have an Email')
user = self.model(
email=email,**kwargs)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password):
"""
Creates and saves a superuser with the given email and password.
"""
user = self.create_user(
email,
password=password
)
user.is_admin = True
user.save(using=self._db)
return user
class User(AbstractBaseUser,PermissionsMixin):
email = models.EmailField(max_length=255, unique=True)
first_name = models.CharField('Фамилия', max_length=255, blank=True, null=True)
last_name = models.CharField('Имя', max_length=255, blank=True, null=True)
avatar = models.ImageField(null=True, blank=True, upload_to='avatars')
date_of_birth = models.DateField(verbose_name="Дата рождения", null=True, blank=True)
last_time_visit = models.DateTimeField(default=timezone.now)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
def __str__(self):
return self.email
class Meta:
verbose_name = 'Пользователь'
verbose_name_plural = 'Пользователи'
Создайте миграции для users. Важно , это вы должны сделать до применения первоначальных миграций
python manage.py makemigrations
Применяем все миграции проекта
python manage.py migrate
Заключение
Для простых проектов вы можете использовать встроенную модель без расширения, так как он из коробки работает прекрасно и выполняет базовые вещи. Для простых сайтов , где не нужна особо работа с пользователями , то применятся вариант из коробки. Для этого блога это вполне хватает ))
Но если вы разрабатываете сложные проекты , то я рекомендую расширять пользовательскую модель. Вначале это сложно и требует некоторых усилий , но в дальнейшем это окупится.