Updated create.create_object to be faster. Made AttributeHandler.add() handle bulk-adding of Attributes and with a slightly more efficient way to create new Attributes.
This commit is contained in:
parent
cda13989f6
commit
05d21ef4f7
3 changed files with 74 additions and 30 deletions
|
|
@ -321,6 +321,12 @@ class AttributeHandler(object):
|
||||||
return ret if len(key) > 1 else default
|
return ret if len(key) > 1 else default
|
||||||
return ret[0] if len(ret)==1 else ret
|
return ret[0] if len(ret)==1 else ret
|
||||||
|
|
||||||
|
def batch_add(self, keys, values, categories=None, lockstrings=None,
|
||||||
|
stratts=None, accessing_obj=None, default_access=True):
|
||||||
|
"""
|
||||||
|
Batch version supporting the addition of more than one
|
||||||
|
"""
|
||||||
|
|
||||||
def add(self, key, value, category=None, lockstring="",
|
def add(self, key, value, category=None, lockstring="",
|
||||||
strattr=False, accessing_obj=None, default_access=True):
|
strattr=False, accessing_obj=None, default_access=True):
|
||||||
"""
|
"""
|
||||||
|
|
@ -332,6 +338,12 @@ class AttributeHandler(object):
|
||||||
If accessing_obj is given, self.obj's 'attrcreate' lock access
|
If accessing_obj is given, self.obj's 'attrcreate' lock access
|
||||||
will be checked against it. If no accessing_obj is given, no check
|
will be checked against it. If no accessing_obj is given, no check
|
||||||
will be done.
|
will be done.
|
||||||
|
|
||||||
|
The method also accepts multiple attributes (this is a faster way
|
||||||
|
to add attributes since it allows for some optimizations).
|
||||||
|
If so, key and value (or strvalue) must be iterables of the same length.
|
||||||
|
All batch-added Attributes will use the same category and lockstring.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if accessing_obj and not self.obj.access(accessing_obj,
|
if accessing_obj and not self.obj.access(accessing_obj,
|
||||||
self._attrcreate, default=default_access):
|
self._attrcreate, default=default_access):
|
||||||
|
|
@ -341,28 +353,41 @@ class AttributeHandler(object):
|
||||||
self._recache()
|
self._recache()
|
||||||
if not key:
|
if not key:
|
||||||
return
|
return
|
||||||
key = key.strip().lower()
|
|
||||||
|
keys, values= make_iter(key), make_iter(value)
|
||||||
|
|
||||||
|
if len(keys) != len(values):
|
||||||
|
raise RuntimeError("AttributeHandler.add(): key and value of different length: %s vs %s" % key, value)
|
||||||
category = category.strip().lower() if category is not None else None
|
category = category.strip().lower() if category is not None else None
|
||||||
cachekey = "%s-%s" % (key, category)
|
new_attrobjs = []
|
||||||
|
for ikey, keystr in enumerate(keys):
|
||||||
|
keystr = keystr.strip().lower()
|
||||||
|
new_value = values[ikey]
|
||||||
|
cachekey = "%s-%s" % (keystr, category)
|
||||||
attr_obj = self._cache.get(cachekey)
|
attr_obj = self._cache.get(cachekey)
|
||||||
if not attr_obj:
|
|
||||||
# no old attr available; create new.
|
if attr_obj:
|
||||||
attr_obj = Attribute(db_key=key, db_category=category,
|
# update an existing attribute object
|
||||||
db_model=self._model, db_attrtype=self._attrtype)
|
|
||||||
attr_obj.save() # important
|
|
||||||
getattr(self.obj, self._m2m_fieldname).add(attr_obj)
|
|
||||||
self._cache[cachekey] = attr_obj
|
|
||||||
if lockstring:
|
|
||||||
attr_obj.locks.add(lockstring)
|
|
||||||
# we shouldn't need to fear stale objects, the field signalling
|
|
||||||
# should catch all cases
|
|
||||||
if strattr:
|
if strattr:
|
||||||
# store as a simple string
|
# store as a simple string (will not notify OOB handlers)
|
||||||
attr_obj.db_strvalue = value
|
attr_obj.db_strvalue = new_value
|
||||||
attr_obj.save(update_fields=["db_strvalue"])
|
attr_obj.save(update_fields=["db_strvalue"])
|
||||||
else:
|
else:
|
||||||
# pickle arbitrary data
|
# store normally (this will also notify OOB handlers)
|
||||||
attr_obj.value = value
|
attr_obj.value = new_value
|
||||||
|
else:
|
||||||
|
# create a new Attribute (no OOB handlers can be notified)
|
||||||
|
kwargs = {"db_key" : keystr, "db_category" : category,
|
||||||
|
"db_model" : self._model, "db_attrtype" : self._attrtype,
|
||||||
|
"db_value" : None if strattr else to_pickle(new_value),
|
||||||
|
"db_strvalue" : value if strattr else None}
|
||||||
|
new_attr = Attribute(**kwargs)
|
||||||
|
new_attr.save()
|
||||||
|
new_attrobjs.append(new_attr)
|
||||||
|
if new_attrobjs:
|
||||||
|
# Add new objects to m2m field all at once
|
||||||
|
getattr(self.obj, self._m2m_fieldname).add(*new_attrobjs)
|
||||||
|
self._recache()
|
||||||
|
|
||||||
def remove(self, key, raise_exception=False, category=None,
|
def remove(self, key, raise_exception=False, category=None,
|
||||||
accessing_obj=None, default_access=True):
|
accessing_obj=None, default_access=True):
|
||||||
|
|
@ -581,8 +606,10 @@ class TagHandler(object):
|
||||||
self.obj, self._m2m_fieldname).filter(
|
self.obj, self._m2m_fieldname).filter(
|
||||||
db_model=self._model).filter(tagtype))
|
db_model=self._model).filter(tagtype))
|
||||||
|
|
||||||
def add(self, tag, category=None, data=None):
|
def add(self, tag=None, category=None, data=None):
|
||||||
"Add a new tag to the handler. Tag is a string or a list of strings."
|
"Add a new tag to the handler. Tag is a string or a list of strings."
|
||||||
|
if not tag:
|
||||||
|
return
|
||||||
for tagstr in make_iter(tag):
|
for tagstr in make_iter(tag):
|
||||||
if not tagstr:
|
if not tagstr:
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,12 @@ def handle_dbref(inp, objclass, raise_errors=True):
|
||||||
objects.
|
objects.
|
||||||
"""
|
"""
|
||||||
if not (isinstance(inp, basestring) and inp.startswith("#")):
|
if not (isinstance(inp, basestring) and inp.startswith("#")):
|
||||||
|
try:
|
||||||
|
return inp.dbobj
|
||||||
|
except AttributeError:
|
||||||
return inp
|
return inp
|
||||||
|
|
||||||
|
# a string, analyze it
|
||||||
inp = inp.lstrip('#')
|
inp = inp.lstrip('#')
|
||||||
try:
|
try:
|
||||||
if int(inp) < 0:
|
if int(inp) < 0:
|
||||||
|
|
@ -67,7 +72,7 @@ def handle_dbref(inp, objclass, raise_errors=True):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# if we get to this point, inp is an integer dbref
|
# if we get to this point, inp is an integer dbref; get the matching object
|
||||||
try:
|
try:
|
||||||
return objclass.objects.get(id=inp)
|
return objclass.objects.get(id=inp)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
@ -98,7 +103,7 @@ def create_object(typeclass=None, key=None, location=None,
|
||||||
containing the error message. If set, this method will return
|
containing the error message. If set, this method will return
|
||||||
None upon errors.
|
None upon errors.
|
||||||
nohome - this allows the creation of objects without a default home location;
|
nohome - this allows the creation of objects without a default home location;
|
||||||
this only used when creating default location itself or during unittests
|
this only used when creating the default location itself or during unittests
|
||||||
"""
|
"""
|
||||||
global _Object, _ObjectDB
|
global _Object, _ObjectDB
|
||||||
if not _Object:
|
if not _Object:
|
||||||
|
|
@ -122,7 +127,6 @@ def create_object(typeclass=None, key=None, location=None,
|
||||||
|
|
||||||
location = handle_dbref(location, _ObjectDB)
|
location = handle_dbref(location, _ObjectDB)
|
||||||
destination = handle_dbref(destination, _ObjectDB)
|
destination = handle_dbref(destination, _ObjectDB)
|
||||||
report_to = handle_dbref(report_to, _ObjectDB)
|
|
||||||
home = handle_dbref(home, _ObjectDB)
|
home = handle_dbref(home, _ObjectDB)
|
||||||
if not home:
|
if not home:
|
||||||
try:
|
try:
|
||||||
|
|
@ -136,9 +140,8 @@ def create_object(typeclass=None, key=None, location=None,
|
||||||
db_destination=destination, db_home=home,
|
db_destination=destination, db_home=home,
|
||||||
db_typeclass_path=typeclass)
|
db_typeclass_path=typeclass)
|
||||||
|
|
||||||
# the name/key is often set later in the typeclass. This
|
|
||||||
# is set here as a failsafe.
|
|
||||||
if not key:
|
if not key:
|
||||||
|
# the object should always have a key, so if not set we give a default
|
||||||
new_db_object.key = "#%i" % new_db_object.dbid
|
new_db_object.key = "#%i" % new_db_object.dbid
|
||||||
|
|
||||||
# this will either load the typeclass or the default one (will also save object)
|
# this will either load the typeclass or the default one (will also save object)
|
||||||
|
|
@ -149,6 +152,7 @@ def create_object(typeclass=None, key=None, location=None,
|
||||||
# gave us a default
|
# gave us a default
|
||||||
SharedMemoryModel.delete(new_db_object)
|
SharedMemoryModel.delete(new_db_object)
|
||||||
if report_to:
|
if report_to:
|
||||||
|
report_to = handle_dbref(report_to, _ObjectDB)
|
||||||
_GA(report_to, "msg")("Error creating %s (%s).\n%s" % (new_db_object.key, typeclass,
|
_GA(report_to, "msg")("Error creating %s (%s).\n%s" % (new_db_object.key, typeclass,
|
||||||
_GA(new_db_object, "typeclass_last_errmsg")))
|
_GA(new_db_object, "typeclass_last_errmsg")))
|
||||||
return None
|
return None
|
||||||
|
|
@ -162,10 +166,21 @@ def create_object(typeclass=None, key=None, location=None,
|
||||||
# customization happens as the typeclass stores custom
|
# customization happens as the typeclass stores custom
|
||||||
# things on its database object.
|
# things on its database object.
|
||||||
|
|
||||||
# note - this will override eventual custom keys, locations etc!
|
# note - this may override input keys, locations etc!
|
||||||
new_object.basetype_setup() # setup the basics of Exits, Characters etc.
|
new_object.basetype_setup() # setup the basics of Exits, Characters etc.
|
||||||
new_object.at_object_creation()
|
new_object.at_object_creation()
|
||||||
|
|
||||||
|
# we want the input to override that set in the hooks, so
|
||||||
|
# we re-apply those if needed
|
||||||
|
if new_object.key != key:
|
||||||
|
new_object.key = key
|
||||||
|
if new_object.location != location:
|
||||||
|
new_object.location = location
|
||||||
|
if new_object.home != home:
|
||||||
|
new_object.home = home
|
||||||
|
if new_object.destination != destination:
|
||||||
|
new_object.destination = destination
|
||||||
|
|
||||||
# custom-given perms/locks do overwrite hooks
|
# custom-given perms/locks do overwrite hooks
|
||||||
if permissions:
|
if permissions:
|
||||||
new_object.permissions.add(permissions)
|
new_object.permissions.add(permissions)
|
||||||
|
|
@ -174,7 +189,7 @@ def create_object(typeclass=None, key=None, location=None,
|
||||||
if aliases:
|
if aliases:
|
||||||
new_object.aliases.add(aliases)
|
new_object.aliases.add(aliases)
|
||||||
|
|
||||||
# trigger relevant move_to hooks in order to display eventual messages.
|
# trigger relevant move_to hooks in order to display messages.
|
||||||
if location:
|
if location:
|
||||||
new_object.at_object_receive(new_object, None)
|
new_object.at_object_receive(new_object, None)
|
||||||
new_object.at_after_move(new_object)
|
new_object.at_after_move(new_object)
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@ from django.forms import CharField, Textarea
|
||||||
from django.forms.util import flatatt
|
from django.forms.util import flatatt
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
|
|
||||||
|
from src.utils.dbserialize import from_pickle, to_pickle
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue