Filtr danych timestamp Django GROUP BY dzień, tydzień, miesiąc, rok

głosy
30

Mam Django (DRF) aplikację, w której ja okresowe przechowywanie danych timeseries oparciu o odpowiedzi API. Oto moja 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)

Używam Django filtry danych zapytań w oparciu o zakres (__lte, __gte). Jak /api/alexa/?created_at__lte=2020-02-14T09:15:52.329641Zprzywrócić wszystkie dane utworzone przed2020-02-14T09:15:52.329641Z

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

Czy istnieje sposób, aby zbudować punkt końcowy, aby powrócić zagregowane dane pogrupowane według dnia, tygodnia, miesiąca i roku na podstawie params zapytań mijam. Na przykład, /api/alexa/?created_at__lte=2020-02-14T09:15:52.329641Z&group_by=monthwróci

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

Oto mój obecny serializer.py

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

Widziałem kilka fragmentów robi agregację ale żaden całkowicie spełniający moje wymagania nie daje mi pełnego pojęcia o temacie.

Jestem nowy Django i budowa analityki pulpitów w ogóle, jeśli istnieje jakiś inny sposób przedstawiania danych takich timeseries do spożycia na wykresach front-end, chciałbym wdzięczni za sugestie, że dobrze.

Utwórz 15/02/2020 o 08:48
użytkownik
W innych językach...                            


1 odpowiedzi

głosy
0

Przede wszystkim klasa AlexaViewSetnie jest serializer ale ViewSet. Nie określono klasę serializer tego ViewSet więc trzeba określić, że.

Z drugiej strony, jeśli chcesz przekazać param zwyczaj kwerendy na URL następnie należy przesłonić listmetodę tego ViewSet i analizowania ciąg kwerendy przekazany w requestobiekcie, aby pobrać wartość group_by, potwierdzić go, a następnie perfom agregację youself ,

Innym problemem, który widzę, jest to, że trzeba także określić, co jest do agregowania pole JSON, który nie jest obsługiwany w SQL i to jest bardzo względne, więc może warto rozważyć przeprojektowanie jak przechowywać informacje z tej dziedziny JSON, jeśli chcesz do perfom agregacji na polach wewnątrz niego. Proponuję wyodrębnieniu pola, które chcesz zsumować z JSON (podczas zapisywania ich w bazie danych) i umieścić je w kolumnie SQL osobno więc można wykonać agregacji później. Klient może także przejść operację agrégation jako parametr zapytania, na przykład aggregation=sumczy aggregation=avg.

W prostym przypadku, w którym po prostu trzeba średnią szeregach powinno to być użyteczne jako przykład (można dodać TruncQuarter, itd.):

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)

Dla tych wartości:

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
    }
]
Odpowiedział 15/02/2020 o 20:34
źródło użytkownik

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