Django Filter timestamp data GROUP per dag, week, maand, jaar

stemmen
30

Ik heb een django (DRF) app waarin ik opslaan periodieke tijdreeks gegevens op basis van API respons. Hier is mijn 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)

Ik ben met behulp van Django-filters om vraag gegevens op basis van een bereik (__lte, __gte). Net als /api/alexa/?created_at__lte=2020-02-14T09:15:52.329641Zhet geven van de gegevens die vóór2020-02-14T09:15:52.329641Z

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

Is er een manier om een eindpunt te bouwen om geaggregeerde gegevens gegroepeerd per dag, week, maand en jaar op basis van de query params ik pas terug te keren. Bijvoorbeeld, /api/alexa/?created_at__lte=2020-02-14T09:15:52.329641Z&group_by=monthzou terugkeren

[
    {
        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 is mijn huidige serializer.py

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

Ik heb verschillende fragmenten doen aggregatie gezien, maar geen van allen echt vervullen van mijn eisen, noch geeft me een compleet beeld over het onderwerp.

Ik ben nieuw in Django en het bouwen van analytics dashboards in het algemeen, als er een andere manier te vertegenwoordigen dergelijke tijdreeks van gegevens voor het verbruik in front-end grafieken, zou ik uw suggesties waarderen dat ook.

De vraag is gesteld op 15/02/2020 om 08:48
user
In andere talen...                            


1 antwoorden

stemmen
0

Allereerst, de klasse AlexaViewSetis niet een serialisator maar een ViewSet. U heeft niet aangegeven de serialisator klasse op die ViewSet dus ik heb je nodig om aan te geven dat.

Aan de andere kant, als je wilt naar een aangepaste query param vellen over de URL dan moet je het overschrijven listwerkwijze van deze ViewSet en ontleden de query string doorgegeven in het requestobject om de waarde van de op te halen group_by, te valideren, en dan perfom de aggregatie youself .

Een ander probleem dat ik zie is dat je moet ook om te bepalen wat een JSON veld, dat niet wordt ondersteund in SQL aggregeren en het is zeer relatief, dus je kunt overwegen herinrichten van de manier waarop u de informatie van dit veld JSON te slaan als je wilt naar perfom aggregaties op velden binnen het. Ik stel voor het extraheren van de velden die u wilt verzamelen uit de JSON (wanneer ze op te slaan in de database) en zet ze in een SQL-kolom los, zodat je aggregaties later kan uitvoeren. De klant kan ook langs de Agrégation bewerking als een query parameter, bijvoorbeeld aggregation=sumof aggregation=avg.

In een eenvoudig geval, waar je gewoon het gemiddelde van de gelederen dit moet nuttig zijn als een voorbeeld (je zou kunnen toevoegen nodig hebben 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)

Voor deze waarden:

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
    }
]
antwoordde op 15/02/2020 om 20:34
bron van user

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