mirror of
https://github.com/evennia/evennia.git
synced 2026-03-27 18:26:32 +01:00
First test with moving Attributes to m2m field. Not working yet.
This commit is contained in:
parent
a0a94df83d
commit
a1d818f8aa
7 changed files with 169 additions and 143 deletions
|
|
@ -17,13 +17,13 @@ transparently through the decorating TypeClass.
|
|||
import traceback
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
from django.db.models.signals import post_init, pre_delete
|
||||
from django.db.models.signals import m2m_changed
|
||||
|
||||
from src.utils.idmapper.models import SharedMemoryModel
|
||||
from src.typeclasses.models import Attribute, TypedObject, TypeNick, TypeNickHandler
|
||||
from src.server.caches import get_field_cache, set_field_cache, del_field_cache
|
||||
from src.server.caches import get_prop_cache, set_prop_cache, del_prop_cache
|
||||
from src.server.caches import attr_post_init, attr_pre_delete
|
||||
|
||||
from src.typeclasses.typeclass import TypeClass
|
||||
from src.players.models import PlayerNick
|
||||
from src.objects.manager import ObjectManager
|
||||
|
|
@ -36,7 +36,7 @@ from src.utils.utils import make_iter, to_unicode, variable_from_module, inherit
|
|||
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
#__all__ = ("ObjAttribute", "Alias", "ObjectNick", "ObjectDB")
|
||||
#__all__ = ("Alias", "ObjectNick", "ObjectDB")
|
||||
|
||||
_ScriptDB = None
|
||||
_AT_SEARCH_RESULT = variable_from_module(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
|
||||
|
|
@ -66,8 +66,8 @@ class ObjAttribute(Attribute):
|
|||
verbose_name_plural = "Object Attributes"
|
||||
|
||||
# attach the cache handlers
|
||||
post_init.connect(attr_post_init, sender=ObjAttribute, dispatch_uid="objattrcache")
|
||||
pre_delete.connect(attr_pre_delete, sender=ObjAttribute, dispatch_uid="objattrcache")
|
||||
#post_init.connect(attr_post_init, sender=ObjAttribute, dispatch_uid="objattrcache")
|
||||
#pre_delete.connect(attr_pre_delete, sender=ObjAttribute, dispatch_uid="objattrcache")
|
||||
|
||||
#------------------------------------------------------------
|
||||
#
|
||||
|
|
@ -518,7 +518,7 @@ class ObjectDB(TypedObject):
|
|||
|
||||
# this is required to properly handle attributes and typeclass loading.
|
||||
_typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
|
||||
_attribute_class = ObjAttribute
|
||||
#_attribute_class = ObjAttribute
|
||||
_db_model_name = "objectdb" # used by attributes to safely store objects
|
||||
_default_typeclass_path = settings.BASE_OBJECT_TYPECLASS or "src.objects.objects.Object"
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ from django.db.models.signals import post_init, pre_delete
|
|||
|
||||
from src.server.caches import get_field_cache, set_field_cache, del_field_cache
|
||||
from src.server.caches import get_prop_cache, set_prop_cache, del_prop_cache
|
||||
from src.server.caches import attr_post_init, attr_pre_delete
|
||||
|
||||
from src.players import manager
|
||||
from src.scripts.models import ScriptDB
|
||||
|
|
@ -44,7 +43,7 @@ from src.utils.utils import inherits_from, make_iter
|
|||
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
__all__ = ("PlayerAttribute", "PlayerNick", "PlayerDB")
|
||||
__all__ = ("PlayerNick", "PlayerDB")
|
||||
|
||||
_ME = _("me")
|
||||
_SELF = _("self")
|
||||
|
|
@ -77,8 +76,8 @@ class PlayerAttribute(Attribute):
|
|||
"Define Django meta options"
|
||||
verbose_name = "Player Attribute"
|
||||
|
||||
post_init.connect(attr_post_init, sender=PlayerAttribute, dispatch_uid="playerattrcache")
|
||||
pre_delete.connect(attr_pre_delete, sender=PlayerAttribute, dispatch_uid="playerattrcache")
|
||||
#post_init.connect(attr_post_init, sender=PlayerAttribute, dispatch_uid="playerattrcache")
|
||||
#pre_delete.connect(attr_pre_delete, sender=PlayerAttribute, dispatch_uid="playerattrcache")
|
||||
|
||||
#------------------------------------------------------------
|
||||
#
|
||||
|
|
@ -252,7 +251,7 @@ class PlayerDB(TypedObject):
|
|||
|
||||
# this is required to properly handle attributes and typeclass loading
|
||||
_typeclass_paths = settings.PLAYER_TYPECLASS_PATHS
|
||||
_attribute_class = PlayerAttribute
|
||||
#_attribute_class = PlayerAttribute
|
||||
_db_model_name = "playerdb" # used by attributes to safely store objects
|
||||
_default_typeclass_path = settings.BASE_PLAYER_TYPECLASS or "src.players.player.Player"
|
||||
|
||||
|
|
|
|||
|
|
@ -28,12 +28,11 @@ from django.conf import settings
|
|||
from django.db import models
|
||||
from django.db.models.signals import post_init, pre_delete
|
||||
|
||||
from src.server.caches import attr_post_init, attr_pre_delete
|
||||
from src.typeclasses.models import Attribute, TypedObject
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from src.scripts.manager import ScriptManager
|
||||
|
||||
__all__ = ("ScriptAttribute", "ScriptDB")
|
||||
__all__ = ("ScriptDB",)
|
||||
|
||||
#------------------------------------------------------------
|
||||
#
|
||||
|
|
@ -50,9 +49,9 @@ class ScriptAttribute(Attribute):
|
|||
verbose_name = "Script Attribute"
|
||||
verbose_name_plural = "Script Attributes"
|
||||
|
||||
# attach cache handlers for attribute lookup
|
||||
post_init.connect(attr_post_init, sender=ScriptAttribute, dispatch_uid="scriptattrcache")
|
||||
pre_delete.connect(attr_pre_delete, sender=ScriptAttribute, dispatch_uid="scriptattrcache")
|
||||
## attach cache handlers for attribute lookup
|
||||
#post_init.connect(attr_post_init, sender=ScriptAttribute, dispatch_uid="scriptattrcache")
|
||||
#pre_delete.connect(attr_pre_delete, sender=ScriptAttribute, dispatch_uid="scriptattrcache")
|
||||
|
||||
#------------------------------------------------------------
|
||||
#
|
||||
|
|
@ -254,7 +253,7 @@ class ScriptDB(TypedObject):
|
|||
|
||||
# this is required to properly handle attributes and typeclass loading
|
||||
_typeclass_paths = settings.SCRIPT_TYPECLASS_PATHS
|
||||
_attribute_class = ScriptAttribute
|
||||
#_attribute_class = ScriptAttribute
|
||||
_db_model_name = "scriptdb" # used by attributes to safely store objects
|
||||
_default_typeclass_path = settings.BASE_SCRIPT_TYPECLASS or "src.scripts.scripts.DoNothing"
|
||||
|
||||
|
|
|
|||
|
|
@ -141,26 +141,34 @@ def field_pre_save(sender, instance=None, update_fields=None, raw=False, **kwarg
|
|||
# to any property).
|
||||
#------------------------------------------------------------
|
||||
|
||||
# connected to post_init signal (connected in respective Attribute model)
|
||||
def attr_post_init(sender, instance=None, **kwargs):
|
||||
"Called when attribute is created or retrieved in connection with obj."
|
||||
#print "attr_post_init:", instance, instance.db_obj, instance.db_key
|
||||
hid = hashid(_GA(instance, "db_obj"), "-%s" % _GA(instance, "db_key"))
|
||||
if hid:
|
||||
global _ATTR_CACHE
|
||||
_ATTR_CACHE[hid] = sender
|
||||
#_ATTR_CACHE.set(hid, sender)
|
||||
|
||||
# connected to pre_delete signal (connected in respective Attribute model)
|
||||
def attr_pre_delete(sender, instance=None, **kwargs):
|
||||
"Called when attribute is deleted (del_attribute)"
|
||||
#print "attr_pre_delete:", instance, instance.db_obj, instance.db_key
|
||||
hid = hashid(_GA(instance, "db_obj"), "-%s" % _GA(instance, "db_key"))
|
||||
if hid:
|
||||
#print "attr_pre_delete:", _GA(instance, "db_key")
|
||||
global _ATTR_CACHE
|
||||
del _ATTR_CACHE[hid]
|
||||
#_ATTR_CACHE.delete(hid)
|
||||
# connected to m2m_changed signal in respective model class
|
||||
def update_attr_cache(sender, **kwargs):
|
||||
"Called when the many2many relation changes some way"
|
||||
obj = kwargs['instance']
|
||||
model = kwargs['model']
|
||||
action = kwargs['action']
|
||||
if kwargs['reverse']:
|
||||
# the reverse relation changed (the Attribute itself was acted on)
|
||||
pass
|
||||
else:
|
||||
# forward relation changed (the Object holding the Attribute m2m field)
|
||||
if action == "post_add":
|
||||
# cache all added objects
|
||||
for attr_id in kwargs["pk_set"]:
|
||||
attr_obj = model.objects.get(pk=attr_id)
|
||||
set_attr_cache(obj, _GA(attr_obj, "db_key"), attr_obj)
|
||||
elif action == "post_remove":
|
||||
# obj.db_attributes.remove(attr) was called
|
||||
for attr_id in kwargs["pk_set"]:
|
||||
attr_obj = model.objects.get(pk=attr_id)
|
||||
del_attr_cache(obj, _GA(attr_obj, "db_key"))
|
||||
attr_obj.delete()
|
||||
elif action == "post_clear":
|
||||
# obj.db_attributes.clear() was called
|
||||
for attr_id in kwargs["pk_set"]:
|
||||
attr_obj = model.objects.get(pk=attr_id)
|
||||
del_attr_cache(obj, _GA(attr_obj, "db_key"))
|
||||
attr_obj.delete()
|
||||
|
||||
# access methods
|
||||
|
||||
|
|
@ -169,15 +177,23 @@ def get_attr_cache(obj, attrname):
|
|||
hid = hashid(obj, "-%s" % attrname)
|
||||
return hid and _ATTR_CACHE.get(hid, None) or None
|
||||
|
||||
def set_attr_cache(attrobj):
|
||||
def set_attr_cache(obj, attrname, attrobj):
|
||||
"Set the attr cache manually; this can be used to update"
|
||||
attr_post_init(None, instance=attrobj)
|
||||
global _ATTR_CACHE
|
||||
hid = hashid(obj, "-%s" % attrname)
|
||||
_ATTR_CACHE[hid] = attrobj
|
||||
|
||||
def del_attr_cache(obj, attrname):
|
||||
"Del attribute cache"
|
||||
global _ATTR_CACHE
|
||||
hid = hashid(obj, "-%s" % attrname)
|
||||
if hid in _ATTR_CACHE:
|
||||
del _ATTR_CACHE[hid]
|
||||
|
||||
def flush_attr_cache():
|
||||
"Clear attribute cache"
|
||||
global _ATTR_CACHE
|
||||
_ATTR_CACHE = {}
|
||||
#_ATTR_CACHE.clear()
|
||||
|
||||
#------------------------------------------------------------
|
||||
# Property cache - this is a generic cache for properties stored on models.
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@ all Attributes and TypedObjects).
|
|||
"""
|
||||
from functools import update_wrapper
|
||||
from django.db import models
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from src.utils import idmapper
|
||||
from src.utils.utils import make_iter
|
||||
from src.utils.dbserialize import to_pickle
|
||||
|
||||
__all__ = ("AttributeManager", "TypedObjectManager")
|
||||
_GA = object.__getattribute__
|
||||
|
||||
# Managers
|
||||
|
||||
|
|
@ -50,26 +52,33 @@ class AttributeManager(models.Manager):
|
|||
|
||||
def attr_namesearch(self, searchstr, obj, exact_match=True):
|
||||
"""
|
||||
Searches the object's attributes for name matches.
|
||||
Searches the object's attributes for attribute key matches.
|
||||
|
||||
searchstr: (str) A string to search for.
|
||||
"""
|
||||
# Retrieve the list of attributes for this object.
|
||||
|
||||
if exact_match:
|
||||
return self.filter(db_obj=obj).filter(
|
||||
db_key__iexact=searchstr)
|
||||
return _GA("obj", "db_attributes").filter(db_key__iexact=searchstr)
|
||||
else:
|
||||
return self.filter(db_obj=obj).filter(
|
||||
db_key__icontains=searchstr)
|
||||
return _GA("obj", "db_attributes").filter(db_key__icontains=searchstr)
|
||||
|
||||
def attr_valuesearch(self, searchstr, obj=None):
|
||||
"""
|
||||
Searches for Attributes with a given value on obj
|
||||
Searches obj for Attributes with a given value.
|
||||
searchstr - value to search for. This may be any suitable object.
|
||||
obj - limit to a given object instance
|
||||
|
||||
If no restraint is given, all Attributes on all types of objects
|
||||
will be searched. It's highly recommended to at least
|
||||
supply the objclass argument (DBObject, DBScript or DBPlayer)
|
||||
to restrict this lookup.
|
||||
"""
|
||||
if obj:
|
||||
return self.filter(db_obj=obj, db_value=searchstr)
|
||||
return _GA(obj, "db_attributes").filter(db_value=searchstr)
|
||||
return self.filter(db_value=searchstr)
|
||||
|
||||
|
||||
#
|
||||
# helper functions for the TypedObjectManager.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -34,15 +34,18 @@ import sys
|
|||
import traceback
|
||||
#from collections import defaultdict
|
||||
|
||||
from django.db import models, IntegrityError
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
from django.utils.encoding import smart_str
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db.models.fields import AutoField, FieldDoesNotExist
|
||||
from src.utils.idmapper.models import SharedMemoryModel
|
||||
from src.server.caches import get_field_cache, set_field_cache, del_field_cache
|
||||
from src.server.caches import get_attr_cache, set_attr_cache
|
||||
from src.server.caches import get_prop_cache, set_prop_cache, del_prop_cache, flush_attr_cache
|
||||
|
||||
from django.db.models.signals import m2m_changed
|
||||
from src.server.caches import update_attr_cache
|
||||
|
||||
#from src.server.caches import call_ndb_hooks
|
||||
from src.server.models import ServerConfig
|
||||
from src.typeclasses import managers
|
||||
|
|
@ -61,6 +64,7 @@ _GA = object.__getattribute__
|
|||
_SA = object.__setattr__
|
||||
_DA = object.__delattr__
|
||||
|
||||
|
||||
#------------------------------------------------------------
|
||||
#
|
||||
# Attributes
|
||||
|
|
@ -106,12 +110,12 @@ class Attribute(SharedMemoryModel):
|
|||
|
||||
db_key = models.CharField('key', max_length=255, db_index=True)
|
||||
# access through the value property
|
||||
db_value = PickledObjectField('value2', null=True)
|
||||
db_value = PickledObjectField('value', null=True)
|
||||
# Lock storage
|
||||
db_lock_storage = models.TextField('locks', blank=True)
|
||||
# references the object the attribute is linked to (this is set
|
||||
# by each child class to this abstract class)
|
||||
db_obj = None # models.ForeignKey("RefencedObject")
|
||||
db_obj = None # models.ForeignKey("RefencedObject") #TODO-remove
|
||||
# time stamp
|
||||
db_date_created = models.DateTimeField('date_created', editable=False, auto_now_add=True)
|
||||
|
||||
|
|
@ -128,7 +132,7 @@ class Attribute(SharedMemoryModel):
|
|||
|
||||
class Meta:
|
||||
"Define Django meta options"
|
||||
abstract = True
|
||||
#abstract = True
|
||||
verbose_name = "Evennia Attribute"
|
||||
|
||||
# Wrapper properties to easily set database fields. These are
|
||||
|
|
@ -426,7 +430,8 @@ class TypedObject(SharedMemoryModel):
|
|||
# Lock storage
|
||||
db_lock_storage = models.TextField('locks', blank=True, help_text="locks limit access to an entity. A lock is defined as a 'lock string' on the form 'type:lockfunctions', defining what functionality is locked and how to determine access. Not defining a lock means no access is granted.")
|
||||
|
||||
#db_attributes = models.ManyToManyField(Attribute, related_name="%(app_label)s_%(class)s_related")
|
||||
# attribute store
|
||||
db_attributes = models.ManyToManyField(Attribute, null=True, help_text='attributes on this object. An attribute can hold any pickle-able python object (see docs for special cases).')
|
||||
|
||||
# Database manager
|
||||
objects = managers.TypedObjectManager()
|
||||
|
|
@ -923,10 +928,10 @@ class TypedObject(SharedMemoryModel):
|
|||
#
|
||||
|
||||
#
|
||||
# Fully persistent attributes. You usually access these
|
||||
# Fully attr_obj attributes. You usually access these
|
||||
# through the obj.db.attrname method.
|
||||
|
||||
# Helper methods for persistent attributes
|
||||
# Helper methods for attr_obj attributes
|
||||
|
||||
def has_attribute(self, attribute_name):
|
||||
"""
|
||||
|
|
@ -935,10 +940,9 @@ class TypedObject(SharedMemoryModel):
|
|||
attribute_name: (str) The attribute's name.
|
||||
"""
|
||||
if not get_attr_cache(self, attribute_name):
|
||||
attrib_obj = _GA(self, "_attribute_class").objects.filter(
|
||||
db_obj=self, db_key__iexact=attribute_name)
|
||||
if attrib_obj:
|
||||
set_attr_cache(attrib_obj[0])
|
||||
attr_obj = _GA(self, "db_attributes").filter(db_key__iexact=attribute_name)
|
||||
if attr_obj:
|
||||
set_attr_cache(self, attribute_name, attr_obj[0])
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
|
@ -956,46 +960,38 @@ class TypedObject(SharedMemoryModel):
|
|||
below to perform access-checked modification of attributes. Lock
|
||||
types checked by secureattr are 'attrread','attredit','attrcreate'.
|
||||
"""
|
||||
attrib_obj = get_attr_cache(self, attribute_name)
|
||||
if not attrib_obj:
|
||||
attrclass = _GA(self, "_attribute_class")
|
||||
# check if attribute already exists.
|
||||
attrib_obj = attrclass.objects.filter(
|
||||
db_obj=self, db_key__iexact=attribute_name)
|
||||
if attrib_obj:
|
||||
# use old attribute
|
||||
attrib_obj = attrib_obj[0]
|
||||
set_attr_cache(attrib_obj) # renew cache
|
||||
attr_obj = get_attr_cache(self, attribute_name)
|
||||
if not attr_obj:
|
||||
# check if attribute already exists
|
||||
attr_obj = _GA(self, "db_attributes").filter(db_key__iexact=attribute_name)
|
||||
if attr_obj:
|
||||
# re-use old attribute object
|
||||
attr_obj = attr_obj[0]
|
||||
set_attr_cache(self, attribute_name, attr_obj) # renew cache
|
||||
else:
|
||||
# no match; create new attribute (this will cache automatically)
|
||||
attrib_obj = attrclass(db_key=attribute_name, db_obj=self)
|
||||
# no old attr available; create new (caches automatically)
|
||||
attr_obj = Attribute(db_key=attribute_name)
|
||||
attr_obj.save() # important
|
||||
_GA(self, "db_attributes").add(attr_obj)
|
||||
if lockstring:
|
||||
attrib_obj.locks.add(lockstring)
|
||||
# re-set an old attribute value
|
||||
try:
|
||||
attrib_obj.value = new_value
|
||||
except IntegrityError:
|
||||
# this can happen if the cache was stale and the database object is
|
||||
# missing. If so we need to clean self.hashid from the cache
|
||||
flush_attr_cache(self)
|
||||
self.delete()
|
||||
raise IntegrityError("Attribute could not be saved - object %s was deleted from database." % self.key)
|
||||
attr_obj.locks.add(lockstring)
|
||||
# we shouldn't need to fear stale objects, the signalling should catch all cases
|
||||
attr_obj.value = new_value
|
||||
|
||||
def get_attribute_obj(self, attribute_name, default=None):
|
||||
"""
|
||||
Get the actual attribute object named attribute_name
|
||||
"""
|
||||
attrib_obj = get_attr_cache(self, attribute_name)
|
||||
if not attrib_obj:
|
||||
attrib_obj = _GA(self, "_attribute_class").objects.filter(
|
||||
db_obj=self, db_key__iexact=attribute_name)
|
||||
if not attrib_obj:
|
||||
attr_obj = get_attr_cache(self, attribute_name)
|
||||
if not attr_obj:
|
||||
attr_obj = _GA(self, "db_attributes").filter(db_key__iexact=attribute_name)
|
||||
if not attr_obj:
|
||||
return default
|
||||
set_attr_cache(attrib_obj[0]) #query is first evaluated here
|
||||
return attrib_obj[0]
|
||||
return attrib_obj
|
||||
attr_obj = attr_obj[0] # query evaluated here
|
||||
set_attr_cache(self, attribute_name, attr_obj)
|
||||
return attr_obj
|
||||
|
||||
def get_attribute(self, attribute_name, default=None):
|
||||
def get_attribute(self, attribute_name, default=None, raise_exception=False):
|
||||
"""
|
||||
Returns the value of an attribute on an object. You may need to
|
||||
type cast the returned value from this function since the attribute
|
||||
|
|
@ -1003,73 +999,76 @@ class TypedObject(SharedMemoryModel):
|
|||
|
||||
attribute_name: (str) The attribute's name.
|
||||
default: What to return if no attribute is found
|
||||
raise_exception (bool) - raise an eception if no object exists instead of returning default.
|
||||
"""
|
||||
attrib_obj = get_attr_cache(self, attribute_name)
|
||||
if not attrib_obj:
|
||||
attrib_obj = _GA(self, "_attribute_class").objects.filter(
|
||||
db_obj=self, db_key__iexact=attribute_name)
|
||||
if not attrib_obj:
|
||||
attr_obj = get_attr_cache(self, attribute_name)
|
||||
if not attr_obj:
|
||||
attr_obj = _GA(self, "db_atttributes").filter(db_key__iexact=attribute_name)
|
||||
if not attr_obj:
|
||||
if raise_exception:
|
||||
raise AttributeError
|
||||
return default
|
||||
set_attr_cache(attrib_obj[0]) #query is first evaluated here
|
||||
return attrib_obj[0].value
|
||||
return attrib_obj.value
|
||||
attr_obj = attr_obj[0] # query is evaluated here
|
||||
set_attr_cache(self, attribute_name, attr_obj)
|
||||
return attr_obj.value
|
||||
|
||||
def get_attribute_raise(self, attribute_name):
|
||||
"""
|
||||
Returns value of an attribute. Raises AttributeError
|
||||
if no match is found.
|
||||
# def get_attribute_raise(self, attribute_name):
|
||||
# """
|
||||
# Returns value of an attribute. Raises AttributeError
|
||||
# if no match is found.
|
||||
#
|
||||
# attribute_name: (str) The attribute's name.
|
||||
# """
|
||||
# attr_obj = get_attr_cache(self, attribute_name)
|
||||
# if not attr_obj:
|
||||
# attr_obj = _GA(self, "attributes").filter(db_key__iexact=attribute_name)
|
||||
# if not attr_obj:
|
||||
# raise AttributeError
|
||||
# attr_obj = attrib_obj[0] # query is evaluated here
|
||||
# set_attr_cache(self, attribute_name, attr_obj[0])
|
||||
# return attr_obj.value
|
||||
|
||||
attribute_name: (str) The attribute's name.
|
||||
"""
|
||||
attrib_obj = get_attr_cache(self, attribute_name)
|
||||
if not attrib_obj:
|
||||
attrib_obj = _GA(self, "_attribute_class").objects.filter(
|
||||
db_obj=self, db_key__iexact=attribute_name)
|
||||
if not attrib_obj:
|
||||
raise AttributeError
|
||||
set_attr_cache(attrib_obj[0]) #query is first evaluated here
|
||||
return attrib_obj[0].value
|
||||
return attrib_obj.value
|
||||
|
||||
def del_attribute(self, attribute_name):
|
||||
def del_attribute(self, attribute_name, raise_exception=False):
|
||||
"""
|
||||
Removes an attribute entirely.
|
||||
|
||||
attribute_name: (str) The attribute's name.
|
||||
raise_exception (bool) - raise exception if attribute to delete
|
||||
could not be found
|
||||
"""
|
||||
attr_obj = get_attr_cache(self, attribute_name)
|
||||
if attr_obj:
|
||||
attr_obj.delete() # this will clear attr cache automatically
|
||||
else:
|
||||
try:
|
||||
_GA(self, "_attribute_class").objects.filter(
|
||||
db_obj=self, db_key__iexact=attribute_name)[0].delete()
|
||||
except IndexError:
|
||||
pass
|
||||
attr_obj = _GA(self, "db_attributes").filter(db_key__iexact=attribute_name)
|
||||
if attr_obj:
|
||||
attr_obj[0].delete()
|
||||
elif raise_exception:
|
||||
raise AttributeError
|
||||
|
||||
def del_attribute_raise(self, attribute_name):
|
||||
"""
|
||||
Removes and attribute. Raises AttributeError if
|
||||
attribute is not found.
|
||||
|
||||
attribute_name: (str) The attribute's name.
|
||||
"""
|
||||
attr_obj = get_attr_cache(self, attribute_name)
|
||||
if attr_obj:
|
||||
attr_obj.delete() # this will clear attr cache automatically
|
||||
else:
|
||||
try:
|
||||
_GA(self, "_attribute_class").objects.filter(
|
||||
db_obj=self, db_key__iexact=attribute_name)[0].delete()
|
||||
except IndexError:
|
||||
pass
|
||||
raise AttributeError
|
||||
# def del_attribute_raise(self, attribute_name):
|
||||
# """
|
||||
# Removes and attribute. Raises AttributeError if
|
||||
# attribute is not found.
|
||||
#
|
||||
# attribute_name: (str) The attribute's name.
|
||||
# """
|
||||
# attr_obj = get_attr_cache(self, attribute_name)
|
||||
# if attr_obj:
|
||||
# attr_obj.delete() # this will clear attr cache automatically
|
||||
# else:
|
||||
# try:
|
||||
# _GA(self, "_attribute_class").objects.filter(
|
||||
# db_obj=self, db_key__iexact=attribute_name)[0].delete()
|
||||
# except IndexError:
|
||||
# pass
|
||||
# raise AttributeError
|
||||
|
||||
def get_all_attributes(self):
|
||||
"""
|
||||
Returns all attributes defined on the object.
|
||||
"""
|
||||
return list(_GA(self,"_attribute_class").objects.filter(db_obj=self))
|
||||
return list(_GA(self, "db_attributes").all())
|
||||
|
||||
def attr(self, attribute_name=None, value=None, delete=False):
|
||||
"""
|
||||
|
|
@ -1195,12 +1194,12 @@ class TypedObject(SharedMemoryModel):
|
|||
db = property(__db_get, __db_set, __db_del)
|
||||
|
||||
#
|
||||
# NON-PERSISTENT storage methods
|
||||
# NON-attr_obj storage methods
|
||||
#
|
||||
|
||||
def nattr(self, attribute_name=None, value=None, delete=False):
|
||||
"""
|
||||
This is the equivalence of self.attr but for non-persistent
|
||||
This is the equivalence of self.attr but for non-attr_obj
|
||||
stores. Will not raise error but return None.
|
||||
"""
|
||||
if attribute_name == None:
|
||||
|
|
@ -1226,7 +1225,7 @@ class TypedObject(SharedMemoryModel):
|
|||
#@property
|
||||
def __ndb_get(self):
|
||||
"""
|
||||
A non-persistent store (ndb: NonDataBase). Everything stored
|
||||
A non-attr_obj store (ndb: NonDataBase). Everything stored
|
||||
to this is guaranteed to be cleared when a server is shutdown.
|
||||
Syntax is same as for the _get_db_holder() method and
|
||||
property, e.g. obj.ndb.attr = value etc.
|
||||
|
|
@ -1235,7 +1234,7 @@ class TypedObject(SharedMemoryModel):
|
|||
return self._ndb_holder
|
||||
except AttributeError:
|
||||
class NdbHolder(object):
|
||||
"Holder for storing non-persistent attributes."
|
||||
"Holder for storing non-attr_obj attributes."
|
||||
def get_all(self):
|
||||
return [val for val in self.__dict__.keys()
|
||||
if not val.startswith('_')]
|
||||
|
|
@ -1313,3 +1312,7 @@ class TypedObject(SharedMemoryModel):
|
|||
as a new Typeclass instance.
|
||||
"""
|
||||
self.__class__.flush_cached_instance(self)
|
||||
|
||||
|
||||
# connect to signal
|
||||
m2m_changed.connect(update_attr_cache, sender=TypedObject.db_attributes.through)
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ class TypeClass(object):
|
|||
log_trace("This is probably due to an unsafe reload.")
|
||||
return # ignore delete
|
||||
try:
|
||||
dbobj.del_attribute_raise(propname)
|
||||
dbobj.del_attribute(propname, raise_exception=True)
|
||||
except AttributeError:
|
||||
string = "Object: '%s' not found on %s(#%s), nor on its typeclass %s."
|
||||
raise AttributeError(string % (propname, dbobj,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue