2026, Jan 08 15:01
Редактирование ManyToMany через TabularInline в Django Admin
Как отобразить и редактировать ManyToMany в Django Admin через TabularInline: решаем проблему с неявной связующей моделью, используем поле .through.
Управление тегами для разных сущностей в Django — распространенный подход: вы централизуете модель тега и переиспользуете её через миксин. Всё идет гладко, пока не возникает задача показать эти теги в Django Admin с TabularInline. Связь many-to-many есть, неявная промежуточная таблица тоже, но какую именно модель передать инлайну? Ниже кратко разбираем, где возникает стопор и как его корректно обойти.
Минимальная конфигурация, на которой проявляется проблема
Представим базовую структуру с общей сущностью для тегов и миксином, который добавляет поле ManyToMany. Логика проста: базовая таблица labels и миксин для любой модели, которой нужны метки.
from django.db import models
class Label(models.Model):
title = models.CharField(max_length=64, unique=True)
class LabelsBase(models.Model):
class Meta:
abstract = True
labels = models.ManyToManyField(Label, blank=True)
class Product(LabelsBase):
name = models.CharField(max_length=64)
В админке хочется отобразить labels как TabularInline у Product. На уровне кода это упирается в вопрос: что указать в model у инлайна?
from django.contrib import admin
class ProductLabelInline(admin.TabularInline):
model = None # что указать здесь?
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
list_display = ("id", "name")
inlines = [ProductLabelInline]
В чём на самом деле причина пробела в конфигурации
ManyToManyField создаёт отдельную «связующую» таблицу. Она формируется неявно и прозрачно для модели, поэтому при создании сущностей всё работает без ручных настроек. Но в админке TabularInline ожидает конкретную модель, на которую можно сослаться. Поскольку сама связь — это отдельная сущность, её и нужно передать. Отсюда и пауза: поле есть, а явной модели, которую можно подставить в inline, нет на виду.
Решение: сослаться на неявную промежуточную модель
Указание .through у поля ManyToManyField выдает ту самую модель, которая соответствует связующей таблице. Этого достаточно, чтобы TabularInline знал, с чем работать.
from django.contrib import admin
class ProductLabelInline(admin.TabularInline):
model = Product.labels.through
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
list_display = ("id", "name")
inlines = [ProductLabelInline]
Суть в одном действии: использовать Product.labels.through. Это прямой доступ к промежуточной модели, которую ManyToMany создал «за кадром».
Почему это важно для реальных проектов
Когда теги или любые метки используются повсеместно, естественно хотеть управлять ими прямо на странице сущности. Без правильной привязки к связующей модели инлайны не работают, и приходится переключаться между экранами. Подстановка .through упрощает админский UX и избавляет от лишней рутины.
Итоги
Если ManyToMany нужно редактировать через inline в Django Admin, указывайте связующую модель поля через .through. Это работает одинаково и для прямых определений поля, и для случаев с миксинами. В итоге вы получаете прозрачную настройку админки без дополнительных сущностей и лишнего кода.