Django Filter timestamp datový GROUP BY den, týden, měsíc, rok

hlasů
30

Mám Django (DRF) app s, ve kterém I ukládání periodické TimeSeries data na základě odpovědi API. Tady je můj 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)

Já používám Django filtry na data dotazu na základě řady (__lte, __gte). Stejně jako /api/alexa/?created_at__lte=2020-02-14T09:15:52.329641Zvrátit všechna data vytvořená před2020-02-14T09:15:52.329641Z

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

Existuje způsob, jak vytvořit koncový bod vrátit souhrnné údaje seskupené podle dne, týdne, měsíce a roku na základě dotazu params předám. Například /api/alexa/?created_at__lte=2020-02-14T09:15:52.329641Z&group_by=monthvrátí

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

Tady je můj současný serializer.py

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

Viděl jsem několik úryvků dělat sčítání, ale nikdo zcela splňují mé požadavky, ani že mi úplnou představu o daném tématu.

Jsem nový Django a budování analytické dashboardy obecně, pokud existuje nějaký jiný způsob, jak reprezentovat tyto TimeSeries údaje o spotřebě v front-end grafy, ocenil bych Vaše podněty k tomu stejně.

Položena 15/02/2020 v 08:48
uživatelem
V jiných jazycích...                            


1 odpovědí

hlasů
0

Za prvé, třída AlexaViewSetnení serializer ale ViewSet. Jste neuvedli třídu Serializátor na tom ViewSet tak jsem je třeba určit, že.

Na druhou stranu, pokud chcete předat vlastní dotazu param na adresu URL, pak byste měli přepsat listmetodu tohoto ViewSet a analyzovat řetězec dotazu předán do requestobjektu načíst hodnotu group_by, ověřovat to, a pak perfom agregaci sami sebe ,

Dalším problémem, který vidím, je, že je také nutné definovat, co je agregovat JSON pole, která není podporována v SQL a je to velmi relativní, takže možná budete chtít, aby zvážila přepracování, jak ukládat informace o tomto oboru JSON, pokud chcete perfom agregací na polích uvnitř ní. Navrhoval bych extrahování pole, která chcete sloučit z JSON (při jejich uložení do databáze) a dát je ve sloupci SQL samostatně, takže si mohl provést agregace později. Klient by také mohla projít operaci agregace jako parametr dotazu, například aggregation=sumnebo aggregation=avg.

V jednoduchém případě, kde stačí průměr řad by to mělo být užitečné, jako například (můžete přidat TruncQuarter, atd.):

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)

Pro tyto hodnoty:

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
    }
]
Odpovězeno 15/02/2020 v 20:34
zdroj uživatelem

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