Есть ли лучший способ сделать вычисления для отношений в Django Viewsets? - PullRequest
0 голосов
/ 13 апреля 2019

У меня проблемы с созданием набора представлений, выполнением вычислений для полей в связанной модели.Я довольно новичок в Django, поэтому, пожалуйста, успокойся.:)

По существу.У меня есть модель персонажа.И модель рейдов.Модель Raids имеет отношение ManyToMany к Character.Каждый рейд стоит Ценности.Думаю, я подвел итоги.

Мой главный вопрос - я хочу, чтобы я мог рассчитывать 30, 60, 90 дней и продолжительность жизни каждого персонажа.И я борюсь.Я буду признателен за любую помощь, которую вы можете оказать.

РЕДАКТИРОВАТЬ : Я ищу сумму raid.value для каждого персонажа (я сделал это, но яне уверен, есть ли лучший / более чистый способ).Кроме того, сложная часть пытается получить посещаемость%.Так по сути.Я хочу разделить количество рейдов на одного персонажа / общее количество рейдов (в 4 разных таймфреймах)

models.py

from datetime import timedelta

from django.contrib.auth.models import User
from django.db import models
from django.utils import timezone

...

class Character(models.Model):
    name = models.CharField(
        'Name',
        unique=True,
        primary_key=True,
        max_length=25,
    )

...

class Raid(CreatedModifiedAbstractModel):
    value = models.PositiveSmallIntegerField('DKP Value')
    datetime = models.DateTimeField('Date',auto_created=True)
    characters = models.ManyToManyField(
        Character,
        verbose_name='Attendees',
        related_name='raids',
    )
    not_attendance = models.BooleanField('Not for Attendance',default=False)

views.py

class Dkp(viewsets.ModelViewSet):
    serializer_class = DkpSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]

    def get_queryset(self, *args, **kwargs):
        date_30 = timezone.now() - timedelta(days=30)
        date_60 = timezone.now() - timedelta(days=60)
        date_90 = timezone.now() - timedelta(days=90)
        all_raids = Raid.objects.filter(not_attendance=False)
        qs = Character.objects.all()
        qs = qs.extra(
            select=all_raids.aggregate(
                raid_30=Count('id', filter=Q(datetime__gte=date_30)),
                raid_60=Count('id', filter=Q(datetime__gte=date_60)),
                raid_90=Count('id', filter=Q(datetime__gte=date_90)),
                raid_life=Count('id'),
            )
        )
        qs = qs.annotate(
            earned_dkp=Coalesce(Sum('raids__value'), 0),
            spent_dkp=Coalesce(Sum('purchases__value'), 0),
            current_dkp=F('earned_dkp') - F('spent_dkp'),
            att_30=Count('raids', filter=(Q(raids__not_attendance=False) & Q(raids__datetime__gte=date_30)), default=0),
            att_60=Count('raids', filter=(Q(raids__not_attendance=False) & Q(raids__datetime__gte=date_60)), default=0),
            att_90=Count('raids', filter=(Q(raids__not_attendance=False) & Q(raids__datetime__gte=date_90)), default=0),
            att_life=Count('raids', filter=Q(raids__not_attendance=False), default=0),
        )
        return qs

serializers.py

class DkpSerializer(CharacterSerializer):
    current_dkp = serializers.IntegerField(read_only=True)
    earned_dkp = serializers.IntegerField(read_only=True)
    spent_dkp = serializers.IntegerField(read_only=True)
    att_30 = serializers.IntegerField(read_only=True)
    att_60 = serializers.IntegerField(read_only=True)
    att_90 = serializers.IntegerField(read_only=True)
    att_life = serializers.IntegerField(read_only=True)
    raid_30 = serializers.IntegerField(read_only=True)
    raid_60 = serializers.IntegerField(read_only=True)
    raid_90 = serializers.IntegerField(read_only=True)
    raid_life = serializers.IntegerField(read_only=True)
    rate_30 = serializers.IntegerField(read_only=True)
    raids = RaidSerializer(read_only=True, many=True)
    purchases = ItemPurchaseSerializer(read_only=True, many=True)

1 Ответ

1 голос
/ 13 апреля 2019

Мой главный вопрос: я хочу, чтобы можно было рассчитать 30, 60, 90 дней и продолжительность жизни для каждого персонажа.

import datetime
from django.db.models import Count, Q
date_30 = datetime.datetime.now() + datetime.timedelta(-30)
date_60 = datetime.datetime.now() + datetime.timedelta(-60)
date_90 = datetime.datetime.now() + datetime.timedelta(-90)


Character.objects.annotate(
    raid_30 = Count('raids', filter=Q(raids__datetime__gte=date_30)),
    raid_60 = Count('raids', filter=Q(raids__datetime__gte=date_60)),
    raid_90 = Count('raids', filter=Q(raids__datetime__gte=date_90)),
    raid_life = Count('raids')
)

Я ищу сумму raid.value для каждого персонажа (я сделал это, но я не уверен, есть ли лучший / более чистый способ).

from django.db.models import Sum
Character.objects.annotate(
    raid_value = Sum('raids__value')
)

Я хочу поделить количество рейдов на посещенных персонажей / общее количество рейдов (в 4 разных таймфреймах)

raids_count = Raid.objects.aggregate(
    raid_30 = Count('pk', filter=Q(datetime__gte=date_30)),
    raid_60 = Count('pk', filter=Q(datetime__gte=date_60)),
    raid_90 = Count('pk', filter=Q(datetime__gte=date_90)),
    raid_life = Count('pk'),
)

Character.objects.annotate(
    raid_30 = Count('raids', filter=Q(raids__datetime__gte=date_30)),
    raid_60 = Count('raids', filter=Q(raids__datetime__gte=date_60)),
    raid_90 = Count('raids', filter=Q(raids__datetime__gte=date_90)),
    raid_life = Count('raids')
).annotate(
    raid_30_percent = F('raid_30')/raids_count['raid_30'],
    raid_60_percent = F('raid_60')/raids_count['raid_60'],
    raid_90_percent = F('raid_90')/raids_count['raid_90'],
    raid_life_percent = F('raid_life')/raids_count['raid_life'],
)
...