Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Proxy модель в Django — одна таблица, несколько интерфейсов
Proxy модель позволяет создать несколько моделей, указывающих на одну таблицу в БД, но с разными методами и поведением. Это решение задач без дублирования данных.
Проблема без proxy
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
role = models.CharField(max_length=50)
class Meta:
db_table = 'person'
Если нужны разные методы для Admins vs Users:
# ❌ Неправильно — создаём лишнюю таблицу
class User(models.Model):
person_ptr = models.OneToOneField(Person, on_delete=models.CASCADE, parent_link=True)
class Meta:
db_table = 'user' # Новая таблица!
Это создаст person и user таблицы с joins.
Решение: Proxy модель
class Person(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
role = models.CharField(max_length=50)
class Meta:
db_table = 'person'
# ОДНА таблица — person
class Admin(Person):
class Meta:
proxy = True # ← Ключевая строка!
def grant_permission(self, permission):
# Специальный метод только для админов
self.permissions.add(permission)
def deactivate_user(self, user_id):
# Специальный метод для администрирования
User.objects.filter(id=user_id).update(is_active=False)
class RegularUser(Person):
class Meta:
proxy = True
def get_posts(self):
# Специальный метод для пользователей
return Post.objects.filter(author=self)
В БД всё ещё одна таблица person!
Практический пример
# models.py
class User(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
is_staff = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
# Proxy для администраторов
class Administrator(User):
class Meta:
proxy = True
def __str__(self):
return f"Admin: {self.name}"
def has_permission(self, perm):
return True # Админы имеют все прав
# Proxy для обычных пользователей
class RegularUser(User):
class Meta:
proxy = True
def __str__(self):
return f"User: {self.name}"
def has_permission(self, perm):
return False # Обычные пользователи без прав
# Использование
admin = Administrator.objects.create(name="Alice", is_staff=True)
user = RegularUser.objects.create(name="Bob", is_staff=False)
print(admin.has_permission("delete_user")) # True
print(user.has_permission("delete_user")) # False
# Оба находятся в таблице user!
print(User.objects.count()) # 2
print(Administrator.objects.count()) # 1
print(RegularUser.objects.count()) # 1
Применение в Django Admin
from django.contrib import admin
from django.contrib.admin import ModelAdmin
# Одна модель — несколько Admin интерфейсов
class AdminAdmin(admin.ModelAdmin):
list_display = ['name', 'email', 'permissions']
actions = ['grant_admin_rights', 'revoke_admin_rights']
def grant_admin_rights(self, request, queryset):
queryset.update(is_staff=True)
class RegularUserAdmin(admin.ModelAdmin):
list_display = ['name', 'email', 'created_at']
readonly_fields = ['created_at'] # Обычные пользователи видят только чтение
admin.site.register(Administrator, AdminAdmin)
admin.site.register(RegularUser, RegularUserAdmin)
В Django Admin они будут в разных списках!
Запросы с Proxy
# Получить всех пользователей
User.objects.all() # 2 человека
# Получить только админов
Administrator.objects.all() # 1 человек
# Получить только обычных пользователей
RegularUser.objects.all() # 1 человек
# Отфильтровать по is_staff
User.objects.filter(is_staff=True) # Админы
Преимущества Proxy
✅ Одна таблица — нет дублирования данных
✅ Нет migration — структура БД не меняется
✅ Отдельный интерфейс — разные Admin views
✅ Разная бизнес-логика — свои методы
✅ Переиспользование — базовые поля есть
Когда НЕ использовать Proxy
# ❌ Proxy НЕ подходит — нужны новые поля
class Student(Person): # Нужны поля: student_id, gpa
class Meta:
proxy = True # ПЛОХО!
# ✅ Используй наследование с новой таблицей
class Student(Person):
student_id = models.CharField(max_length=20)
gpa = models.FloatField()
# Будет две таблицы: person и student
Типовые use cases
1. Роли пользователей
class User(models.Model): # Одна таблица
name = models.CharField()
role = models.CharField()
class Moderator(User):
proxy = True
def ban_user(self, user): pass
class Contributor(User):
proxy = True
def create_post(self): pass
2. Состояния объектов
class Order(models.Model):
status = models.CharField()
class PendingOrder(Order):
proxy = True
def approve(self): pass
class CompletedOrder(Order):
proxy = True
def archive(self): pass
3. Специализированные QuerySets
class PublishedPostManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(published=True)
class PublishedPost(Post):
proxy = True
objects = PublishedPostManager()
Итог
Proxy модель нужна для:
✅ Разных интерфейсов для одного объекта
✅ Разной бизнес-логики без дублирования данных
✅ Разных Admin views в Django
✅ Специализированных QuerySets
Не путать с наследованием моделей, которое создаёт новую таблицу.