示例#1
0
    def get_context_data(self, **kwargs):
        all_drops = get_drop_querysets(self.get_queryset())
        recent_drops = {
            'items': all_drops['items'].values(
                'item',
                name=F('item__name'),
                icon=F('item__icon'),
            ).annotate(
                count=Sum('quantity')
            ).order_by('-count') if 'items' in all_drops else [],
            'monsters': replace_value_with_choice(
                list(all_drops['monsters'].values(
                    name=F('monster__name'),
                    icon=F('monster__image_filename'),
                    element=F('monster__element'),
                    stars=F('grade'),
                    is_awakened=F('monster__is_awakened'),
                    can_awaken=F('monster__can_awaken'),
                ).annotate(
                    count=Count('pk')
                ).order_by('-count')),
                {'element': Monster.ELEMENT_CHOICES}) if 'monsters' in all_drops else [],
            'runes': replace_value_with_choice(
                list(all_drops['runes'].values(
                    'type',
                    'quality',
                    'stars',
                ).annotate(
                    count=Count('pk')
                ).order_by('-count') if 'runes' in all_drops else []),
                {
                    'type': RuneInstance.TYPE_CHOICES,
                    'quality': RuneInstance.QUALITY_CHOICES,
                }
            ),
        }

        if self.get_log_count():
            bin_width = 50000
            damage_stats = self.get_queryset().aggregate(min=Min('damage'), max=Max('damage'))
            bin_start = floor_to_nearest(damage_stats['min'], bin_width)
            bin_end = ceil_to_nearest(damage_stats['max'], bin_width)
            damage_histogram = {
                'type': 'histogram',
                'width': bin_width,
                'data': histogram(self.get_queryset(), 'damage', range(bin_start, bin_end, bin_width)),
            }
        else:
            damage_histogram = None

        context = {
            'dashboard': {
                'recent_drops': recent_drops,
            },
            'report': drop_report(self.get_queryset(), min_count=0),
            'damage_histogram': damage_histogram
        }

        context.update(kwargs)
        return super().get_context_data(**context)
示例#2
0
    def get_context_data(self, **kwargs):
        all_drops = get_drop_querysets(self.get_queryset())
        recent_drops = {
            'items':
            all_drops['items'].values(
                'item',
                name=F('item__name'),
                icon=F('item__icon'),
            ).annotate(count=Sum('quantity')).order_by('-count')
            if 'items' in all_drops else [],
            'monsters':
            replace_value_with_choice(
                list(all_drops['monsters'].values(
                    name=F('monster__name'),
                    icon=F('monster__image_filename'),
                    element=F('monster__element'),
                    stars=F('grade'),
                    is_awakened=F('monster__is_awakened'),
                    can_awaken=F('monster__can_awaken'),
                ).annotate(count=Count('pk')).order_by('-count')),
                {'element': Monster.ELEMENT_CHOICES})
            if 'monsters' in all_drops else [],
            'runes':
            replace_value_with_choice(
                list(all_drops['runes'].values(
                    'type',
                    'quality',
                    'stars',
                ).annotate(count=Count('pk')).order_by('-count') if 'runes' in
                     all_drops else []), {
                         'type': RuneInstance.TYPE_CHOICES,
                         'quality': RuneInstance.QUALITY_CHOICES,
                     }),
        }

        dashboard_data = {
            'energy_spent': {
                'type':
                'occurrences',
                'total':
                self.get_log_count(),
                'data':
                transform_to_dict(
                    list(self.get_queryset(
                    ).values('level__dungeon__name').annotate(
                        count=Sum('level__energy_cost'), ).order_by('-count')),
                    name_key='level__dungeon__name',
                ),
            },
            'recent_drops': recent_drops,
        }

        level_list = Level.objects.filter(
            pk__in=set(self.get_queryset().values_list('level', flat=True)))

        kwargs['dashboard'] = dashboard_data
        kwargs['level_list'] = level_list

        return super().get_context_data(**kwargs)
示例#3
0
    def get_context_data(self, **kwargs):
        all_drops = get_drop_querysets(self.get_queryset())
        recent_drops = {
            'items': all_drops['items'].values(
                'item',
                name=F('item__name'),
                icon=F('item__icon'),
            ).annotate(
                count=Sum('quantity')
            ).order_by('-count') if 'items' in all_drops else [],
            'monsters': replace_value_with_choice(
                list(all_drops['monsters'].values(
                    name=F('monster__name'),
                    icon=F('monster__image_filename'),
                    element=F('monster__element'),
                    stars=F('grade'),
                    is_awakened=F('monster__is_awakened'),
                    can_awaken=F('monster__can_awaken'),
                ).annotate(
                    count=Count('pk')
                ).order_by('-count')),
                {'element': Monster.ELEMENT_CHOICES}
            ) if 'monsters' in all_drops else [],
            'rune_crafts': replace_value_with_choice(
                list(all_drops['rune_crafts'].values(
                    'type',
                    'quality',
                    'rune',
                ).annotate(
                    count=Count('pk')
                ).order_by('-count') if 'rune_crafts' in all_drops else []),
                {
                    'type': RuneCraft.CRAFT_CHOICES,
                    'quality': RuneCraft.QUALITY_CHOICES,
                    'rune': RuneCraft.TYPE_CHOICES,
                }
            )
        }

        level_list = Level.objects.filter(
            pk__in=set(self.get_queryset().values_list('level', flat=True))
        ).order_by('-floor').prefetch_related('dungeon')

        kwargs['dashboard'] = {
            'recent_drops': recent_drops,
        }
        kwargs['level_list'] = level_list

        return super().get_context_data(**kwargs)
示例#4
0
def _rune_craft_report_data(qs, total_log_count, **kwargs):
    if qs.count() == 0:
        return None

    min_count = kwargs.get('min_count',
                           max(1, int(MINIMUM_THRESHOLD * total_log_count)))

    return {
        'type': {
            'type':
            'occurrences',
            'total':
            qs.count(),
            'data':
            transform_to_dict(
                replace_value_with_choice(
                    list(
                        qs.values('type').annotate(count=Count('pk')).filter(
                            count__gt=min_count).order_by('-count')),
                    {'type': qs.model.CRAFT_CHOICES})),
        },
        'rune': {
            'type':
            'occurrences',
            'total':
            qs.count(),
            'data':
            transform_to_dict(
                replace_value_with_choice(
                    list(
                        qs.values('rune').annotate(count=Count('pk')).filter(
                            count__gt=min_count).order_by('-count')),
                    {'rune': qs.model.TYPE_CHOICES})),
        },
        'quality': {
            'type':
            'occurrences',
            'total':
            qs.count(),
            'data':
            transform_to_dict(
                replace_value_with_choice(
                    list(
                        qs.values('quality').annotate(
                            count=Count('pk')).filter(
                                count__gt=min_count).order_by('-count')),
                    {'quality': qs.model.QUALITY_CHOICES})),
        },
        'stat': {
            'type':
            'occurrences',
            'total':
            qs.count(),
            'data':
            transform_to_dict(
                replace_value_with_choice(
                    list(
                        qs.values('stat').annotate(count=Count('stat')).filter(
                            count__gt=min_count).order_by('stat')),
                    {'stat': qs.model.STAT_CHOICES}))
        },
    }
示例#5
0
def get_artifact_report(qs, total_log_count, **kwargs):
    if qs.count() == 0:
        return None

    min_count = kwargs.get('min_count',
                           max(1, int(MINIMUM_THRESHOLD * total_log_count)))
    # Secondary effect distribution
    # Unable to use database aggregation on an ArrayField without ORM gymnastics, so post-process data in python
    all_effects = qs.annotate(
        flat_effects=Func(F('effects'), function='unnest')).values_list(
            'flat_effects', flat=True)
    effect_counts = Counter(all_effects)

    return {
        'element': {
            'type':
            'occurrences',
            'total':
            qs.filter(slot=Artifact.SLOT_ELEMENTAL).count(),
            'data':
            transform_to_dict(
                replace_value_with_choice(
                    list(
                        qs.filter(slot=Artifact.SLOT_ELEMENTAL).values(
                            'element').annotate(count=Count('pk')).filter(
                                count__gt=min_count).order_by('-count')),
                    {'element': qs.model.ELEMENT_CHOICES})),
        },
        'archetype': {
            'type':
            'occurrences',
            'total':
            qs.filter(slot=Artifact.SLOT_ARCHETYPE).count(),
            'data':
            transform_to_dict(
                replace_value_with_choice(
                    list(
                        qs.filter(slot=Artifact.SLOT_ARCHETYPE).values(
                            'archetype').annotate(count=Count('pk')).filter(
                                count__gt=min_count).order_by('-count')),
                    {'archetype': qs.model.ARCHETYPE_CHOICES})),
        },
        'quality': {
            'type':
            'occurrences',
            'total':
            qs.count(),
            'data':
            transform_to_dict(
                replace_value_with_choice(
                    list(
                        qs.values('quality').annotate(
                            count=Count('pk')).filter(
                                count__gt=min_count).order_by('-count')),
                    {'quality': qs.model.QUALITY_CHOICES})),
        },
        'main_stat': {
            'type':
            'occurrences',
            'total':
            qs.count(),
            'data':
            transform_to_dict(
                replace_value_with_choice(
                    list(
                        qs.values('main_stat').annotate(
                            count=Count('main_stat')).filter(
                                count__gt=min_count).order_by('main_stat')),
                    {'main_stat': qs.model.STAT_CHOICES}))
        },
        'effects': {
            'type':
            'occurrences',
            'total':
            len(all_effects),
            'data':
            transform_to_dict(
                replace_value_with_choice(
                    sorted([{
                        'effect': k,
                        'count': v
                    } for k, v in effect_counts.items()],
                           key=lambda count: count['effect']),
                    {'effect': qs.model.EFFECT_CHOICES}), )
        },
        'max_efficiency': {
            'type':
            'histogram',
            'width':
            5,
            'data':
            histogram(qs,
                      'max_efficiency',
                      range(0, 100, 5),
                      slice_on='quality'),
        },
    }
示例#6
0
def get_rune_report(qs, total_log_count, **kwargs):
    if qs.count() == 0:
        return None

    min_count = kwargs.get('min_count',
                           max(1, int(MINIMUM_THRESHOLD * total_log_count)))

    # Substat distribution
    # Unable to use database aggregation on an ArrayField without ORM gymnastics, so post-process data in python
    all_substats = qs.annotate(
        flat_substats=Func(F('substats'), function='unnest')).values_list(
            'flat_substats', flat=True)
    substat_counts = Counter(all_substats)

    # Sell value ranges
    min_value, max_value = qs.aggregate(Min('value'), Max('value')).values()
    min_value = int(floor_to_nearest(min_value, 1000))
    max_value = int(ceil_to_nearest(max_value, 1000))

    return {
        'stars': {
            'type':
            'occurrences',
            'total':
            qs.count(),
            'data':
            transform_to_dict(
                list(
                    qs.values(grade=Concat(Cast('stars', CharField(
                    )), Value('⭐'))).annotate(count=Count('pk')).filter(
                        count__gt=min_count).order_by('-count'))),
        },
        'type': {
            'type':
            'occurrences',
            'total':
            qs.count(),
            'data':
            transform_to_dict(
                replace_value_with_choice(
                    list(
                        qs.values('type').annotate(count=Count('pk')).filter(
                            count__gt=min_count).order_by('-count')),
                    {'type': qs.model.TYPE_CHOICES})),
        },
        'quality': {
            'type':
            'occurrences',
            'total':
            qs.count(),
            'data':
            transform_to_dict(
                replace_value_with_choice(
                    list(
                        qs.values('quality').annotate(
                            count=Count('pk')).filter(
                                count__gt=min_count).order_by('-count')),
                    {'quality': qs.model.QUALITY_CHOICES})),
        },
        'slot': {
            'type':
            'occurrences',
            'total':
            qs.count(),
            'data':
            transform_to_dict(
                list(
                    qs.values('slot').annotate(count=Count('pk')).filter(
                        count__gt=min_count).order_by('-count'))),
        },
        'main_stat': {
            'type':
            'occurrences',
            'total':
            qs.count(),
            'data':
            transform_to_dict(
                replace_value_with_choice(
                    list(
                        qs.values('main_stat').annotate(
                            count=Count('main_stat')).filter(
                                count__gt=min_count).order_by('main_stat')),
                    {'main_stat': qs.model.STAT_CHOICES}))
        },
        'slot_2_main_stat': {
            'type':
            'occurrences',
            'total':
            qs.filter(slot=2).count(),
            'data':
            transform_to_dict(
                replace_value_with_choice(
                    list(
                        qs.filter(slot=2).values('main_stat').annotate(
                            count=Count('main_stat')).filter(
                                count__gt=min_count).order_by('main_stat')),
                    {'main_stat': qs.model.STAT_CHOICES}))
        },
        'slot_4_main_stat': {
            'type':
            'occurrences',
            'total':
            qs.filter(slot=4).count(),
            'data':
            transform_to_dict(
                replace_value_with_choice(
                    list(
                        qs.filter(slot=4).values('main_stat').annotate(
                            count=Count('main_stat')).filter(
                                count__gt=min_count).order_by('main_stat')),
                    {'main_stat': qs.model.STAT_CHOICES}))
        },
        'slot_6_main_stat': {
            'type':
            'occurrences',
            'total':
            qs.filter(slot=6).count(),
            'data':
            transform_to_dict(
                replace_value_with_choice(
                    list(
                        qs.filter(slot=6).values('main_stat').annotate(
                            count=Count('main_stat')).filter(
                                count__gt=min_count).order_by('main_stat')),
                    {'main_stat': qs.model.STAT_CHOICES}))
        },
        'innate_stat': {
            'type':
            'occurrences',
            'total':
            qs.count(),
            'data':
            transform_to_dict(
                replace_value_with_choice(
                    list(
                        qs.values('innate_stat').annotate(
                            count=Count('pk')).filter(
                                count__gt=min_count).order_by('innate_stat')),
                    {'innate_stat': qs.model.STAT_CHOICES}))
        },
        'substats': {
            'type':
            'occurrences',
            'total':
            len(all_substats),
            'data':
            transform_to_dict(
                replace_value_with_choice(
                    sorted([{
                        'substat': k,
                        'count': v
                    } for k, v in substat_counts.items()],
                           key=lambda count: count['substat']),
                    {'substat': qs.model.STAT_CHOICES}), )
        },
        'max_efficiency': {
            'type':
            'histogram',
            'width':
            5,
            'data':
            histogram(qs,
                      'max_efficiency',
                      range(0, 100, 5),
                      slice_on='quality'),
        },
        'value': {
            'type':
            'histogram',
            'width':
            500,
            'data':
            histogram(qs,
                      'value',
                      range(min_value, max_value, 500),
                      slice_on='quality')
        }
    }
示例#7
0
def get_monster_report(qs, total_log_count, **kwargs):
    if qs.count() == 0:
        return None

    min_count = kwargs.get('min_count',
                           max(1, int(MINIMUM_THRESHOLD * total_log_count)))

    return {
        'monsters': {  # By unique monster
            'type': 'occurrences',
            'total': qs.count(),
            'data': transform_to_dict(
                list(
                    qs.values(
                        'monster',
                    ).annotate(
                        monster_name=Func(
                            Concat(F('monster__element'), Value(' '), F('monster__name')),
                            function='INITCAP',
                        ),
                        count=Count('pk'),
                    ).filter(count__gt=min_count).order_by('-count')
                ),
                name_key='monster_name'
            ),
        },
        'family': {  # By family
            'type': 'occurrences',
            'total': qs.count(),
            'data': transform_to_dict(
                list(
                    qs.values(
                        family_id=F('monster__family_id'),
                        name=F('monster__name'),
                    ).annotate(
                        count=Count('pk')
                    ).filter(
                        count__gt=min_count
                    ).order_by('-count')
                ),
                name_key='name'
            )
        },
        'nat_stars': {  # By nat stars
            'type': 'occurrences',
            'total': qs.count(),
            'data': transform_to_dict(
                list(
                    qs.values(
                        nat_stars=F('monster__natural_stars'),
                    ).annotate(
                        grade=Concat(Cast('monster__natural_stars', CharField()), Value('⭐')),
                        count=Count('monster__natural_stars'),
                    ).filter(count__gt=min_count).order_by('-count')
                ),
                name_key='grade'
            )
        },
        'element': {  # By element
            'type': 'occurrences',
            'total': qs.count(),
            'data': transform_to_dict(
                replace_value_with_choice(
                    list(
                        qs.values(
                            element=F('monster__element')
                        ).annotate(
                            element_cap=Func(F('monster__element'), function='INITCAP',),
                            count=Count('pk')
                        ).filter(count__gt=min_count).order_by('-count')
                    ),
                    {'element': Monster.ELEMENT_CHOICES}
                ),
                name_key='element_cap',
            )
        },
        'awakened': {  # By awakened/unawakened
            'type': 'occurrences',
            'total': qs.count(),
            'data': transform_to_dict(
                list(
                    qs.values(
                        awakened=F('monster__is_awakened')
                    ).annotate(
                        count=Count('pk')
                    ).filter(count__gt=min_count).order_by('-count')
                ),
                transform={
                    True: 'Awakened',
                    False: 'Unawakened',
                }
            ),
        }
    }
示例#8
0
def get_report_summary(drops, total_log_count, **kwargs):
    summary = {
        'table': {},
        'chart': [],
    }

    min_count = kwargs.get('min_count',
                           max(1, int(MINIMUM_THRESHOLD * total_log_count)))

    # Chart data: list of {'drop': <string>, 'count': <int>}
    # Table data: dict (by drop type) of lists of items which drop, with stats. 'count' is only required stat.
    for drop_type, qs in drops.items():
        # Remove very low frequency occurrences from dataset
        qs = qs.annotate(count=Count('pk')).filter(count__gte=min_count)

        if drop_type == models.ItemDrop.RELATED_NAME:
            if kwargs.get('exclude_social_points'):
                qs = qs.exclude(item__category=GameItem.CATEGORY_CURRENCY,
                                item__name='Social Point')

            chart_qs = qs.values(name=F('item__name')).annotate(
                count=Count('pk')).order_by('-count')

            if not kwargs.get('include_currency'):
                chart_qs = chart_qs.exclude(
                    item__category=GameItem.CATEGORY_CURRENCY)

            chart_data = list(chart_qs)
            table_data = list(
                qs.values(
                    name=F('item__name'),
                    icon=F('item__icon'),
                ).annotate(
                    count=Count('pk'),
                    min=Min('quantity'),
                    max=Max('quantity'),
                    avg=Avg('quantity'),
                    drop_chance=Cast(Count('pk'), FloatField()) /
                    total_log_count * 100,
                    qty_per_100=Cast(Sum('quantity'), FloatField()) /
                    total_log_count * 100,
                ).order_by('item__category', '-count'))
        elif drop_type == models.MonsterDrop.RELATED_NAME:
            # Monster drops in chart are counted by stars
            chart_data = list(
                qs.values(name=Concat(Cast('grade', CharField()),
                                      Value('⭐ Monster'))).annotate(
                                          count=Count('pk')).filter(
                                              count__gt=0).order_by('-count'))

            table_data = replace_value_with_choice(
                list(
                    qs.values(
                        name=F('monster__name'),
                        slug=F('monster__bestiary_slug'),
                        icon=F('monster__image_filename'),
                        element=F('monster__element'),
                        can_awaken=F('monster__can_awaken'),
                        is_awakened=F('monster__is_awakened'),
                        stars=F('grade'),
                    ).annotate(
                        count=Count('pk'),
                        drop_chance=Cast(Count('pk'), FloatField()) /
                        total_log_count * 100,
                        qty_per_100=Cast(Count('pk'), FloatField()) /
                        total_log_count * 100,
                    )), {'element': Monster.ELEMENT_CHOICES})
        elif drop_type == models.RuneCraftDrop.RELATED_NAME:
            # Rune crafts are counted by type
            chart_data = list(
                replace_value_with_choice(
                    qs.values(name=F('type'), ).annotate(
                        count=Count('pk'), ).order_by('-count'),
                    {'name': models.RuneCraftDrop.CRAFT_CHOICES}))

            table_data = {
                'sets':
                replace_value_with_choice(
                    list(
                        qs.values('rune').annotate(
                            count=Count('pk')).order_by('rune')),
                    {'rune': Rune.TYPE_CHOICES}),
                'type':
                replace_value_with_choice(
                    list(
                        qs.values('type').annotate(
                            count=Count('pk')).order_by('type')),
                    {'type': Rune.TYPE_CHOICES}),
                'quality':
                replace_value_with_choice(
                    list(
                        qs.values('quality').annotate(
                            count=Count('pk')).order_by('quality')),
                    {'quality': Rune.QUALITY_CHOICES}),
            }
        else:
            # Chart is name, count only
            item_name = ' '.join(
                [s.capitalize() for s in drop_type.split('_')]).rstrip('s')
            count = qs.aggregate(count=Count('pk'))['count']
            if count > 0:
                chart_data = [{
                    'name': item_name,
                    'count': count,
                }]
            else:
                chart_data = []

            # Table data based on item type
            if drop_type == models.MonsterPieceDrop.RELATED_NAME:
                table_data = replace_value_with_choice(
                    list(
                        qs.values(
                            name=F('monster__name'),
                            slug=F('monster__bestiary_slug'),
                            icon=F('monster__image_filename'),
                            element=F('monster__element'),
                            can_awaken=F('monster__can_awaken'),
                            is_awakened=F('monster__is_awakened'),
                            stars=F('monster__natural_stars'),
                            count=Count('pk'),
                            min=Min('quantity'),
                            max=Max('quantity'),
                            avg=Avg('quantity'),
                            drop_chance=Cast(Count('pk'), FloatField()) /
                            total_log_count * 100,
                            qty_per_100=Cast(Sum('quantity'), FloatField()) /
                            total_log_count * 100,
                        )), {'element': Monster.ELEMENT_CHOICES})
            elif drop_type == models.RuneDrop.RELATED_NAME:
                table_data = {
                    'sets':
                    replace_value_with_choice(
                        list(
                            qs.values('type').annotate(
                                count=Count('pk')).order_by('type')),
                        {'type': Rune.TYPE_CHOICES}),
                    'slots':
                    list(
                        qs.values('slot').annotate(
                            count=Count('pk')).order_by('slot')),
                    'quality':
                    replace_value_with_choice(
                        list(
                            qs.values('quality').annotate(
                                count=Count('pk')).order_by('quality')),
                        {'quality': Rune.QUALITY_CHOICES}),
                }
            elif drop_type == models.RuneCraftDrop.RELATED_NAME:
                table_data = replace_value_with_choice(
                    list(
                        qs.values('type', 'rune', 'quality').annotate(
                            count=Count('pk'), ).order_by(
                                'type', 'rune', 'quality')), {
                                    'type': Rune.TYPE_CHOICES,
                                    'quality': Rune.QUALITY_CHOICES
                                })
            elif drop_type == models.ArtifactDrop.RELATED_NAME:
                table_data = {
                    'element':
                    replace_value_with_choice(
                        list(
                            qs.filter(slot=Artifact.SLOT_ELEMENTAL).values(
                                'element').annotate(
                                    count=Count('pk')).order_by('element')),
                        {'type': Artifact.ELEMENT_CHOICES}),
                    'archetype':
                    replace_value_with_choice(
                        list(
                            qs.filter(slot=Artifact.SLOT_ARCHETYPE).values(
                                'archetype').annotate(
                                    count=Count('pk')).order_by('archetype')),
                        {'type': Artifact.ARCHETYPE_CHOICES}),
                    'quality':
                    replace_value_with_choice(
                        list(
                            qs.values('quality').annotate(
                                count=Count('pk')).order_by('quality')),
                        {'quality': Artifact.QUALITY_CHOICES}),
                }
            elif drop_type == models.DungeonSecretDungeonDrop.RELATED_NAME:
                table_data = replace_value_with_choice(
                    list(
                        qs.values(
                            name=F(
                                'level__dungeon__secretdungeon__monster__name'
                            ),
                            slug=
                            F('level__dungeon__secretdungeon__monster__bestiary_slug'
                              ),
                            icon=
                            F('level__dungeon__secretdungeon__monster__image_filename'
                              ),
                            element=
                            F('level__dungeon__secretdungeon__monster__element'
                              ),
                            can_awaken=
                            F('level__dungeon__secretdungeon__monster__can_awaken'
                              ),
                            is_awakened=
                            F('level__dungeon__secretdungeon__monster__is_awakened'
                              ),
                            stars=
                            F('level__dungeon__secretdungeon__monster__natural_stars'
                              ),
                        ).annotate(
                            count=Count('pk'),
                            drop_chance=Cast(Count('pk'), FloatField()) /
                            total_log_count * 100,
                            qty_per_100=Cast(Sum('pk'), FloatField()) /
                            total_log_count * 100,
                        )), {'element': Monster.ELEMENT_CHOICES})

            else:
                raise NotImplementedError(
                    f"No summary table generation for {drop_type}")

        summary['chart'] += chart_data

        if table_data:
            summary['table'][drop_type] = table_data

    return summary
示例#9
0
    def get_context_data(self, **kwargs):
        all_drops = get_drop_querysets(self.get_queryset())
        recent_drops = {
            'items': all_drops['items'].values(
                'item',
                name=F('item__name'),
                icon=F('item__icon'),
            ).annotate(
                count=Sum('quantity')
            ).order_by('-count') if 'items' in all_drops else [],
            'monsters': replace_value_with_choice(
                list(all_drops['monsters'].values(
                    name=F('monster__name'),
                    icon=F('monster__image_filename'),
                    element=F('monster__element'),
                    stars=F('grade'),
                    is_awakened=F('monster__is_awakened'),
                    can_awaken=F('monster__can_awaken'),
                ).annotate(
                    count=Count('pk')
                ).order_by('-count')),
                {'element': Monster.ELEMENT_CHOICES}) if 'monsters' in all_drops else [],
            # 'monster_pieces': 'insert_data_here' if 'monster_pieces' in all_drops else [],
            'runes': replace_value_with_choice(
                list(all_drops['runes'].values(
                    'type',
                    'quality',
                    'stars',
                ).annotate(
                    count=Count('pk')
                ).order_by('-count') if 'runes' in all_drops else []),
                {
                    'type': RuneInstance.TYPE_CHOICES,
                    'quality': RuneInstance.QUALITY_CHOICES,
                }
            ),
            # 'secret_dungeons': 'insert_data_here' if 'runes' in all_drops else [],
        }

        dashboard_data = {
            'energy_spent': {
                'type': 'occurrences',
                'total': self.get_log_count(),
                'data': transform_to_dict(
                    list(
                        self.get_queryset().values(
                            'level'
                        ).annotate(
                            dungeon_name=Concat(
                                F('level__dungeon__name'),
                                Value(' B'),
                                F('level__floor'),
                                output_field=CharField()
                            ),
                            count=Sum('level__energy_cost'),
                        ).order_by('-count')
                    ),
                    name_key='dungeon_name',
                ),
            },
            'recent_drops': recent_drops,
        }

        level_order = self.get_queryset().values('level').annotate(
            energy_spent=Sum('level__energy_cost')
        ).order_by('-energy_spent').values_list('level', flat=True)
        preserved_order = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(level_order)])
        level_list = Level.objects.filter(
            pk__in=set(self.get_queryset().values_list('level', flat=True))
        ).order_by(preserved_order).prefetch_related('dungeon')[:20]

        kwargs['dashboard'] = dashboard_data
        kwargs['level_list'] = level_list

        return super().get_context_data(**kwargs)
示例#10
0
def get_report_summary(drops, total_log_count):
    summary = {
        'table': {},
        'chart': [],
    }

    # Chart data: list of {'drop': <string>, 'count': <int>}
    # Table data: dict (by drop type) of lists of items which drop, with stats. 'count' is only required stat.
    for drop_type, qs in drops.items():
        if drop_type == models.ItemDrop.RELATED_NAME:
            # Chart excludes currency
            chart_data = list(
                qs.exclude(item__category=GameItem.CATEGORY_CURRENCY, ).values(
                    name=F('item__name'), ).annotate(
                        count=Count('pk'), ).filter(
                            count__gt=0).order_by('-count'))

            table_data = list(
                qs.values(
                    name=F('item__name'),
                    icon=F('item__icon'),
                ).annotate(
                    count=Count('pk'),
                    min=Min('quantity'),
                    max=Max('quantity'),
                    avg=Avg('quantity'),
                    drop_chance=Cast(Count('pk'), FloatField()) /
                    total_log_count * 100,
                    avg_per_run=Cast(Sum('quantity'), FloatField()) /
                    total_log_count,
                ).filter(count__gt=0).order_by('item__category', '-count'))
        elif drop_type == models.MonsterDrop.RELATED_NAME:
            # Monster drops in chart are counted by stars
            chart_data = list(
                qs.values(name=Concat(Cast('grade', CharField()),
                                      Value('⭐ Monster'))).annotate(
                                          count=Count('pk')).filter(
                                              count__gt=0).order_by('-count'))

            table_data = replace_value_with_choice(
                list(
                    qs.values(
                        name=F('monster__name'),
                        slug=F('monster__bestiary_slug'),
                        icon=F('monster__image_filename'),
                        element=F('monster__element'),
                        can_awaken=F('monster__can_awaken'),
                        is_awakened=F('monster__is_awakened'),
                        stars=F('monster__base_stars'),
                    ).annotate(
                        count=Count('pk'),
                        drop_chance=Cast(Count('pk'), FloatField()) /
                        total_log_count * 100,
                    )), {'element': Monster.ELEMENT_CHOICES})
        else:
            # Chart can is name, count only
            item_name = ' '.join(
                [s.capitalize() for s in drop_type.split('_')]).rstrip('s')
            count = qs.aggregate(count=Count('pk'))['count']
            if count > 0:
                chart_data = [{
                    'name': item_name,
                    'count': count,
                }]
            else:
                chart_data = []

            # Table data based on item type
            if drop_type == models.MonsterPieceDrop.RELATED_NAME:
                table_data = replace_value_with_choice(
                    list(
                        qs.values(
                            name=F('monster__name'),
                            icon=F('monster__image_filename'),
                            element=F('monster__element'),
                            count=Count('pk'),
                            min=Min('quantity'),
                            max=Max('quantity'),
                            avg=Avg('quantity'),
                        )), {'element': Monster.ELEMENT_CHOICES})
            elif drop_type == models.RuneDrop.RELATED_NAME:
                table_data = {
                    'sets':
                    replace_value_with_choice(
                        list(
                            qs.values('type').annotate(
                                count=Count('pk')).order_by('type')),
                        {'type': Rune.TYPE_CHOICES}),
                    'slots':
                    list(
                        qs.values('slot').annotate(
                            count=Count('pk')).order_by('slot')),
                    'quality':
                    replace_value_with_choice(
                        list(
                            qs.values('quality').annotate(
                                count=Count('pk')).order_by('quality')),
                        {'quality': Rune.QUALITY_CHOICES}),
                }
            elif drop_type == models.RuneCraftDrop.RELATED_NAME:
                table_data = replace_value_with_choice(
                    list(
                        qs.values('type', 'rune', 'quality').annotate(
                            count=Count('pk'), ).order_by(
                                'type', 'rune', 'quality')), {
                                    'type': Rune.TYPE_CHOICES,
                                    'quality': Rune.QUALITY_CHOICES
                                })
            elif drop_type == models.DungeonSecretDungeonDrop.RELATED_NAME:
                table_data = replace_value_with_choice(
                    list(
                        qs.values(
                            name=F(
                                'level__dungeon__secretdungeon__monster__name'
                            ),
                            element=
                            F('level__dungeon__secretdungeon__monster__element'
                              ),
                            icon=
                            F('level__dungeon__secretdungeon__monster__image_filename'
                              ),
                        ).annotate(count=Count('pk'), )),
                    {'element': Monster.ELEMENT_CHOICES})

            else:
                raise NotImplementedError(
                    f"No summary table generation for {drop_type}")

        summary['chart'] += chart_data

        if table_data:
            summary['table'][drop_type] = table_data

    return summary
示例#11
0
def get_monster_report(qs, total_log_count):
    if qs.count() == 0:
        return None

    results = {}

    # By unique monster
    results['monsters'] = {
        'type':
        'occurrences',
        'total':
        qs.count(),
        'data':
        list(
            qs.values(
                'monster',
                name=F('monster__name'),
                element=F('monster__element'),
                com2us_id=F('monster__com2us_id'),
                icon=F('monster__image_filename')).annotate(count=Count('pk')))
    }

    # By family
    results['family'] = {
        'type':
        'occurrences',
        'total':
        qs.count(),
        'data':
        list(
            qs.values(
                family_id=F('monster__family_id'),
                name=F('monster__name'),
            ).annotate(count=Count('pk')))
    }

    # By nat stars
    mons_by_nat_stars = list(
        qs.values(nat_stars=F('monster__base_stars'), ).annotate(
            count=Count('monster__base_stars'),
            drop_chance=Cast(Count('pk'), FloatField()) / total_log_count *
            100,
        ))

    results['nat_stars'] = {
        'type': 'occurrences',
        'total': qs.count(),
        'data': mons_by_nat_stars,
    }

    # By element
    results['element'] = {
        'type':
        'occurrences',
        'total':
        qs.count(),
        'data':
        replace_value_with_choice(
            list(
                qs.values(element=F('monster__element')).annotate(
                    count=Count('pk'))), {'element': Monster.ELEMENT_CHOICES})
    }

    # By awakened/unawakened
    results['awakened'] = {
        'type':
        'occurrences',
        'total':
        qs.count(),
        'data':
        list(
            qs.values(awakened=F('monster__is_awakened')).annotate(
                count=Count('pk'))),
    }

    return results