Optimize/fix searching objects by-attribute-value

This commit is contained in:
Griatch 2020-07-27 20:44:14 +02:00
parent 23767f4205
commit b5d148b00a
2 changed files with 21 additions and 26 deletions

View file

@ -154,7 +154,7 @@ class ObjectDBManager(TypedObjectManager):
Args: Args:
attribute_name (str): Attribute key to search for. attribute_name (str): Attribute key to search for.
attribute_value (str): Attribute value to search for. attribute_value (any): Attribute value to search for. This can also be database objects.
candidates (list, optional): Candidate objects to limit search to. candidates (list, optional): Candidate objects to limit search to.
typeclasses (list, optional): Python pats to restrict matches with. typeclasses (list, optional): Python pats to restrict matches with.
@ -175,31 +175,16 @@ class ObjectDBManager(TypedObjectManager):
) )
type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q() type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q()
# This doesn't work if attribute_value is an object. Workaround below results = (
self
if isinstance(attribute_value, (str, int, float, bool)): .filter(
return self.filter(
cand_restriction cand_restriction
& type_restriction & type_restriction
& Q(db_attributes__db_key=attribute_name, db_attributes__db_value=attribute_value) & Q(db_attributes__db_key=attribute_name)
).order_by("id") & Q(db_attributes__db_value=attribute_value))
else: .order_by("id")
# We must loop for safety since the referenced lookup gives deepcopy error if attribute value is an object. )
global _ATTR return results
if not _ATTR:
from evennia.typeclasses.models import Attribute as _ATTR
cands = list(
self.filter(
cand_restriction & type_restriction & Q(db_attributes__db_key=attribute_name)
)
)
results = [
attr.objectdb_set.all()
for attr in _ATTR.objects.filter(
objectdb__in=cands, db_value=attribute_value
).order_by("id")
]
return chain(*results)
def get_objs_with_db_property(self, property_name, candidates=None): def get_objs_with_db_property(self, property_name, candidates=None):
""" """

View file

@ -31,7 +31,7 @@ Modified for Evennia by Griatch and the Evennia community.
from ast import literal_eval from ast import literal_eval
from datetime import datetime from datetime import datetime
from copy import deepcopy from copy import deepcopy, Error as CopyError
from base64 import b64encode, b64decode from base64 import b64encode, b64decode
from zlib import compress, decompress from zlib import compress, decompress
@ -44,6 +44,7 @@ from django.forms.widgets import Textarea
from pickle import loads, dumps from pickle import loads, dumps
from django.utils.encoding import force_str from django.utils.encoding import force_str
from evennia.utils.dbserialize import pack_dbobj
DEFAULT_PROTOCOL = 4 DEFAULT_PROTOCOL = 4
@ -92,7 +93,16 @@ def dbsafe_encode(value, compress_object=False, pickle_protocol=DEFAULT_PROTOCOL
# The reason this is important is because we do all of our lookups as # The reason this is important is because we do all of our lookups as
# simple string matches, thus the character streams must be the same # simple string matches, thus the character streams must be the same
# for the lookups to work properly. See tests.py for more information. # for the lookups to work properly. See tests.py for more information.
value = dumps(deepcopy(value), protocol=pickle_protocol) try:
value = deepcopy(value)
except CopyError:
# this can happen on a manager query where the search query string is a
# database model.
value = pack_dbobj(value)
value = dumps(value, protocol=pickle_protocol)
if compress_object: if compress_object:
value = compress(value) value = compress(value)
value = b64encode(value).decode() # decode bytes to str value = b64encode(value).decode() # decode bytes to str