/
views.py
144 lines (104 loc) · 4.5 KB
/
views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
from django.db.models import Q
from django.shortcuts import render
from django_filters import widgets, fields, filters, NumberFilter, CharFilter
from rest_framework import viewsets, status
from rest_framework import generics
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_datatables import pagination as dt_pagination
from rest_framework_datatables.django_filters.filters import GlobalFilter
from rest_framework_datatables.django_filters.filterset import DatatablesFilterSet
from rest_framework_datatables.django_filters.backends import DatatablesFilterBackend
from .models import Album, Artist, Genre
from .serializers import AlbumSerializer, ArtistSerializer
def index(request):
return render(request, 'albums/albums.html')
def get_album_options():
return "options", {
"artist": [{'label': obj.name, 'value': obj.pk} for obj in Artist.objects.all()],
"genre": [{'label': obj.name, 'value': obj.pk} for obj in Genre.objects.all()]
}
class AlbumViewSet(viewsets.ModelViewSet):
queryset = Album.objects.all().order_by('rank')
serializer_class = AlbumSerializer
def get_options(self):
return get_album_options()
class Meta:
datatables_extra_json = ('get_options', )
class ArtistViewSet(viewsets.ViewSet):
queryset = Artist.objects.all().order_by('name')
serializer_class = ArtistSerializer
def list(self, request):
serializer = self.serializer_class(self.queryset, many=True)
return Response(serializer.data)
def get_options(self):
return get_album_options()
class Meta:
datatables_extra_json = ('get_options', )
class AlbumPostListView(generics.ListAPIView):
queryset = Album.objects.all().order_by('rank')
serializer_class = AlbumSerializer
pagination_class = dt_pagination.DatatablesLimitOffsetPagination
def post(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
class YADCFMultipleChoiceWidget(widgets.QueryArrayWidget):
def value_from_datadict(self, data, files, name):
if name not in data:
return None
vals = data[name].split("|")
new_data = data.copy()
new_data[name] = vals
return super().value_from_datadict(new_data, files, name)
class YADCFModelMultipleChoiceField(fields.ModelMultipleChoiceField):
widget = YADCFMultipleChoiceWidget
class YADCFModelMultipleChoiceFilter(filters.ModelMultipleChoiceFilter):
field_class = YADCFModelMultipleChoiceField
def global_q(self):
"""
This method is necessary for the global filter
- i.e. any string values entered into the search box.
"""
if not self._global_search_value:
return Q()
kw = "{}__{}".format(self.field_name, self.lookup_expr)
return Q(**{kw: self._global_search_value})
class GlobalCharFilter(GlobalFilter, filters.CharFilter):
pass
class GlobalNumberFilter(GlobalFilter, filters.NumberFilter):
pass
class AlbumFilter(DatatablesFilterSet):
# the name of this attribute must match the declared 'data' attribute in
# the DataTables column
artist_name = YADCFModelMultipleChoiceFilter(
field_name="artist__name", queryset=Artist.objects.all(), lookup_expr="contains"
)
# additional attributes need to be declared so that sorting works
# the field names must match those declared in the DataTables columns.
rank = GlobalNumberFilter()
name = GlobalCharFilter()
class Meta:
model = Album
fields = ("artist_name", )
class AlbumFilterListView(generics.ListAPIView):
# select_related() and prefetch_related provide more efficient DB queries
queryset = Album.objects.all().select_related("artist").prefetch_related("genres").order_by('rank')
serializer_class = AlbumSerializer
filter_backends = (DatatablesFilterBackend,)
filterset_class = AlbumFilter
class AlbumFilterArtistOptionsListView(APIView):
"""
Return the list of options to appear in the Albums 'artist' column filter.
"""
allowed_methods = ("GET",)
pagination_class = None
def get(self, request, *args, **kwargs):
artists = list(
Artist.objects.filter()
.values_list("id", "name")
.order_by("name")
.distinct()
)
options = list()
for id_, name in artists:
options.append({"value": str(id_), "label": name})
return Response(data={"options": options}, status=status.HTTP_200_OK)