Администрирование 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
, которое выглядит примерно так (плюс автозавершение для названий песен):