如何在Django中按多字段排序对象并分碟展示音乐专辑曲目?
Got it, let's get your multi-disc album tracks showing in the format you want. Here's a straightforward way to do it using Django's built-in template tags and a small adjustment to your view.
Step 1: Update the View to Sort Tracks by Disc First
First, we need to make sure our tracks are ordered by disc number (and then track number) so we can group them correctly in the template. Modify your view code like this:
def music_album_detail(request, pk): music_album = get_object_or_404(MusicAlbums, pk=pk) # Order by disc first, then track number to ensure proper grouping music_album_tracks = MusicTracks.objects.filter(album=music_album).order_by('disc', 'track') args = { 'music_album': music_album, 'music_album_tracks': music_album_tracks, } return render(request, 'App/music_album_detail.html', args)
Step 2: Use Django's regroup Tag in the Template
Now, use Django's {% regroup %} template tag to group tracks by their disc number. Then loop through each disc group to display the disc label followed by the track names separated by " - ".
Replace your existing template loop with this:
{% regroup music_album_tracks by disc as disc_groups %} {% for disc_group in disc_groups %} <p> {# Handle cases where disc number might be null (default to 1) #} 碟{{ disc_group.grouper|default:1 }} {% for track in disc_group.list %} {% if not forloop.first %} - {% endif %} {{ track.title }} {% endfor %} </p> {% endfor %}
How This Works:
{% regroup ... %}takes your sorted track list and groups them by thediscfield, creating a list of groups where each group has agrouper(the disc number) and alistof tracks in that disc.- The
|default:1filter ensures that any tracks with no disc number set will be grouped under "碟1". - The inner loop adds " - " before each track except the first one, giving you the exact format you want.
Example Output:
If you have 2 discs with 4 tracks each, this will render:
碟1 - 曲目名1 - 曲目名2 - 曲目名3 - 曲目名4
碟2 - 曲目名1 - 曲目名2 - 曲目名3 - 曲目名4
Alternative: Group in the View with itertools.groupby
If you prefer to handle grouping in the view instead of the template, you can use Python's itertools.groupby. Here's how:
Update your view:
from itertools import groupby from operator import attrgetter def music_album_detail(request, pk): music_album = get_object_or_404(MusicAlbums, pk=pk) tracks = MusicTracks.objects.filter(album=music_album).order_by('disc', 'track') # Group tracks by disc number disc_groups = [] for disc_num, track_group in groupby(tracks, key=attrgetter('disc')): disc_groups.append({ 'disc_number': disc_num or 1, 'tracks': list(track_group) }) args = { 'music_album': music_album, 'disc_groups': disc_groups, } return render(request, 'App/music_album_detail.html', args)
Then your template becomes simpler:
{% for disc in disc_groups %} <p> 碟{{ disc.disc_number }} {% for track in disc.tracks %} {% if not forloop.first %} - {% endif %} {{ track.title }} {% endfor %} </p> {% endfor %}
Either approach will work—pick whichever you find more readable!
内容的提问来源于stack exchange,提问作者user16837137

