Атрибут fk_name

Атрибут fk_name класса StackedInline указывает, какое именно поле внешнего ключа следует использовать, если между родительской и дочерней моделями существует более одной связи. Этот атрибут обязателен, когда модель содержит несколько внешних ключей на одну и ту же модель.

Синтаксис

pythonclass MyInline(StackedInline):
  model = ChildModel
  fk_name = 'field_name'

Пример

Рассмотрим модели, где статья имеет автора и редактора, оба являются пользователями:

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

class Article(models.Model):
  title = models.CharField(max_length=200)
  content = models.TextField()
  author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='authored_articles')
  editor = models.ForeignKey(User, on_delete=models.CASCADE, related_name='edited_articles')
  created_at = models.DateTimeField(auto_now_add=True)

В административной панели мы хотим редактировать статьи пользователя, но Django не знает, какое поле внешнего ключа использовать:

pythonfrom django.contrib import admin
from myapp.models import Article, User

class ArticleInline(StackedInline):
  model = Article
  # Django не может определить, какое поле ForeignKey использовать

@admin.register(User)
class UserAdmin(admin.ModelAdmin):
  inlines = [ArticleInline]

Чтобы решить эту проблему, укажем fk_name:

pythonfrom django.contrib import admin
from myapp.models import Article, User

class ArticleInline(StackedInline):
  model = Article
  fk_name = 'author'  # Явно указываем, что используем поле author

@admin.register(User)
class UserAdmin(admin.ModelAdmin):
  inlines = [ArticleInline]

Пример

Теперь создадим административный интерфейс для модели 'Category', где используются два внешних ключа на модель 'Product':

pythonfrom django.db import models

class Product(models.Model):
  name = models.CharField(max_length=100)
  price = models.DecimalField(max_digits=10, decimal_places=2)

class Category(models.Model):
  name = models.CharField(max_length=100)
  main_product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True, related_name='main_categories')
  secondary_product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True, related_name='secondary_categories')

Создадим inline для редактирования категорий внутри продукта:

pythonfrom django.contrib import admin
from myapp.models import Product, Category

class CategoryInline(StackedInline):
  model = Category
  fk_name = 'main_product'
  extra = 1

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
  list_display = ('name', 'price')
  inlines = [CategoryInline]

В результате в интерфейсе администратора для продукта отобразятся только те категории, где 'main_product' указывает на данный продукт, и будет возможность добавлять новые категории с этим продуктом в качестве основного.

python# Результат: в админке продукта отображаются категории,
# где main_product_id равен id текущего продукта

Смотрите также

  • класс StackedInline,
    который используется для создания вертикальных inline-форм в административной панели
  • класс TabularInline,
    который создает горизонтальные inline-формы для отображения связанных объектов
  • атрибут model,
    который указывает модель для inline-редактирования
  • атрибут inlines,
    который определяет набор inline-классов для модели в административной панели