Django Filter tidsstempel data GROUP BY dag, uke, måned, år

stemmer
30

Jeg har en django (DRF) app der jeg lagring av periodiske tidsseriedata basert på API-respons. Her er min model.py

# Model to store the Alexa API Data
class Alexa(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    extra = jsonfield.JSONField(null=True)
    rank =  models.PositiveIntegerField(default=0, null=True)

Jeg bruker django-filtrene til søkedata basert på et område (__lte, __gte). Som /api/alexa/?created_at__lte=2020-02-14T09:15:52.329641Zreturnere alle data som er opprettet før2020-02-14T09:15:52.329641Z

[
    {
        id: 1,
        created_at: 2020-02-03T19:30:57.868588Z,
        extra: {'load_time': 00, 'backlink': 0},
        rank: 0
    },
    ...
 ]

Er det en måte å bygge et endepunkt for å gå tilbake aggregerte data gruppert etter dag, uke, måned og år basert på spørre params jeg passerer. For eksempel /api/alexa/?created_at__lte=2020-02-14T09:15:52.329641Z&group_by=monthvil returnere

[
    {
        created_at: 2020-01-01T00:00:00.000000Z,
        extra: {'load_time': 00, 'backlink': 0}, <- Aggregated Data 
        rank: 0                                    <- Aggregated Data
    },
    {
        created_at: 2020-02-01T00:00:00.000000Z,
        extra: {'load_time': 00, 'backlink': 0}, <- Aggregated Data 
        rank: 0                                    <- Aggregated Data 
    },
 ]

Her er min nåværende serializer.py

class AlexaViewSet(viewsets.ModelViewSet):
    queryset = Alexa.objects.all()
    filter_fields = {'created_at' : ['iexact', 'lte', 'gte']}
    http_method_names = ['get', 'post', 'head']

Jeg har sett flere snutter gjør aggregering, men ingen helt oppfyller mine krav og heller gi meg en fullstendig ideen om emnet.

Jeg er ny på Django og bygge analyse oversikter generelt, hvis det er noen annen måte å representere slike tidsseriedata for forbruk i front-end grafer, ville jeg sette pris på dine forslag til det også.

Publisert på 15/02/2020 klokken 08:48
bruker
På andre språk...                            


1 svar

stemmer
0

Først av alt, klassen AlexaViewSeter 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 listmetoden for denne ViewSet og analysere søkestrengen vedtatt i requestobjektet 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=sumeller 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
    }
]
Svarte 15/02/2020 kl. 20:34
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more