Refactors object_totals to crunch more of the data db-side instead of app-side.

This commit is contained in:
Johnny 2020-01-14 22:05:02 +00:00
parent edff348d87
commit b848d321f9
2 changed files with 31 additions and 13 deletions

View file

@ -606,9 +606,9 @@ class CmdObjects(COMMAND_DEFAULT_CLASS):
"|wtypeclass|n", "|wcount|n", "|w%|n", border="table", align="l"
)
typetable.align = "l"
dbtotals = ObjectDB.objects.object_totals()
for path, count in dbtotals.items():
typetable.add_row(path, count, "%.2f" % ((float(count) / nobjs) * 100))
dbtotals = ObjectDB.objects.get_typeclass_totals()
for stat in dbtotals:
typetable.add_row(stat.get('typeclass', '<error>'), stat.get('count', -1), "%.2f" % stat.get('percent', -1))
# last N table
objs = ObjectDB.objects.all().order_by("db_date_created")[

View file

@ -5,7 +5,8 @@ all Attributes and TypedObjects).
"""
import shlex
from django.db.models import Q, Count
from django.db.models import F, Q, Count, ExpressionWrapper, FloatField
from django.db.models.functions import Cast
from evennia.utils import idmapper
from evennia.utils.utils import make_iter, variable_from_module
from evennia.typeclasses.attributes import Attribute
@ -265,7 +266,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
tagtype (str, optional): 'type' of Tag, by default
this is either `None` (a normal Tag), `alias` or
`permission`. This always apply to all queried tags.
Kwargs:
match (str): ALL or ANY, determines whether the target object must match
ALL of the provided tags/categories or ANY single one. ANY will perform
@ -499,7 +500,29 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
if max_dbref is not None:
retval = retval.filter(id__lte=self.dbref(max_dbref, reqhash=False))
return retval
def get_typeclass_totals(self, *args, **kwargs) -> object:
"""
Returns a queryset of typeclass composition statistics.
Returns:
qs (Queryset): A queryset of dicts containing the typeclass (name),
the count of objects with that typeclass and a float representing
the percentage of objects associated with the typeclass.
"""
return self.values('db_typeclass_path').distinct().annotate(
# Get count of how many objects for each typeclass exist
count=Count('db_typeclass_path')
).annotate(
# Rename db_typeclass_path field to something more human
typeclass=F('db_typeclass_path'),
# Calculate this class' percentage of total composition
percent=ExpressionWrapper(
((F('count') / float(self.count())) * 100.0), output_field=FloatField()
),
).values('typeclass', 'count', 'percent')
def object_totals(self):
"""
Get info about database statistics.
@ -511,13 +534,8 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
object having that typeclass set on themselves).
"""
dbtotals = {}
typeclass_paths = set(self.values_list("db_typeclass_path", flat=True))
for typeclass_path in typeclass_paths:
dbtotals[typeclass_path] = self.filter(
db_typeclass_path=typeclass_path
).count()
return dbtotals
stats = self.get_typeclass_totals().order_by('typeclass')
return {x.get('typeclass'):x.get('count') for x in stats}
def typeclass_search(
self, typeclass, include_children=False, include_parents=False