I have a database with 1000+ songs. I have a custom model "Schedule" that accepts songs as field.
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
I want to be able to add any song I want to a schedule, but it is difficult do to so through the default list in the Django-Administration, which looks like this. I have to scroll and CTRL+select each one of them, then add them.
I'd like something more more practical where I can select, search, etc.
What are my options? I don't know where to start looking.
It's only comfortable if you have very few related items (few songs in schedule). But it is super easy and will be better than what you have now. (django.contrib.admin comes with built-in select2.)
@admin.register(Schedule)
class ScheduleAdmin(admin.ModelAdmin):
...
autocomplete_fields = ("songs",)
(upd: damn, forgot it at first, it's also super simple and quite efficient)
It looks alright-ish. Usable. Not particularly comfortable. But better than ctrl-clicking the stuff.
@admin.register(Schedule)
class ScheduleAdmin(admin.ModelAdmin):
...
filter_horizontal = ('songs',)
If you want a comfortable UI without implementing custom pages or actions (which are unfortunately a complete mess), you should use a StackedInline admin.
It's quite a bit more difficult though.
First you will need a through model. (I don't think inlines are possible with auto-generated many-to-many models.) It's basucally your many-to-many between the two models. Something like that:
class ScheduleSongNM(models.Model):
song = models.ForeignKey("Song", null=False)
schedule = models.ForeignKey("Schedule", null=False)
Tell your Schedule
model to use your custom through model:
class Schedule(models.Model):
songs = models.ManyToManyField(Song, through="ScheduleSongNM")
Now create an inline admin for the ScheduleSongNM
:
class ScheduleSongInline(admin.StackedInline):
model = ScheduleSongNM
fields = ["song"]
autocomplete_fields = ["song"] # select2 works here too
Finally, tell your Schedule
admin that it has an inline now:
@admin.register(Schedule)
class ScheduleAdmin(admin.ModelAdmin):
...
inlines = [ScheduleSongInline]
...
Maybe I missed something (obviously I haven't tested it), but I think you got the general idea. In the end you get a box inside of your Schedule
admin that looks something like that (plus auto completion for song names):