Django date de filtrare GROUP timestamp-ul de zi, săptămână, lună, an

voturi
30

Am o aplicație Django (DRF), în care am stocarea de date periodice bazate pe serii temporale de răspuns API. Aici este model.py meu

# 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)

Sunt folosind django-filtre pentru datele de interogare bazate pe un interval (__lte, __gte). La fel ca /api/alexa/?created_at__lte=2020-02-14T09:15:52.329641Zreturna toate datele create înainte2020-02-14T09:15:52.329641Z

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

Există o modalitate de a construi un punct final pentru a reveni date agregate grupate pe zi, pe săptămână, lună și an , pe baza de interogare params I trec. De exemplu, /api/alexa/?created_at__lte=2020-02-14T09:15:52.329641Z&group_by=months - ar întoarce

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

Iată serializer.py meu actual

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

Am văzut mai multe fragmente de agregare fac, dar nici unul nu îndeplinesc în totalitate cerințele mele, nici oferindu-mi o idee completă despre acest subiect.

Sunt nou la Django și construirea de analiză de tablouri de bord, în general, în cazul în care există nici un alt mod de reprezentare a datelor astfel de serii temporale pentru consum în graficele de front-end, aș aprecia sugestiile dumneavoastră la fel de bine.

Întrebat 15/02/2020 la 08:48
de către utilizator
În alte limbi...                            


1 răspunsuri

voturi
0

În primul rând, clasa AlexaViewSetnu este o serializare , ci un ViewSet. Nu ați specificat clasa serializare pe acel ViewSet , așa că am nevoie pentru a specifica acest lucru.

Pe de altă parte, dacă doriți să treacă un parametru de interogare personalizată pe adresa URL atunci ar trebui să suprascrie listmetoda acestei ViewSet și analiza șirul de interogare a trecut în requestobiect pentru a prelua valoarea group_by, validați - l, și apoi perfom agregarea youself .

O altă problemă pe care o văd este că , de asemenea , trebuie să se definească ceea ce este de a cumula un câmp JSON, care nu este acceptat în SQL și este foarte relativă, astfel încât poate doriți să ia în considerare redesenarea modul în care stocați informațiile din acest domeniu JSON dacă doriți la agregări perfom pe câmpuri în interiorul acestuia. Aș sugera extragerea câmpurile pe care doriți să cumulați din JSON (atunci când stocarea lor în baza de date) și le -a pus într - o coloană SQL separat , astfel încât ați putea efectua agregări mai târziu. Clientul ar putea trece , de asemenea , operațiunea ca parametru agregare de interogare, de exemplu , aggregation=sumsau aggregation=avg.

Într - un caz simplu, în cazul în care ai nevoie doar de media rangurilor acest lucru ar trebui să fie util , de exemplu , (ați putea adăuga 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)

Pentru aceste valori:

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
    }
]
Publicat 15/02/2020 la 20:34
sursa de către utilizator

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