admin.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. from django.conf import settings
  2. from django.contrib import admin
  3. from django.db.models import Count, F
  4. from django.urls import reverse
  5. from django.utils.html import format_html
  6. from django.utils.translation import gettext as _
  7. from furl import furl
  8. from rest_framework.reverse import reverse as drf_reverse
  9. from .models import Album, Artist, Track
  10. def get_api_url(obj, view="detail", params=None, title=None, request=None):
  11. path = drf_reverse(
  12. f"{obj._meta.model_name}-{view}",
  13. kwargs={
  14. "uuid": obj.uuid,
  15. "version": settings.REST_FRAMEWORK["DEFAULT_VERSION"],
  16. },
  17. request=request,
  18. )
  19. if params:
  20. path = furl(path).set(params).url
  21. return format_html('<a href="{0}" title="{1}">{1}</a>', path, title or str(obj))
  22. def get_admin_url(obj, view="change", params=None, title=None):
  23. path = reverse(
  24. f"admin:{obj._meta.app_label}_{obj._meta.model_name}_{view}",
  25. kwargs={"object_id": obj.pk} if view == "change" else {},
  26. )
  27. if params:
  28. path = furl(path).set(params).url
  29. return format_html('<a href="{0}" title="{1}">{1}</a>', path, title or str(obj))
  30. class ArtistDecadeActiveListFilter(admin.SimpleListFilter):
  31. title = _("decade active")
  32. parameter_name = "decade_active"
  33. def lookups(self, request, model_admin):
  34. return (
  35. ("1980", _("1980s")),
  36. ("1990", _("1990s")),
  37. ("2000", _("2000s")),
  38. ("2010", _("2010s")),
  39. ("2020", _("2020s")),
  40. )
  41. def queryset(self, request, queryset):
  42. try:
  43. year_since = int(self.value())
  44. year_until = year_since + 10
  45. except (TypeError, ValueError):
  46. return queryset
  47. return queryset.filter(
  48. albums__year__gte=year_since, albums__year__lt=year_until
  49. )
  50. class ArtistAlbumInline(admin.TabularInline):
  51. model = Album
  52. fields = ("name", "year", "album_admin_link", "tracks_admin_link")
  53. readonly_fields = ("album_admin_link", "tracks_admin_link")
  54. extra = 0
  55. def get_queryset(self, request):
  56. queryset = super().get_queryset(request)
  57. return queryset.annotate(track_count=Count("tracks"))
  58. def album_admin_link(self, album):
  59. return get_admin_url(album)
  60. album_admin_link.short_description = _("Album")
  61. def tracks_admin_link(self, album):
  62. return get_admin_url(
  63. Track,
  64. view="changelist",
  65. params={"album": album.pk},
  66. title=album.track_count,
  67. )
  68. tracks_admin_link.short_description = _("Tracks")
  69. class AlbumTrackInline(admin.TabularInline):
  70. model = Track
  71. fields = ("number", "name")
  72. extra = 0
  73. @admin.register(Artist)
  74. class ArtistAdmin(admin.ModelAdmin):
  75. list_display = ("name", "albums_admin_link")
  76. list_filter = (ArtistDecadeActiveListFilter,)
  77. fields = ("name", "uuid", "albums_admin_link", "artist_api_link")
  78. readonly_fields = ("uuid", "albums_admin_link", "artist_api_link")
  79. search_fields = ("uuid", "name")
  80. inlines = (ArtistAlbumInline,)
  81. def get_queryset(self, request):
  82. self.request = request
  83. queryset = super().get_queryset(request)
  84. return queryset.prefetch_related("albums").annotate(album_count=Count("albums"))
  85. def albums_admin_link(self, artist):
  86. return get_admin_url(
  87. Album,
  88. view="changelist",
  89. params={"artist": artist.pk},
  90. title=artist.album_count,
  91. )
  92. albums_admin_link.short_description = _("Albums")
  93. albums_admin_link.admin_order_field = "album_count"
  94. def artist_api_link(self, artist):
  95. return get_api_url(artist, request=self.request)
  96. artist_api_link.short_description = _("API")
  97. @admin.register(Album)
  98. class AlbumAdmin(admin.ModelAdmin):
  99. list_display = ("name", "artist_admin_link", "album_year", "tracks_admin_link")
  100. list_filter = ("year",)
  101. search_fields = ("uuid", "name", "artist__name")
  102. fields = (
  103. "name",
  104. "year",
  105. "uuid",
  106. "artist_admin_link",
  107. "tracks_admin_link",
  108. "album_api_link",
  109. )
  110. readonly_fields = (
  111. "uuid",
  112. "tracks_admin_link",
  113. "artist_admin_link",
  114. "album_api_link",
  115. )
  116. list_select_related = ("artist",)
  117. inlines = (AlbumTrackInline,)
  118. def get_queryset(self, request):
  119. self.request = request
  120. queryset = super().get_queryset(request)
  121. return queryset.annotate(track_count=Count("tracks"))
  122. def album_year(self, album):
  123. return get_admin_url(
  124. Album, view="changelist", params={"year": album.year}, title=album.year
  125. )
  126. album_year.short_description = _("Year")
  127. album_year.admin_order_field = "year"
  128. def artist_admin_link(self, album):
  129. return get_admin_url(album.artist)
  130. artist_admin_link.short_description = _("Artist")
  131. artist_admin_link.admin_order_field = "artist__name"
  132. def tracks_admin_link(self, album):
  133. return get_admin_url(
  134. Track,
  135. view="changelist",
  136. params={"album": album.pk},
  137. title=album.track_count,
  138. )
  139. tracks_admin_link.short_description = _("Tracks")
  140. tracks_admin_link.admin_order_field = "track_count"
  141. def album_api_link(self, album):
  142. return get_api_url(album, request=self.request)
  143. album_api_link.short_description = _("API")
  144. @admin.register(Track)
  145. class TrackAdmin(admin.ModelAdmin):
  146. list_display = ("name", "artist_admin_link", "album_admin_link", "album_year")
  147. list_filter = ("album__year",)
  148. search_fields = ("uuid", "name", "album__name", "album__artist__name")
  149. fields = (
  150. "name",
  151. "uuid",
  152. "artist_admin_link",
  153. "album_admin_link",
  154. "album_year",
  155. "track_api_link",
  156. )
  157. readonly_fields = (
  158. "uuid",
  159. "artist_admin_link",
  160. "album_admin_link",
  161. "album_year",
  162. "track_api_link",
  163. )
  164. list_select_related = ("album", "album__artist")
  165. ordering = ("name", "album__artist__name", "album__name")
  166. def get_queryset(self, request):
  167. self.request = request
  168. queryset = super().get_queryset(request)
  169. return queryset.annotate(album_year=F("album__year"))
  170. def album_admin_link(self, track):
  171. return get_admin_url(track.album)
  172. album_admin_link.short_description = _("Album")
  173. album_admin_link.admin_order_field = "album__name"
  174. def artist_admin_link(self, track):
  175. return get_admin_url(track.album.artist)
  176. artist_admin_link.short_description = _("Artist")
  177. artist_admin_link.admin_order_field = "album__artist__name"
  178. def album_year(self, track):
  179. return get_admin_url(
  180. Track,
  181. view="changelist",
  182. params={"album__year": track.album_year},
  183. title=track.album_year,
  184. )
  185. album_year.short_description = _("Year")
  186. album_year.admin_order_field = "album__year"
  187. def track_api_link(self, track):
  188. return get_api_url(track, request=self.request)
  189. track_api_link.short_description = _("API")