Django Filter Zeitstempel Daten GROUP BY Tag, Woche, Monat, Jahr

stimmen
30

Ich habe eine django (DRF), in der app I periodische Zeitreihendaten basierend auf API-Antwort zu speichern. Hier ist meine 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)

Ich bin mit django-Filter , um die Abfragedaten basierend auf einem Bereich (__lte, __gte). Wie /api/alexa/?created_at__lte=2020-02-14T09:15:52.329641ZRückkehr alle erstellten Daten vor2020-02-14T09:15:52.329641Z

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

Gibt es eine Möglichkeit , einen Endpunkt zu bauen aggregierte Daten nach Tag, Woche, Monat und Jahr auf der Grundlage der Abfrage params gruppierten zurückzukehren I übergeben. Zum Beispiel /api/alexa/?created_at__lte=2020-02-14T09:15:52.329641Z&group_by=monthwürde zurückkehren

[
    {
        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 
    },
 ]

Hier ist meine aktuelle serializer.py

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

Ich habe mehrere Schnipsel gesehen Aggregation zu tun, aber keiner meine Anforderungen vollständig zu erfüllen, noch mir eine komplette Idee über das Thema geben.

Ich bin neu in Django und den Aufbau Analytik Dashboards in der Regel, wenn es eine andere Möglichkeit gibt zu repräsentieren solche Zeitreihen-Daten für den Verbrauch in Front-End-Grafiken, würde ich Ihre Vorschläge an, dass auch zu schätzen wissen.

Veröffentlicht am 15/02/2020 um 08:48
vom benutzer
In anderen Sprachen...                            


1 antworten

stimmen
0

Zunächst einmal die Klasse AlexaViewSetist kein Serializer sondern ein Viewset. Sie haben geben Sie den Serializer Klasse nicht auf dieser Viewset so dass ich Sie brauchen , dass angeben.

Auf der anderen Seite, wenn Sie eine benutzerdefinierte Abfrage param auf die URL übergeben wollen , dann sollten Sie die überschreiben listMethode dieser Viewset und die Query - String in dem übergebenen analysieren requestObjekt den Wert abzurufen group_by, zu validieren und perfom dann die Aggregation youself .

Ein weiteres Problem , das ich sehe , ist , dass Sie auch , was müssen definieren , ist ein JSON - Feld zu aggregieren, die in SQL nicht unterstützt wird , und es ist sehr relativ, so dass Sie möchten Redesign überlegen , wie Sie die Informationen dieses JSON Feld speichern , wenn Sie möchten , perfom Aggregationen auf Felder in seinem Inneren. Ich würde vorschlagen , um die Felder zu extrahieren Sie aus dem JSON aggregieren wollen (wenn sie in der Datenbank zu speichern) und legt sie in einer SQL - Spalte getrennt , so dass Sie Aggregationen später durchführen können. Der Kunde könnte auch den agregation Betrieb als Abfrage - Parameter übergeben, zum Beispiel aggregation=sumoder aggregation=avg.

In einem einfachen Fall, wo man nur den Durchschnitt benötigt die Reihen dies als Beispiel nützlich sein sollte (man könnte hinzufügen TruncQuarter, etc.):

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)

Für diese Werte:

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
    }
]
Beantwortet am 15/02/2020 um 20:34
quelle vom benutzer

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