Администрирование Django - Настройка внешнего вида списка и выбора ключей ManyToManyField
У меня есть база данных с 1000+ песнями. У меня есть пользовательская модель "Расписание", которая принимает песни в качестве поля.
models.py
from django.db import models
class Song(models.Model):
    title = models.CharField(max_length=255)
    words = models.TextField()
    slug = models.SlugField()
    date = models.DateTimeField(auto_now_add=True)
    snippet = models.CharField(max_length=50)
    def __str__(self):
        return self.title
class Schedule(models.Model):
    songs = models.ManyToManyField(Song)
    date = models.DateTimeField(auto_now_add=True)
    def __str__(self):
        return str(self.date)
admin.py
from django.contrib import admin
from .models import Song, Schedule
@admin.register(Song)
class SongModel(admin.ModelAdmin):
    search_fields = ('title',)
    list_display = ('title',)
    list_per_page = 100
@admin.register(Schedule)
class ScheduleModel(admin.ModelAdmin):
    search_fields = ('date',)
    list_display = ('date',)
    list_per_page = 100
Я хочу иметь возможность добавить любую песню, которую я хочу, в расписание, но это трудно сделать через список по умолчанию в Django-Administration, который выглядит так. Мне приходится прокручивать и CTRL+выбирать каждую из них, а затем добавлять их.
Хотелось бы чего-то более практичного, где можно выбирать, искать и т.д.
Какие у меня есть варианты? Я не знаю, с чего начать поиски.
Вариант 1
Это удобно, только если у вас очень мало связанных элементов (несколько песен в расписании). Но это супер просто и будет лучше, чем то, что вы имеете сейчас. (django.contrib.admin поставляется со встроенным select2.)
@admin.register(Schedule)
class ScheduleAdmin(admin.ModelAdmin):
    ...
    autocomplete_fields = ("songs",)
Вариант 2
(upd: черт, забыл сначала, это тоже супер просто и довольно эффективно)
Выглядит неплохо. Полезно. Не особенно удобно. Но лучше, чем нажимать на клавишу ctrl.
@admin.register(Schedule)
class ScheduleAdmin(admin.ModelAdmin):
    ...
    filter_horizontal = ('songs',)
Вариант 3
Если вам нужен удобный пользовательский интерфейс без внедрения пользовательских страниц или действий (которые, к сожалению, являются полным беспорядком), вам следует использовать StackedInline admin.
Хотя это гораздо сложнее.
Сначала вам понадобится сквозная модель. (Я не думаю, что inlines возможен с автоматически генерируемыми моделями "многие-ко-многим".) В основном, это many-to-many между двумя моделями. Что-то вроде этого:
class ScheduleSongNM(models.Model):
    song = models.ForeignKey("Song", null=False)
    schedule = models.ForeignKey("Schedule", null=False)
 Укажите вашей модели Schedule использовать вашу пользовательскую сквозную модель: 
class Schedule(models.Model):
    songs = models.ManyToManyField(Song, through="ScheduleSongNM")
 Теперь создайте встроенного администратора для ScheduleSongNM:
class ScheduleSongInline(admin.StackedInline):
    model = ScheduleSongNM
    fields = ["song"]
    autocomplete_fields = ["song"]  # select2 works here too
 Наконец, скажите вашему Schedule администратору, что у него теперь есть инлайн:
@admin.register(Schedule)
class ScheduleAdmin(admin.ModelAdmin):
    ...
    inlines = [ScheduleSongInline]
    ...
 Возможно, я что-то упустил (очевидно, я не тестировал это), но я думаю, что вы поняли общую идею. В итоге вы получаете поле внутри вашей админки Schedule, которое выглядит примерно так (плюс автозавершение для названий песен):
