Django 管理 - 自定义列表外观和 ManyToManyField 键的选择

Django Administration - Customize list appearance and selection of ManyToManyField keys

我有一个包含 1000 多首歌曲的数据库。我有一个接受歌曲作为字段的自定义模型“Schedule”。

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 管理中的默认列表来实现,looks like this。我必须滚动并按 CTRL+select 每一个,然后添加它们。

我想要更实用的东西select、搜索等

我有哪些选择?我不知道从哪里开始寻找。

选项 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

如果您想要一个舒适的 UI 而无需实施自定义页面或操作(不幸的是,它们完全是一团糟),您应该使用 StackedInline admin.

不过还是比较难。

首先,您需要在两个模型之间设置 through model. (I don't think inlines are possible with auto-generated many-to-many models.) It's basucally your 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 管理界面中看到一个看起来像这样的框(加上歌曲名称的自动完成):