← Назад к вопросам

Какие есть способы расширения модели пользователя в Django?

1.0 Junior🔥 231 комментариев
#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Какие есть способы расширения модели пользователя в Django?

Это очень частый вопрос, потому что встроенный User в Django часто недостаточен. Есть несколько проверенных способов, каждый с плюсами и минусами.

Способ 1: AbstractBaseUser (РЕКОМЕНДУЕТСЯ)

Создаёшь свой User с нуля, наследуя от AbstractBaseUser:

# models.py
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.db import models

class CustomUserManager(BaseUserManager):
    def create_user(self, email, password=None):
        user = self.model(email=email)
        user.set_password(password)
        user.save(using=self._db)
        return user
    
    def create_superuser(self, email, password):
        user = self.create_user(email, password)
        user.is_staff = True
        user.is_superuser = True
        user.save(using=self._db)
        return user

class CustomUser(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True)
    first_name = models.CharField(max_length=150, blank=True)
    last_name = models.CharField(max_length=150, blank=True)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    date_joined = models.DateTimeField(auto_now_add=True)
    
    # НОВЫЕ ПОЛЯ
    phone = models.CharField(max_length=20, blank=True)
    avatar = models.ImageField(upload_to='avatars/', null=True, blank=True)
    bio = models.TextField(blank=True)
    
    objects = CustomUserManager()
    
    USERNAME_FIELD = 'email'  # Логин через email вместо username
    REQUIRED_FIELDS = []       # Поля для createsuperuser
    
    class Meta:
        db_table = 'auth_user'  # Чтобы не создавалась новая таблица
    
    def __str__(self):
        return self.email

settings.py:

AUTH_USER_MODEL = 'yourapp.CustomUser'  # ВАЖНО!

Плюсы:

  • Полный контроль над моделью
  • Можно менять USERNAME_FIELD
  • Легко добавлять новые поля
  • Best practice в современном Django

Минусы:

  • Нужно создать собственный UserManager
  • Больше кода в начале
  • Миграция существующего проекта сложнее

Способ 2: OneToOneField (Profile pattern)

Создаёшь отдельную модель, связанную с встроенным User:

from django.contrib.auth.models import User
from django.db import models

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
    phone = models.CharField(max_length=20, blank=True)
    avatar = models.ImageField(upload_to='avatars/', null=True, blank=True)
    bio = models.TextField(blank=True)
    date_of_birth = models.DateField(null=True, blank=True)
    
    def __str__(self):
        return f"{self.user.username}'s Profile"

# Использование
user = User.objects.get(username='john')
print(user.profile.phone)  # Доступ через related_name

# Автоматическое создание профиля
from django.db.models.signals import post_save

@post_save.connect(sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)

Плюсы:

  • Простой способ добавить поля
  • Не трогаем встроенный User
  • Отличное разделение ответственности
  • Работает с существующей БД

Минусы:

  • Дополнительная таблица в БД
  • Нужно создавать профиль через сигналы
  • Немного медленнее (JOIN при каждом запросе)

Способ 3: ForeignKey (для множества профилей)

Если пользователю нужно несколько профилей:

from django.contrib.auth.models import User
from django.db import models

class Profile(models.Model):
    ROLE_CHOICES = [
        ('admin', 'Administrator'),
        ('user', 'Regular User'),
        ('moderator', 'Moderator'),
    ]
    
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='profiles')
    role = models.CharField(max_length=20, choices=ROLE_CHOICES)
    department = models.CharField(max_length=100)
    is_active = models.BooleanField(default=True)
    
    class Meta:
        unique_together = ('user', 'role')  # Один пользователь одну роль

# Использование
user = User.objects.get(username='john')
for profile in user.profiles.all():
    print(profile.role)

Способ 4: Наследование (Multi-table inheritance)

Создаёшь специализированные пользователи через наследование:

from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    phone = models.CharField(max_length=20, blank=True)
    avatar = models.ImageField(upload_to='avatars/', null=True, blank=True)

class Administrator(CustomUser):
    access_level = models.IntegerField(default=1)
    
    class Meta:
        proxy = False  # Создаёт отдельную таблицу

class Moderator(CustomUser):
    permissions = models.JSONField(default=dict)

Плюсы:

  • Объектно-ориентированно
  • Специализированные типы пользователей

Минусы:

  • Много таблиц в БД
  • Сложно в тестировании
  • Может быть медленнее

Способ 5: JSONField (для гибких данных)

Добавишь дополнительные данные в JSON без миграций:

from django.contrib.auth.models import User
from django.db import models

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    metadata = models.JSONField(default=dict)  # Гибкие данные

# Использование
user = User.objects.get(username='john')
user.profile.metadata = {
    'phone': '+1234567890',
    'avatar': '/media/avatar.jpg',
    'preferences': {
        'theme': 'dark',
        'notifications': True
    }
}
user.profile.save()

Плюсы:

  • Очень гибко
  • Не нужны миграции для новых полей
  • Отличный для экспериментов

Минусы:

  • Нет типизации
  • Сложно фильтровать в QuerySet
  • Валидация на уровне приложения

Сравнительная таблица

Способ                 Новая таблица  Сложность  Производительность
=================================================================
AbstractBaseUser       Нет            Высокая    Отличная
OneToOneField (Profile) Да            Низкая     Хорошая
ForeignKey            Да            Средняя    Хорошая
Multi-table наследование Да          Высокая    Средняя
JSONField             Нет            Низкая     Хорошая

Мой рекомендуемый подход

Для нового проекта: AbstractBaseUser

# Это best practice
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    email = models.EmailField(unique=True)
    phone = models.CharField(max_length=20, blank=True)
    avatar = models.ImageField(upload_to='avatars/', null=True, blank=True)
    
    USERNAME_FIELD = 'email'
    
    class Meta:
        db_table = 'auth_user'

Для существующего проекта: OneToOneField

# Не трогаем встроенный User
class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
    # НОВЫЕ ПОЛЯ

На собеседовании

"Есть несколько способов расширить пользователя в Django:

  1. AbstractBaseUser — для нового проекта (РЕКОМЕНДУЕТСЯ). Создаешь свой User с нуля.

  2. OneToOneField (Profile pattern) — для существующего проекта. Отдельная таблица с профилем пользователя.

  3. ForeignKey — если нужно несколько профилей на одного пользователя.

  4. Multi-table наследование — для специализированных типов пользователей.

  5. JSONField — для гибких данных без миграций.

Я предпочитаю AbstractBaseUser в новых проектах, потому что это даёт полный контроль и это best practice Django."

Этот ответ покажет твой опыт работы с Django.

Какие есть способы расширения модели пользователя в Django? | PrepBro