Først av alt, klassen AlexaViewSet
er ikke en serialisering men en ViewSet. Du spesifiserte ikke serialisering klassen på at ViewSet så jeg må du spesifisere det.
På den andre siden, hvis du ønsker å passere en tilpasset søkeparameter på nettadressen bør du overstyre list
metoden for denne ViewSet og analysere søkestrengen vedtatt i request
objektet for å hente verdien av group_by
, validere den, og deretter perfom aggregering deg selv .
Et annet problem som jeg ser er at du også trenger å definere hva som er å samle en JSON-feltet, som ikke støttes i SQL, og det er veldig relativt, så det kan være lurt å vurdere å omstrukturere hvordan du lagrer informasjon om denne JSON feltet hvis du vil å perfom samlinger på felt inni den. Jeg vil foreslå å trekke ut de feltene du ønsker å aggregere fra JSON (når lagre dem i databasen) og legg dem i en SQL kolonne separat slik at du kan utføre samlinger senere. Klienten kan også bestå agrégation drift som en søkeparameter, for eksempel aggregation=sum
eller aggregation=avg
.
I et enkelt tilfelle, der du bare trenger gjennomsnittet av rangerer dette bør være nyttig som et eksempel (du kan legge til TruncQuarter
, osv):
class AlexaViewSet(viewsets.ModelViewSet):
serializer_class = AlexaSerializer
queryset = Alexa.objects.all()
filter_fields = {'created_at': ['iexact', 'lte', 'gte']}
http_method_names = ['get', 'post', 'head']
GROUP_CASTING_MAP = { # Used for outputing the reset datetime when grouping
'day': Cast(TruncDate('created_at'), output_field=DateTimeField()),
'month': Cast(TruncMonth('created_at'), output_field=DateTimeField()),
'week': Cast(TruncWeek('created_at'), output_field=DateTimeField()),
'year': Cast(TruncYear('created_at'), output_field=DateTimeField()),
}
GROUP_ANNOTATIONS_MAP = { # Defines the fields used for grouping
'day': {
'day': TruncDay('created_at'),
'month': TruncMonth('created_at'),
'year': TruncYear('created_at'),
},
'week': {
'week': TruncWeek('created_at')
},
'month': {
'month': TruncMonth('created_at'),
'year': TruncYear('created_at'),
},
'year': {
'year': TruncYear('created_at'),
},
}
def list(self, request, *args, **kwargs):
group_by_field = request.GET.get('group_by', None)
if group_by_field and group_by_field not in self.GROUP_CASTING_MAP.keys(): # validate possible values
return Response(status=status.HTTP_400_BAD_REQUEST)
queryset = self.filter_queryset(self.get_queryset())
if group_by_field:
queryset = queryset.annotate(**self.GROUP_ANNOTATIONS_MAP[group_by_field]) \
.values(*self.GROUP_ANNOTATIONS_MAP[group_by_field]) \
.annotate(rank=Avg('rank'), created_at=self.GROUP_CASTING_MAP[group_by_field]) \
.values('rank', 'created_at')
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
For disse verdiene:
GET /alexa
[
{
"id": 1,
"created_at": "2020-03-16T12:04:59.096098Z",
"extra": "{}",
"rank": 2
},
{
"id": 2,
"created_at": "2020-02-15T12:05:01.907920Z",
"extra": "{}",
"rank": 64
},
{
"id": 3,
"created_at": "2020-02-15T12:05:03.890150Z",
"extra": "{}",
"rank": 232
},
{
"id": 4,
"created_at": "2020-02-15T12:05:06.357748Z",
"extra": "{}",
"rank": 12
}
]
GET /alexa/?group_by=day
[
{
"created_at": "2020-02-15T00:00:00Z",
"extra": null,
"rank": 102
},
{
"created_at": "2020-03-16T00:00:00Z",
"extra": null,
"rank": 2
}
]
GET /alexa/?group_by=week
[
{
"created_at": "2020-02-10T00:00:00Z",
"extra": null,
"rank": 102
},
{
"created_at": "2020-03-16T00:00:00Z",
"extra": null,
"rank": 2
}
]
GET /alexa/?group_by=month
[
{
"created_at": "2020-02-01T00:00:00Z",
"extra": null,
"rank": 102
},
{
"created_at": "2020-03-01T00:00:00Z",
"extra": null,
"rank": 2
}
]
GET /alexa/?group_by=year
[
{
"created_at": "2020-01-01T00:00:00Z",
"extra": null,
"rank": 77
}
]