django возможно ли объединить все поля набора запросов одновременно? - PullRequest
0 голосов
/ 28 января 2020

Данные поступают из другой базы данных, поэтому я не могу редактировать модель.

каждый пользователь играет несколько матчей, и статистика каждого матча сохраняется в отдельной строке таблицы, например, если мне нужно подсчитать количество убийств игрока сделал я могу сосчитать это по

kills = Get5StatsPlayers.objects.filter(steamid64=reuest.user.SocialAuth.uid).aggregate(
sum=Sum('kills'))

мой вопрос, могу ли я сделать это для всех полей одновременно?

class Get5StatsPlayers(models.Model):
matchid = models.PositiveIntegerField(primary_key=True)
mapnumber = models.PositiveSmallIntegerField()
steamid64 = models.CharField(max_length=32)
team = models.CharField(max_length=16)
rounds_played = models.PositiveSmallIntegerField()
name = models.CharField(max_length=64)
kills = models.PositiveSmallIntegerField()
deaths = models.PositiveSmallIntegerField()
assists = models.PositiveSmallIntegerField()
flashbang_assists = models.PositiveSmallIntegerField()
teamkills = models.PositiveSmallIntegerField()
headshot_kills = models.PositiveSmallIntegerField()
damage = models.PositiveIntegerField()
bomb_plants = models.PositiveSmallIntegerField()
bomb_defuses = models.PositiveSmallIntegerField()
v1 = models.PositiveSmallIntegerField()
v2 = models.PositiveSmallIntegerField()
v3 = models.PositiveSmallIntegerField()
v4 = models.PositiveSmallIntegerField()
v5 = models.PositiveSmallIntegerField()
number_2k = models.PositiveSmallIntegerField(db_column='2k')  # Field renamed because it wasn't a valid Python identifier.
number_3k = models.PositiveSmallIntegerField(db_column='3k')  # Field renamed because it wasn't a valid Python identifier.
number_4k = models.PositiveSmallIntegerField(db_column='4k')  # Field renamed because it wasn't a valid Python identifier.
number_5k = models.PositiveSmallIntegerField(db_column='5k')  # Field renamed because it wasn't a valid Python identifier.
firstkill_t = models.PositiveSmallIntegerField()
firstkill_ct = models.PositiveSmallIntegerField()
firstdeath_t = models.PositiveSmallIntegerField()
firstdeath_ct = models.PositiveSmallIntegerField()

Ответы [ 2 ]

0 голосов
/ 28 января 2020

Вы можете создать метод, который будет динамически добавлять поля к агрегации:

from django.db.models import Sum
from django.db.models.fields import PositiveIntegerField, PositiveSmallIntegerField

class Get5StatsPlayers(models.Model):
    ...

    @staticmethod
    def aggregate_many(model, qs, exclude=None):
        exclude_fields = exclude if exclude else []
        model_fields = model._met.get_fields()
        int_fields = [field for field in model_fields if isinstance(field, (PositiveIntegerField, PositiveSmallIntegerField)) and field.name not in exclude_fields]
        aggregation_fields = dict([(f'{field.name}_sum', Sum(f'{field.name}')) for field in int_fields])
        return qs.aggregate(**aggregation_fields)

И затем вызвать этот метод:

aggregated_qs = Get5StatsPlayers.aggregate_many(Get5StatsPlayers, your_queryset)

В результате все ваши целочисленные поля в любой модели если вы перейдете к функции, она будет автоматически добавлена ​​к агрегации.

Вы можете сделать это еще более удобным для использования, переместив ее в менеджер моделей.

0 голосов
/ 28 января 2020

Конечно.

Вы можете передать несколько агрегатных функций в .aggregate() вызов для получения агрегации по нескольким столбцам:

stats = Get5StatsPlayers.objects.filter(
    steamid64=request.user.SocialAuth.uid
).aggregate(
    s_kills=Sum('kills'),
    s_deaths=Sum('deaths'),
    s_headshot_kills=Sum('headshot_kills'),
    s_teamkills=Sum('teamkills'),
    # and so on ...
)

Для большей автоматизации вы можете иметь список полей, которые нужно агрегировать (и сохранить его, т. е. как атрибут модели; или иметь метод для обхода всех полей модели, если они целочисленные - добавить их в список), а затем объединить список полей в словарь имен полей в результирующем вызове агрегирования и агрегировать:

aggregate_fields = ['kills', 'teamkills', 'headshot_kills']

stats_agg = {}
for field in aggregate_fields:
    stats_agg['sum_%s' % field] = Sum(field)

stats = Get5StatsPlayers.objects.filter(
    steamid64=request.user.SocialAuth.uid
).aggregate(
    **stats_agg
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...