Modifies filter chain to use Q objects.

This commit is contained in:
Johnny 2019-12-04 00:42:08 +00:00
parent a6f5cccdfa
commit fe99edd611

View file

@ -5,7 +5,7 @@ all Attributes and TypedObjects).
""" """
import shlex import shlex
from django.db.models import Q from django.db.models import Q, Count
from evennia.utils import idmapper from evennia.utils import idmapper
from evennia.utils.utils import make_iter, variable_from_module from evennia.utils.utils import make_iter, variable_from_module
from evennia.typeclasses.attributes import Attribute from evennia.typeclasses.attributes import Attribute
@ -236,7 +236,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
""" """
return self.get_tag(key=key, category=category, obj=obj, tagtype="alias") return self.get_tag(key=key, category=category, obj=obj, tagtype="alias")
def get_by_tag(self, key=None, category=None, tagtype=None): def get_by_tag(self, key=None, category=None, tagtype=None, **kwargs):
""" """
Return objects having tags with a given key or category or combination of the two. Return objects having tags with a given key or category or combination of the two.
Also accepts multiple tags/category/tagtype Also accepts multiple tags/category/tagtype
@ -262,6 +262,10 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
if not (key or category): if not (key or category):
return [] return []
global _Tag
if not _Tag:
from evennia.typeclasses.models import Tag as _Tag
keys = make_iter(key) if key else [] keys = make_iter(key) if key else []
categories = make_iter(category) if category else [] categories = make_iter(category) if category else []
n_keys = len(keys) n_keys = len(keys)
@ -271,7 +275,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
query = ( query = (
self.filter(db_tags__db_tagtype__iexact=tagtype, db_tags__db_model__iexact=dbmodel) self.filter(db_tags__db_tagtype__iexact=tagtype, db_tags__db_model__iexact=dbmodel)
.distinct() .distinct()
.order_by("id") #.order_by("id")
) )
if n_keys > 0: if n_keys > 0:
@ -286,16 +290,30 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
"get_by_tag needs a single category or a list of categories " "get_by_tag needs a single category or a list of categories "
"the same length as the list of tags." "the same length as the list of tags."
) )
clauses = Q()
for ikey, key in enumerate(keys): for ikey, key in enumerate(keys):
query = query.filter( # Keep each key and category together, grouped by AND
db_tags__db_key__iexact=key, db_tags__db_category__iexact=categories[ikey] clause = Q(db_key__iexact=key, db_category__iexact=categories[ikey])
) clauses |= clause
query = query.filter(db_tags__in=_Tag.objects.filter(clauses)).annotate(num_tags=Count('db_tags', distinct=True)).filter(num_tags__gte=len(keys))
print(keys, query.query)
else: else:
# only one or more categories given # only one or more categories given
for category in categories: clauses = Q()
query = query.filter(db_tags__db_category__iexact=category) uniq_categories = sorted(set(categories))
for category in uniq_categories:
clause = Q(db_category__iexact=category,)
return query # Join all discrete clauses with an OR
clauses |= clause
query = query.filter(db_tags__in=_Tag.objects.filter(clauses)).annotate(num_tags=Count('db_tags__db_category', distinct=True)).filter(num_tags__gte=len(uniq_categories))
return query.order_by('-num_tags')
def get_by_permission(self, key=None, category=None): def get_by_permission(self, key=None, category=None):
""" """