First version with all caches seemingly working ok. Started to remove the on-model wrappers that are not handled by the idmapper metaclass.

This commit is contained in:
Griatch 2013-07-11 15:59:03 +02:00
parent f1ba0ca177
commit 9e10a41e18
10 changed files with 144 additions and 165 deletions

View file

@ -303,8 +303,6 @@ class Msg(SharedMemoryModel):
logger.log_errmsg("Lock_Storage (on %s) cannot be deleted. Use obj.lock.delete() instead." % self)
lock_storage = property(__lock_storage_get, __lock_storage_set, __lock_storage_del)
_db_model_name = "msg" # used by attributes to safely store objects
#
# Msg class methods
#

View file

@ -45,7 +45,7 @@ class HelpEntry(SharedMemoryModel):
# These database fields are all set using their corresponding properties,
# named same as the field, but withtout the db_* prefix.
# title of the help
# title of the help entry
db_key = models.CharField('help key', max_length=255, unique=True, help_text='key to search for')
# help category
db_help_category = models.CharField("help category", max_length=255, default="General",
@ -72,9 +72,6 @@ class HelpEntry(SharedMemoryModel):
verbose_name = "Help Entry"
verbose_name_plural = "Help Entries"
# used by Attributes to safely retrieve stored object
_db_model_name = "helpentry"
# Wrapper properties to easily set database fields. These are
# @property decorators that allows to access these fields using
# normal python operations (without having to remember to save()
@ -85,53 +82,53 @@ class HelpEntry(SharedMemoryModel):
# key property (wraps db_key)
#@property
def __key_get(self):
"Getter. Allows for value = self.key"
return self.db_key
#@key.setter
def __key_set(self, value):
"Setter. Allows for self.key = value"
self.db_key = value
self.save()
#@key.deleter
def __key_del(self):
"Deleter. Allows for del self.key. Deletes entry."
self.delete()
key = property(__key_get, __key_set, __key_del)
#def __key_get(self):
# "Getter. Allows for value = self.key"
# return self.db_key
##@key.setter
#def __key_set(self, value):
# "Setter. Allows for self.key = value"
# self.db_key = value
# self.save()
##@key.deleter
#def __key_del(self):
# "Deleter. Allows for del self.key. Deletes entry."
# self.delete()
#key = property(__key_get, __key_set, __key_del)
# help_category property (wraps db_help_category)
#@property
def __help_category_get(self):
"Getter. Allows for value = self.help_category"
return self.db_help_category
#@help_category.setter
def __help_category_set(self, value):
"Setter. Allows for self.help_category = value"
self.db_help_category = value
self.save()
#@help_category.deleter
def __help_category_del(self):
"Deleter. Allows for del self.help_category"
self.db_help_category = "General"
self.save()
help_category = property(__help_category_get, __help_category_set, __help_category_del)
## help_category property (wraps db_help_category)
##@property
#def __help_category_get(self):
# "Getter. Allows for value = self.help_category"
# return self.db_help_category
##@help_category.setter
#def __help_category_set(self, value):
# "Setter. Allows for self.help_category = value"
# self.db_help_category = value
# self.save()
##@help_category.deleter
#def __help_category_del(self):
# "Deleter. Allows for del self.help_category"
# self.db_help_category = "General"
# self.save()
#help_category = property(__help_category_get, __help_category_set, __help_category_del)
# entrytext property (wraps db_entrytext)
#@property
def __entrytext_get(self):
"Getter. Allows for value = self.entrytext"
return self.db_entrytext
#@entrytext.setter
def __entrytext_set(self, value):
"Setter. Allows for self.entrytext = value"
self.db_entrytext = value
self.save()
#@entrytext.deleter
def __entrytext_del(self):
"Deleter. Allows for del self.entrytext"
self.db_entrytext = ""
self.save()
entrytext = property(__entrytext_get, __entrytext_set, __entrytext_del)
## entrytext property (wraps db_entrytext)
##@property
#def __entrytext_get(self):
# "Getter. Allows for value = self.entrytext"
# return self.db_entrytext
##@entrytext.setter
#def __entrytext_set(self, value):
# "Setter. Allows for self.entrytext = value"
# self.db_entrytext = value
# self.save()
##@entrytext.deleter
#def __entrytext_del(self):
# "Deleter. Allows for del self.entrytext"
# self.db_entrytext = ""
# self.save()
#entrytext = property(__entrytext_get, __entrytext_set, __entrytext_del)
# permissions property
#@property
@ -153,20 +150,20 @@ class HelpEntry(SharedMemoryModel):
permissions = property(__permissions_get, __permissions_set, __permissions_del)
# lock_storage property (wraps db_lock_storage)
#@property
def __lock_storage_get(self):
"Getter. Allows for value = self.lock_storage"
return self.db_lock_storage
#@nick.setter
def __lock_storage_set(self, value):
"""Saves the lock_storagetodate. This is usually not called directly, but through self.lock()"""
self.db_lock_storage = value
self.save()
#@nick.deleter
def __lock_storage_del(self):
"Deleter is disabled. Use the lockhandler.delete (self.lock.delete) instead"""
logger.log_errmsg("Lock_Storage (on %s) cannot be deleted. Use obj.lock.delete() instead." % self)
lock_storage = property(__lock_storage_get, __lock_storage_set, __lock_storage_del)
##@property
#def __lock_storage_get(self):
# "Getter. Allows for value = self.lock_storage"
# return self.db_lock_storage
##@nick.setter
#def __lock_storage_set(self, value):
# """Saves the lock_storagetodate. This is usually not called directly, but through self.lock()"""
# self.db_lock_storage = value
# self.save()
##@nick.deleter
#def __lock_storage_del(self):
# "Deleter is disabled. Use the lockhandler.delete (self.lock.delete) instead"""
# logger.log_errmsg("Lock_Storage (on %s) cannot be deleted. Use obj.lock.delete() instead." % self)
#lock_storage = property(__lock_storage_get, __lock_storage_set, __lock_storage_del)
#

View file

@ -6,7 +6,7 @@
from django import forms
from django.conf import settings
from django.contrib import admin
from src.typeclases.models import Attribute
from src.typeclasses.models import Attribute
from src.objects.models import ObjectDB, ObjectNick, Alias
from src.utils.utils import mod_import

View file

@ -187,8 +187,11 @@ class ObjectDB(TypedObject):
# Database manager
objects = ObjectManager()
# Add the object-specific handlers
# caches for quick lookups of typeclass loading.
_typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
_default_typeclass_path = settings.BASE_OBJECT_TYPECLASS or "src.objects.objects.Object"
# Add the object-specific handlers
def __init__(self, *args, **kwargs):
"Parent must be initialized first."
TypedObject.__init__(self, *args, **kwargs)
@ -495,11 +498,6 @@ class ObjectDB(TypedObject):
# ObjectDB class access methods/properties
#
# this is required to properly handle attributes and typeclass loading.
_typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
#_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"
#@property
def __sessions_get(self):

View file

@ -137,11 +137,15 @@ class PlayerDB(TypedObject):
db_is_connected = models.BooleanField(default=False, verbose_name="is_connected", help_text="If player is connected to game or not")
# database storage of persistant cmdsets.
db_cmdset_storage = models.CharField('cmdset', max_length=255, null=True,
help_text="optional python path to a cmdset class. If creating a Character, this will default to settings.CMDSET_CHARACTER.")
help_text="optional python path to a cmdset class. If creating a Character, this will default to settings.CMDSET_CHARACTER.")
# Database manager
objects = manager.PlayerManager()
# caches for quick lookups
_typeclass_paths = settings.PLAYER_TYPECLASS_PATHS
_default_typeclass_path = settings.BASE_PLAYER_TYPECLASS or "src.players.player.Player"
class Meta:
app_label = 'players'
verbose_name = 'Player'
@ -229,11 +233,6 @@ class PlayerDB(TypedObject):
def __unicode__(self):
return u"%s(player#%s)" % (_GA(self, "name"), _GA(self, "dbid"))
# this is required to properly handle attributes and typeclass loading
_typeclass_paths = settings.PLAYER_TYPECLASS_PATHS
#_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"
# name property (wraps self.user.username)
#@property

View file

@ -96,6 +96,10 @@ class ScriptDB(TypedObject):
# Database manager
objects = ScriptManager()
# caches for quick lookups
_typeclass_paths = settings.SCRIPT_TYPECLASS_PATHS
_default_typeclass_path = settings.BASE_SCRIPT_TYPECLASS or "src.scripts.scripts.DoNothing"
class Meta:
"Define Django meta options"
verbose_name = "Script"
@ -233,11 +237,6 @@ class ScriptDB(TypedObject):
#
#
# this is required to properly handle attributes and typeclass loading
_typeclass_paths = settings.SCRIPT_TYPECLASS_PATHS
#_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"
def at_typeclass_error(self):
"""

View file

@ -90,7 +90,7 @@ def field_pre_save(sender, instance=None, update_fields=None, raw=False, **kwarg
"""
if raw:
return
print "field_pre_save:", instance, update_fields# if hasattr(instance, "db_key") else instance, update_fields
#print "field_pre_save:", instance, update_fields# if hasattr(instance, "db_key") else instance, update_fields
if update_fields:
# this is a list of strings at this point. We want field objects
update_fields = (_GA(_GA(instance, "_meta"), "get_field_by_name")(field)[0] for field in update_fields)
@ -166,7 +166,7 @@ def post_attr_update(sender, **kwargs):
obj = kwargs['instance']
model = kwargs['model']
action = kwargs['action']
print "update_attr_cache:", obj, model, action
#print "update_attr_cache:", obj, model, action
if kwargs['reverse']:
# the reverse relation changed (the Attribute itself was acted on)
pass

View file

@ -48,9 +48,6 @@ class ServerConfig(SharedMemoryModel):
objects = ServerConfigManager()
# used by Attributes eventually storing this safely
_db_model_name = "serverconfig"
# Wrapper properties to easily set database fields. These are
# @property decorators that allows to access these fields using
# normal python operations (without having to remember to save()

View file

@ -401,29 +401,29 @@ class TypedObject(SharedMemoryModel):
# TypedObject Database Model setup
#
#
# These databse fields are all set using their corresponding properties,
# named same as the field, but withtou the db_* prefix.
# These databse fields are all accessed and set using their corresponding properties,
# named same as the field, but without the db_* prefix (no separate save() call is needed)
# Main identifier of the object, for searching. Can also
# be referenced as 'name'.
# Main identifier of the object, for searching. Is accessed with self.key or self.name
db_key = models.CharField('key', max_length=255, db_index=True)
# This is the python path to the type class this object is tied to
# (the type class is what defines what kind of Object this is)
db_typeclass_path = models.CharField('typeclass', max_length=255, null=True, help_text="this defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass.")
# Creation date
# This is the python path to the type class this object is tied to the type class is what defines what kind of Object this is)
db_typeclass_path = models.CharField('typeclass', max_length=255, null=True,
help_text="this defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass.")
# Creation date. This is not changed once the object is created.
db_date_created = models.DateTimeField('creation date', editable=False, auto_now_add=True)
# Permissions (access these through the 'permissions' property)
db_permissions = models.CharField('permissions', max_length=255, blank=True, help_text="a comma-separated list of text strings checked by certain locks. They are often used for hierarchies, such as letting a Player have permission 'Wizards', 'Builders' etc. Character objects use 'Players' by default. Most other objects don't have any permissions.")
db_permissions = models.CharField('permissions', max_length=255, blank=True,
help_text="a comma-separated list of text strings checked by in-game locks. They are often used for hierarchies, such as letting a Player have permission 'Wizards', 'Builders' etc. Character objects use 'Players' by default. Most other objects don't have any permissions.")
# 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.")
# 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).')
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.")
# attribute store. This is accessed through the self.db handler.
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()
# object cache and flags
# quick on-object typeclass cache for speed
_cached_typeclass = None
# lock handler self.locks
@ -441,6 +441,7 @@ class TypedObject(SharedMemoryModel):
verbose_name = "Evennia Database Object"
ordering = ['-db_date_created', 'id', 'db_typeclass_path', 'db_key']
# wrapper
# Wrapper properties to easily set database fields. These are
# @property decorators that allows to access these fields using
# normal python operations (without having to remember to save()
@ -449,7 +450,6 @@ class TypedObject(SharedMemoryModel):
# value = self.attr and del self.attr respectively (where self
# is the object in question).
# key property (wraps db_key)
#@property
#def __key_get(self):
@ -466,53 +466,44 @@ class TypedObject(SharedMemoryModel):
# raise Exception("Cannot delete objectdb key!")
#key = property(__key_get, __key_set, __key_del)
# name property (wraps db_key too - alias to self.key)
#@property
def __name_get(self):
"Getter. Allows for value = self.name"
return self.key
#@name.sette
def __name_set(self, value):
"Setter. Allows for self.name = value"
self.key = value
#@name.deleter
def __name_del(self):
"Deleter. Allows for del self.name"
raise Exception("Cannot delete name!")
# name property (alias to self.key)
def __name_get(self): return self.key
def __name_set(self, value): self.key = value
def __name_del(self): raise Exception("Cannot delete name")
name = property(__name_get, __name_set, __name_del)
# typeclass_path property - we don't cache this.
# typeclass_path property - we manage this separately.
#@property
def __typeclass_path_get(self):
"Getter. Allows for value = self.typeclass_path"
return _GA(self, "db_typeclass_path")#get_field_cache(self, "typeclass_path")
#@typeclass_path.setter
def __typeclass_path_set(self, value):
"Setter. Allows for self.typeclass_path = value"
_SA(self, "db_typeclass_path", value)
update_fields = ["db_typeclass_path"] if _GA(self, "_get_pk_val")(_GA(self, "_meta")) is not None else None
_GA(self, "save")(update_fields=update_fields)
#@typeclass_path.deleter
def __typeclass_path_del(self):
"Deleter. Allows for del self.typeclass_path"
self.db_typeclass_path = ""
_GA(self, "save")(update_fields=["db_typeclass_path"])
typeclass_path = property(__typeclass_path_get, __typeclass_path_set, __typeclass_path_del)
#def __typeclass_path_get(self):
# "Getter. Allows for value = self.typeclass_path"
# return _GA(self, "db_typeclass_path")
##@typeclass_path.setter
#def __typeclass_path_set(self, value):
# "Setter. Allows for self.typeclass_path = value"
# _SA(self, "db_typeclass_path", value)
# update_fields = ["db_typeclass_path"] if _GA(self, "_get_pk_val")(_GA(self, "_meta")) is not None else None
# _GA(self, "save")(update_fields=update_fields)
##@typeclass_path.deleter
#def __typeclass_path_del(self):
# "Deleter. Allows for del self.typeclass_path"
# self.db_typeclass_path = ""
# _GA(self, "save")(update_fields=["db_typeclass_path"])
#typeclass_path = property(__typeclass_path_get, __typeclass_path_set, __typeclass_path_del)
# date_created property
#@property
def __date_created_get(self):
"Getter. Allows for value = self.date_created"
return get_field_cache(self, "date_created")
#@date_created.setter
def __date_created_set(self, value):
"Setter. Allows for self.date_created = value"
raise Exception("Cannot change date_created!")
#@date_created.deleter
def __date_created_del(self):
"Deleter. Allows for del self.date_created"
raise Exception("Cannot delete date_created!")
date_created = property(__date_created_get, __date_created_set, __date_created_del)
#def __date_created_get(self):
# "Getter. Allows for value = self.date_created"
# return get_field_cache(self, "date_created")
##@date_created.setter
#def __date_created_set(self, value):
# "Setter. Allows for self.date_created = value"
# raise Exception("Cannot change date_created!")
##@date_created.deleter
#def __date_created_del(self):
# "Deleter. Allows for del self.date_created"
# raise Exception("Cannot delete date_created!")
#date_created = property(__date_created_get, __date_created_set, __date_created_del)
# permissions property
#@property
@ -537,18 +528,18 @@ class TypedObject(SharedMemoryModel):
# lock_storage property (wraps db_lock_storage)
#@property
def __lock_storage_get(self):
"Getter. Allows for value = self.lock_storage"
return get_field_cache(self, "lock_storage")
#@lock_storage.setter
def __lock_storage_set(self, value):
"""Saves the lock_storagetodate. This is usually not called directly, but through self.lock()"""
set_field_cache(self, "lock_storage", value)
#@lock_storage.deleter
def __lock_storage_del(self):
"Deleter is disabled. Use the lockhandler.delete (self.lock.delete) instead"""
logger.log_errmsg("Lock_Storage (on %s) cannot be deleted. Use obj.lock.delete() instead." % self)
lock_storage = property(__lock_storage_get, __lock_storage_set, __lock_storage_del)
#def __lock_storage_get(self):
# "Getter. Allows for value = self.lock_storage"
# return get_field_cache(self, "lock_storage")
##@lock_storage.setter
#def __lock_storage_set(self, value):
# """Saves the lock_storage. This is usually not called directly, but through self.lock()"""
# set_field_cache(self, "lock_storage", value)
##@lock_storage.deleter
#def __lock_storage_del(self):
# "Deleter is disabled. Use the lockhandler.delete (self.lock.delete) instead"""
# logger.log_errmsg("Lock_Storage (on %s) cannot be deleted. Use obj.lock.delete() instead." % self)
#lock_storage = property(__lock_storage_get, __lock_storage_set, __lock_storage_del)
@ -560,8 +551,6 @@ class TypedObject(SharedMemoryModel):
# these are identifiers for fast Attribute access and caching
_typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
_attribute_class = Attribute # replaced by relevant attribute class for child
_db_model_name = "typeclass" # used by attributes to safely store objects
def __eq__(self, other):
return other and hasattr(other, 'dbid') and self.dbid == other.dbid

View file

@ -87,18 +87,18 @@ class SharedMemoryModelBase(ModelBase):
"Helper method to create property wrappers with unique names (must be in separate call)"
def _get(cls, fname):
"Wrapper for getting database field"
#print "_get wrapper:", fname, value, type(value)
value = _GA(cls, fieldname)
if isinstance(value, (basestring, int, float, bool)):
if type(value) in (basestring, int, float, bool):
return value
elif hasattr(value, "typeclass"):
return _GA(value, "typeclass")
return value
def _set(cls, fname, value):
"Wrapper for setting database field"
if hasattr(value, "dbobj"):
value = _GA(value, "dbobj")
else:
elif fname.isdigit() or fname.startswith("#"):
# we also allow setting using dbrefs, if so we try to load the matching object.
# (we assume the object is of the same type as the class holding the field, if
# not a custom handler must be used for that field)
@ -107,25 +107,27 @@ class SharedMemoryModelBase(ModelBase):
try:
value = cls._default_manager.get(id=dbid)
except ObjectDoesNotExist:
err = "Could not set %s. Tried to treat value '%s' as a dbref, but no matching object with that id was found."
err = err % (fname, value)
raise ObjectDoesNotExist(err)
# maybe it is just a name
pass
#print "_set wrapper:", fname, value, type(value), cls._get_pk_val(cls._meta)
_SA(cls, fname, value)
# only use explicit update_fields in save if we actually have a
# primary key assigned already (won't be when first creating object)
update_fields = [fname] if _GA(cls, "_get_pk_val")(_GA(cls, "_meta")) is not None else None
_GA(cls, "save")(update_fields=update_fields)
def _del(cls, fname):
"Wrapper for clearing database field - sets it to None"
_SA(cls, fname, None)
update_fields = [fname] if _GA(cls, "_get_pk_val")(_GA(cls, "_meta")) is not None else None
_GA(cls, "save")(update_fields=update_fields)
# create class wrappers
fget = lambda cls: _get(cls, fieldname)
fset = lambda cls, val: _set(cls, fieldname, val)
fdel = lambda cls: _del(cls, fieldname)
doc = "Wraps setting, saving and deleting the %s field." % fieldname
type(cls).__setattr__(cls, wrappername, property(fget, fset, fdel, doc))
# exclude some models that should not auto-create wrapper fields