2025, Dec 16 23:00
Edit ManyToMany tags from a mixin in Django Admin TabularInline using the implicit through model
Display and edit ManyToMany tags in Django Admin TabularInline by referencing the implicit through model (.through), even when the field comes from a mixin.
Managing tags across different entities in Django is a common pattern: you centralize the tag model and reuse it through a mixin. Everything goes smoothly until it’s time to expose those tags in Django Admin with a TabularInline. The many-to-many relation exists, the implicit join table exists too, but what exactly should be passed to the inline as its model? Ниже кратко разбираем, где возникает стопор и как его корректно обойти.
Minimal setup that exposes the issue
Представим базовую структуру с общей сущностью для тегов и миксином, который добавляет поле 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 # what goes here?
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
list_display = ("id", "name")
inlines = [ProductLabelInline]
What actually causes the configuration gap
ManyToManyField создаёт отдельную «связующую» таблицу. Она формируется неявно и прозрачно для модели, поэтому при создании сущностей всё работает без ручных настроек. Но в админке TabularInline ожидает конкретную модель, на которую можно сослаться. Поскольку сама связь — это отдельная сущность, её и нужно передать. Отсюда и пауза: поле есть, а явной модели, которую можно подставить в inline, нет на виду.
Solution: reference the implicit through model
Указание .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 создал «за кадром».
Why this matters for real projects
Когда теги или любые метки используются повсеместно, естественно хотеть управлять ими прямо на странице сущности. Без правильной привязки к связующей модели инлайны не работают, и приходится переключаться между экранами. Подстановка .through упрощает админский UX и избавляет от лишней рутины.
Takeaways
Если ManyToMany нужно редактировать через inline в Django Admin, указывайте связующую модель поля через .through. Это работает одинаково и для прямых определений поля, и для случаев с миксинами. В итоге вы получаете прозрачную настройку админки без дополнительных сущностей и лишнего кода.