OBS- need to run migrations! Refactored attributes to use a slightly different internal storage format for faster access. Also set up caching of all attribute data, so subsequent reads of an attribute will not hit the database anymore, and writes will re-cache.

This commit is contained in:
Griatch 2012-02-14 23:40:16 +01:00
parent 8b5f3628ab
commit a32aebaa0e
12 changed files with 560 additions and 152 deletions

View file

@ -224,8 +224,8 @@ start
@create/drop The sea (in the distance);sea;ocean @create/drop The sea (in the distance);sea;ocean
# #
@desc sea = @desc sea =
The grey sea stretches as far as the eye can se to the east, and far below you its waves crash The grey sea stretches as far as the eye can see to the east. Far below you its waves crash
against the foot of the cliff. The vast inland moors meets the ocean along a high and uninviting against the foot of the cliff. The vast inland moor meets the ocean along a high and uninviting
coastline of ragged vertical stone. coastline of ragged vertical stone.
Once this part of the world might have been beautiful, but now the eternal winds and storms have Once this part of the world might have been beautiful, but now the eternal winds and storms have
@ -287,16 +287,15 @@ north
: tutorial_world.rooms.TutorialRoom : tutorial_world.rooms.TutorialRoom
= enter;in,leave;out = enter;in,leave;out
# #
@desc The Evennia Inn consist mainly of one large room filled with tables. The bardisk extends @desc The Evennia Inn consists of one large room filled with tables. The bardisk extends
along the east wall, where multiple barrels and bottles line the shelves. The barkeep seems busy along the east wall, where multiple barrels and bottles line the shelves. The barkeep seems busy
handing out ale and chatting with the patrons, which are a rowdy and cheerful lot, keeping the sound handing out ale and chatting with the patrons, which are a rowdy and cheerful lot, keeping the sound
level only just below thunderous. level only just below thunderous. This is a rare spot of warmth and mirth on this dread moor.
Soon you have a beer in hand and is chatting with the locals. Your eye fall on a {wbarrel{n in a corner with a few Soon you have a beer in hand and is chatting with the locals. Your eye fall on a {wbarrel{n in a corner with a few
old rusty weapons sticking out. There is a sign next to it: {wFree to take{n. old rusty weapons sticking out. There is a sign next to it: {wFree to take{n. A patron tells you cheerfully that
it's the leftovers from those foolish adventurers that challenged the old ruin before you ...
A patron tells you cheerfully that it's the leftovers from those foolish adventurers that challenged the old ruin before you ...
# #
@set here/tutorial_info = @set here/tutorial_info =
Nothing special about this room, only a bonus place to go for chatting Nothing special about this room, only a bonus place to go for chatting

View file

@ -319,6 +319,7 @@ class Msg(SharedMemoryModel):
logger.log_errmsg("Lock_Storage (on %s) cannot be deleted. Use obj.lock.delete() instead." % self) 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) 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 # Msg class methods
@ -513,6 +514,8 @@ class Channel(SharedMemoryModel):
logger.log_errmsg("Lock_Storage (on %s) cannot be deleted. Use obj.lock.delete() instead." % self) 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) lock_storage = property(lock_storage_get, lock_storage_set, lock_storage_del)
db_model_name = "channel" # used by attributes to safely store objects
class Meta: class Meta:
"Define Django meta options" "Define Django meta options"
verbose_name = "Channel" verbose_name = "Channel"

View file

@ -0,0 +1,112 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models
try:
import cPickle as pickle
except ImportError:
import pickle
from src.utils.utils import to_str, to_unicode
class Migration(DataMigration):
def forwards(self, orm):
"Write your forwards methods here."
for attr in orm.ObjAttribute.objects.all():
attr.value = pickle.loads(to_str(attr.db_value))
def backwards(self, orm):
"Write your backwards methods here."
raise RuntimeError
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'objects.alias': {
'Meta': {'object_name': 'Alias'},
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'objects.objattribute': {
'Meta': {'object_name': 'ObjAttribute'},
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}),
'db_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'objects.objectdb': {
'Meta': {'object_name': 'ObjectDB'},
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destinations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_location': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}),
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'objects.objectnick': {
'Meta': {'unique_together': "(('db_nick', 'db_type', 'db_obj'),)", 'object_name': 'ObjectNick'},
'db_nick': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}),
'db_real': ('django.db.models.fields.TextField', [], {}),
'db_type': ('django.db.models.fields.CharField', [], {'default': "'inputline'", 'max_length': '16', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'players.playerdb': {
'Meta': {'object_name': 'PlayerDB'},
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']", 'null': 'True', 'blank': 'True'}),
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
}
}
complete_apps = ['objects']

View file

@ -425,6 +425,7 @@ class ObjectDB(TypedObject):
#attribute_model_name = "ObjAttribute" #attribute_model_name = "ObjAttribute"
typeclass_paths = settings.OBJECT_TYPECLASS_PATHS typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
attribute_class = ObjAttribute attribute_class = ObjAttribute
db_model_name = "objectdb" # used by attributes to safely store objects
# this is used by all typedobjects as a fallback # this is used by all typedobjects as a fallback
try: try:

View file

@ -0,0 +1,106 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models
try:
import cPickle as pickle
except ImportError:
import pickle
from src.utils.utils import to_str, to_unicode
class Migration(DataMigration):
def forwards(self, orm):
"Write your forwards methods here."
for attr in orb.PlayerAttribute.objects.all():
attr.value = pickle.loads(to_str(attr.db_value))
def backwards(self, orm):
"Write your backwards methods here."
raise RuntimeError
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'objects.objectdb': {
'Meta': {'object_name': 'ObjectDB'},
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destinations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_location': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}),
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'players.playerattribute': {
'Meta': {'object_name': 'PlayerAttribute'},
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']"}),
'db_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'players.playerdb': {
'Meta': {'object_name': 'PlayerDB'},
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']", 'null': 'True', 'blank': 'True'}),
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
},
'players.playernick': {
'Meta': {'unique_together': "(('db_nick', 'db_type', 'db_obj'),)", 'object_name': 'PlayerNick'},
'db_nick': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']"}),
'db_real': ('django.db.models.fields.TextField', [], {}),
'db_type': ('django.db.models.fields.CharField', [], {'default': "'inputline'", 'max_length': '16', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
}
}
complete_apps = ['players']

View file

@ -269,6 +269,7 @@ class PlayerDB(TypedObject):
#attribute_model_name = "PlayerAttribute" #attribute_model_name = "PlayerAttribute"
typeclass_paths = settings.PLAYER_TYPECLASS_PATHS typeclass_paths = settings.PLAYER_TYPECLASS_PATHS
attribute_class = PlayerAttribute attribute_class = PlayerAttribute
db_model_name = "playerdb" # used by attributes to safely store objects
# name property (wraps self.user.username) # name property (wraps self.user.username)
#@property #@property

View file

@ -0,0 +1,114 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models
try:
import cPickle as pickle
except ImportError:
import pickle
from src.utils.utils import to_str, to_unicode
class Migration(DataMigration):
def forwards(self, orm):
"Write your forwards methods here."
for attr in orm.ScriptAttribute.objects.all():
attr.value = pickle.loads(to_str(attr.db_value))
def backwards(self, orm):
"Write your backwards methods here."
raise RuntimeError
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'objects.objectdb': {
'Meta': {'object_name': 'ObjectDB'},
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destinations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_location': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}),
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'players.playerdb': {
'Meta': {'object_name': 'PlayerDB'},
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']", 'null': 'True', 'blank': 'True'}),
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
},
'scripts.scriptattribute': {
'Meta': {'object_name': 'ScriptAttribute'},
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['scripts.ScriptDB']"}),
'db_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'scripts.scriptdb': {
'Meta': {'object_name': 'ScriptDB'},
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'db_desc': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'db_interval': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'db_is_active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']", 'null': 'True', 'blank': 'True'}),
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'db_persistent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'db_repeats': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'db_start_delay': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
}
}
complete_apps = ['scripts']

View file

@ -249,6 +249,7 @@ class ScriptDB(TypedObject):
#attribute_model_name = "ScriptAttribute" #attribute_model_name = "ScriptAttribute"
typeclass_paths = settings.SCRIPT_TYPECLASS_PATHS typeclass_paths = settings.SCRIPT_TYPECLASS_PATHS
attribute_class = ScriptAttribute attribute_class = ScriptAttribute
db_model_name = "scriptdb" # used by attributes to safely store objects
# this is used by all typedobjects as a fallback # this is used by all typedobjects as a fallback
try: try:

View file

@ -7,7 +7,11 @@ import and inherit from these classes.
Attributes are database objects stored on other objects. The implementing Attributes are database objects stored on other objects. The implementing
class needs to supply a ForeignKey field attr_object pointing to the kind class needs to supply a ForeignKey field attr_object pointing to the kind
of object being mapped. of object being mapped. Attributes storing iterables actually store special
types of iterables named PackedList/PackedDict respectively. These make
sure to save changes to them to database - this is criticial in order to
allow for obj.db.mylist[2] = data. Also, all dbobjects are saved as
dbrefs but are also aggressively cached.
TypedObjects are objects 'decorated' with a typeclass - that is, the typeclass TypedObjects are objects 'decorated' with a typeclass - that is, the typeclass
(which is a normal Python class implementing some special tricks with its (which is a normal Python class implementing some special tricks with its
@ -37,7 +41,7 @@ from src.server.models import ServerConfig
from src.typeclasses import managers from src.typeclasses import managers
from src.locks.lockhandler import LockHandler from src.locks.lockhandler import LockHandler
from src.utils import logger, utils from src.utils import logger, utils
from src.utils.utils import is_iter, has_parent from src.utils.utils import is_iter, has_parent, to_unicode, to_str
PERMISSION_HIERARCHY = [p.lower() for p in settings.PERMISSION_HIERARCHY] PERMISSION_HIERARCHY = [p.lower() for p in settings.PERMISSION_HIERARCHY]
@ -45,17 +49,20 @@ CTYPEGET = ContentType.objects.get
GA = object.__getattribute__ GA = object.__getattribute__
SA = object.__setattr__ SA = object.__setattr__
DA = object.__delattr__ DA = object.__delattr__
PLOADS = pickle.loads
PDUMPS = pickle.dumps
# used by Attribute to efficiently identify stored object types.
# Note that these have to be updated if directory structure changes. # # used by Attribute to efficiently identify stored object types.
PARENTS = { # # Note that these have to be updated if directory structure changes.
"typeclass":"src.typeclasses.typeclass.TypeClass", # PARENTS = {
"objectdb":"src.objects.models.ObjectDB", # "typeclass":"src.typeclasses.typeclass.TypeClass",
"playerdb":"src.players.models.PlayerDB", # "objectdb":"src.objects.models.ObjectDB",
"scriptdb":"src.scripts.models.ScriptDB", # "playerdb":"src.players.models.PlayerDB",
"msg":"src.comms.models.Msg", # "scriptdb":"src.scripts.models.ScriptDB",
"channel":"src.comms.models.Channel", # "msg":"src.comms.models.Msg",
"helpentry":"src.help.models.HelpEntry"} # "channel":"src.comms.models.Channel",
# "helpentry":"src.help.models.HelpEntry"}
#------------------------------------------------------------ #------------------------------------------------------------
# #
@ -63,15 +70,20 @@ PARENTS = {
# #
#------------------------------------------------------------ #------------------------------------------------------------
class PackedDBobject(object): class PackedDBobject(dict):
""" """
Attribute helper class. Attribute helper class.
A container for storing and easily identifying database objects in A container for storing and easily identifying database objects in
the database (which doesn't suppport storing db_objects directly). the database (which doesn't suppport storing db_objects directly).
""" """
def __init__(self, ID, db_model): def __init__(self, ID, db_model, db_key):
self.id = ID self['id'] = ID
self.db_model = db_model self['db_model'] = db_model
self['key'] = db_key
def __str__(self):
return "%s(#%s)" % (self['key'], self['id'])
def __unicode__(self):
return u"%s(#%s)" % (self['key'], self['id'])
class PackedDict(dict): class PackedDict(dict):
""" """
@ -90,34 +102,29 @@ class PackedDict(dict):
""" """
self.db_obj = db_obj self.db_obj = db_obj
self.db_store = False
super(PackedDict, self).__init__(*args, **kwargs) super(PackedDict, self).__init__(*args, **kwargs)
def db_save(self): def __str__(self):
"save data to Attribute, if db_store is active" return "{%s}" % ", ".join("%s:%s" % (key, str(val)) for key, val in self.items())
if self.db_store:
self.db_obj.value = self
def __setitem__(self, *args, **kwargs): def __setitem__(self, *args, **kwargs):
"Custom setitem that stores changed dict to database." "assign item to this dict"
super(PackedDict, self).__setitem__(*args, **kwargs) super(PackedDict, self).__setitem__(*args, **kwargs)
self.db_save() self.db_obj.value = self
def __getitem__(self, *args, **kwargs):
return super(PackedDict, self).__getitem__(*args, **kwargs)
def clear(self, *args, **kwargs): def clear(self, *args, **kwargs):
"Custom clear" "Custom clear"
super(PackedDict, self).clear(*args, **kwargs) super(PackedDict, self).clear(*args, **kwargs)
self.db_save() self.db_obj.value = self
def pop(self, *args, **kwargs): def pop(self, *args, **kwargs):
"Custom pop" "Custom pop"
super(PackedDict, self).pop(*args, **kwargs) super(PackedDict, self).pop(*args, **kwargs)
self.db_save() self.db_obj.value = self
def popitem(self, *args, **kwargs): def popitem(self, *args, **kwargs):
"Custom popitem" "Custom popitem"
super(PackedDict, self).popitem(*args, **kwargs) super(PackedDict, self).popitem(*args, **kwargs)
self.db_save() self.db_obj.value = self
def update(self, *args, **kwargs): def update(self, *args, **kwargs):
"Custom update" "Custom update"
super(PackedDict, self).update(*args, **kwargs) super(PackedDict, self).update(*args, **kwargs)
self.db_save() self.db_obj.value = self
class PackedList(list): class PackedList(list):
""" """
@ -128,54 +135,45 @@ class PackedList(list):
""" """
def __init__(self, db_obj, *args, **kwargs): def __init__(self, db_obj, *args, **kwargs):
""" """
Sets up the packing list. The db_store variable Sets up the packing list.
is set by Attribute.validate_data() when returned in
order to allow custom updates to the list.
db_obj - the Attribute object storing this dict. db_obj - the Attribute object storing this dict.
""" """
self.db_obj = db_obj self.db_obj = db_obj
self.db_store = False
super(PackedList, self).__init__(*args, **kwargs) super(PackedList, self).__init__(*args, **kwargs)
def db_save(self): def __str__(self):
"save data to Attribute, if db_store is active" return "[%s]" % ", ".join(str(val) for val in self)
if self.db_store:
self.db_obj.value = self
def __setitem__(self, *args, **kwargs): def __setitem__(self, *args, **kwargs):
"Custom setitem that stores changed dict to database." "Custom setitem that stores changed list to database."
super(PackedList, self).__setitem__(*args, **kwargs) super(PackedList, self).__setitem__(*args, **kwargs)
self.db_save() self.db_obj.value = self
def append(self, *args, **kwargs): def append(self, *args, **kwargs):
"Custom append" "Custom append"
super(PackedList, self).append(*args, **kwargs) super(PackedList, self).append(*args, **kwargs)
self.db_save() self.db_obj.value = self
def extend(self, *args, **kwargs): def extend(self, *args, **kwargs):
"Custom extend" "Custom extend"
super(PackedList, self).extend(*args, **kwargs) super(PackedList, self).extend(*args, **kwargs)
self.db_save() self.db_obj.value = self
def insert(self, *args, **kwargs): def insert(self, *args, **kwargs):
"Custom insert" "Custom insert"
super(PackedList, self).insert(*args, **kwargs) super(PackedList, self).insert(*args, **kwargs)
self.db_save() self.db_obj.value = self
def remove(self, *args, **kwargs): def remove(self, *args, **kwargs):
"Custom remove" "Custom remove"
super(PackedList, self).remove(*args, **kwargs) super(PackedList, self).remove(*args, **kwargs)
self.db_save() self.db_obj.value = self
def pop(self, *args, **kwargs): def pop(self, *args, **kwargs):
"Custom pop" "Custom pop"
super(PackedList, self).pop(*args, **kwargs) super(PackedList, self).pop(*args, **kwargs)
self.db_save() self.db_obj.value = self
def reverse(self, *args, **kwargs): def reverse(self, *args, **kwargs):
"Custom reverse" "Custom reverse"
super(PackedList, self).reverse(*args, **kwargs) super(PackedList, self).reverse(*args, **kwargs)
self.db_save() self.db_obj.value = self
def sort(self, *args, **kwargs): def sort(self, *args, **kwargs):
"Custom sort" "Custom sort"
super(PackedList, self).sort(*args, **kwargs) super(PackedList, self).sort(*args, **kwargs)
self.db_save() self.db_obj.value = self
class Attribute(SharedMemoryModel): class Attribute(SharedMemoryModel):
""" """
@ -195,7 +193,15 @@ class Attribute(SharedMemoryModel):
obj - which object the attribute is defined on obj - which object the attribute is defined on
date_created - when the attribute was created date_created - when the attribute was created
value - the data stored in the attribute value - the data stored in the attribute
what is actually stored in the field is a dict
{type : nodb|dbobj|dbiter,
data : <data>}
where type is info for the loader, telling it if holds a single
dbobject (dbobj), have to do a full scan for dbrefs (dbiter) or
if it is a normal Python structure without any dbobjs inside it
and can thus return it without further action (nodb).
""" """
# #
@ -214,7 +220,7 @@ class Attribute(SharedMemoryModel):
# by each child class to this abstact class) # by each child class to this abstact class)
db_obj = None # models.ForeignKey("RefencedObject") db_obj = None # models.ForeignKey("RefencedObject")
# time stamp # time stamp
db_date_created = models.DateTimeField('date_created',editable=False, auto_now_add=True) db_date_created = models.DateTimeField('date_created', editable=False, auto_now_add=True)
# Database manager # Database manager
objects = managers.AttributeManager() objects = managers.AttributeManager()
@ -224,7 +230,8 @@ class Attribute(SharedMemoryModel):
"Initializes the parent first -important!" "Initializes the parent first -important!"
SharedMemoryModel.__init__(self, *args, **kwargs) SharedMemoryModel.__init__(self, *args, **kwargs)
self.locks = LockHandler(self) self.locks = LockHandler(self)
self.value_cache = None self.no_cache = True
self.cached_value = None
class Meta: class Meta:
"Define Django meta options" "Define Django meta options"
@ -291,17 +298,30 @@ class Attribute(SharedMemoryModel):
#@property #@property
def value_get(self): def value_get(self):
""" """
Getter. Allows for value = self.value. Getter. Allows for value = self.value. Reads from cache if possible.
""" """
if self.no_cache:
# re-create data from database and cache it
try: try:
return utils.to_unicode(self.validate_data(pickle.loads(utils.to_str(self.db_value)))) value = self.from_attr(PLOADS(to_str(self.db_value)))
except pickle.UnpicklingError: except pickle.UnpicklingError:
return self.db_value value = self.db_value
self.cached_value = value
self.no_cache = False
return value
else:
# normally the memory cache holds the latest data so no db access is needed.
return self.cached_value
#@value.setter #@value.setter
def value_set(self, new_value): def value_set(self, new_value):
"Setter. Allows for self.value = value" """
self.db_value = utils.to_unicode(pickle.dumps(utils.to_str(self.validate_data(new_value, setmode=True)))) Setter. Allows for self.value = value. We make sure to cache everything.
#self.db_value = utils.to_unicode(pickle.dumps(utils.to_str(self.validate_data(new_value)))) """
new_value = self.to_attr(new_value)
self.cached_value = self.from_attr(new_value)
self.no_cache = False
self.db_value = to_unicode(PDUMPS(to_str(new_value)))
self.save() self.save()
#@value.deleter #@value.deleter
def value_del(self): def value_del(self):
@ -338,8 +358,12 @@ class Attribute(SharedMemoryModel):
def __unicode__(self): def __unicode__(self):
return u"%s(%s)" % (self.key, self.id) return u"%s(%s)" % (self.key, self.id)
def validate_data(self, item, niter=0, setmode=False): # operators on various data
def to_attr(self, data):
""" """
Convert data to proper attr data format before saving
We have to make sure to not store database objects raw, since We have to make sure to not store database objects raw, since
this will crash the system. Instead we must store their IDs this will crash the system. Instead we must store their IDs
and make sure to convert back when the attribute is read back and make sure to convert back when the attribute is read back
@ -351,75 +375,120 @@ class Attribute(SharedMemoryModel):
(and any nested combination of them) this way, all other (and any nested combination of them) this way, all other
iterables are stored and returned as lists. iterables are stored and returned as lists.
setmode - used for iterables; when first assigning, this settings makes data storage format:
sure that it's a normal built-in python object that is stored in the db, (simple|dbobj|iter, <data>)
not the custom one. This will then just be updated later, assuring the where
pickling works as it should. simple - a single non-db object, like a string or number
niter - iteration counter for recursive iterable search. dbobj - a single dbobj
iter - any iterable object - will be looped over recursively
to convert dbobj->id.
""" """
if isinstance(item, basestring):
# a string is unmodified def iter_db2id(item):
ret = item """
elif type(item) == PackedDBobject: recursively looping through stored iterables, replacing objects with ids.
# unpack a previously packed db_object (Python only builds nested functions once, so there is no overhead for nesting)
"""
dtype = type(item)
if dtype in (basestring, int, float): # check the most common types first, for speed
return item
elif hasattr(item, "id") and hasattr(item, "db_model_name") and hasattr(item, "db_key"):
db_model_name = item.db_model_name
if db_model_name == "typeclass":
db_model_name = GA(item.dbobj, "db_model_name")
return PackedDBobject(item.id, db_model_name, item.db_key)
elif dtype == tuple:
return tuple(iter_db2id(val) for val in item)
elif dtype in (dict, PackedDict):
return dict((key, iter_db2id(val)) for key, val in item.items())
elif hasattr(item, '__iter__'):
return list(iter_db2id(val) for val in item)
else:
return item
dtype = type(data)
if dtype in (basestring, int, float):
return ("simple",data)
elif hasattr(data, "id") and hasattr(data, "db_model_name") and hasattr(data, 'db_key'):
# all django models (objectdb,scriptdb,playerdb,channel,msg,typeclass)
# have the protected property db_model_name hardcoded on themselves for speed.
db_model_name = data.db_model_name
if db_model_name == "typeclass":
# typeclass cannot help us, we want the actual child object model name
db_model_name = GA(data.dbobj, "db_model_name")
return ("dbobj", PackedDBobject(data.id, db_model_name, data.db_key))
elif hasattr(data, "__iter__"):
return ("iter", iter_db2id(data))
else:
return ("simple", data)
def from_attr(self, datatuple):
"""
Retrieve data from a previously stored attribute. This
is always a dict with keys type and data.
datatuple comes from the database storage and has
the following format:
(simple|dbobj|iter, <data>)
where
simple - a single non-db object, like a string. is returned as-is.
dbobj - a single dbobj-id. This id is retrieved back from the database.
iter - an iterable. This is traversed iteratively, converting all found
dbobj-ids back to objects. Also, all lists and dictionaries are
returned as their PackedList/PackedDict counterparts in order to
allow in-place assignment such as obj.db.mylist[3] = val. Mylist
is then a PackedList that saves the data on the fly.
"""
# nested functions
def id2db(data):
"""
Convert db-stored dbref back to object
"""
mclass = CTYPEGET(model=data["db_model"]).model_class()
try: try:
#print "unpack:", item.id, item.db_model return mclass.objects.dbref_search(data['id'])
mclass = CTYPEGET(model=item.db_model).model_class()
try:
ret = mclass.objects.dbref_search(item.id)
except AttributeError: except AttributeError:
ret = mclass.objects.get(id=item.id) try:
except Exception: return mclass.objects.get(id=data['id'])
logger.log_trace("Attribute error: %s, %s" % (item.db_model, item.id)) #TODO: Remove when stable? except mclass.DoesNotExist: # could happen if object was deleted in the interim.
ret = None return None
elif type(item) == tuple:
# handle tuples def iter_id2db(item):
ret = [] """
for it in item: Recursively looping through stored iterables, replacing ids with actual objects.
ret.append(self.validate_data(it)) We return PackedDict and PackedLists instead of normal lists; this is needed in order for
ret = tuple(ret) the user to do dynamic saving of nested in-place, such as obj.db.attrlist[2]=3. What is
elif type(item) == dict or type(item) == PackedDict: stored in the database are however always normal python primitives.
# handle dictionaries """
if setmode: dtype = type(item)
ret = {} if dtype in (basestring, int, float): # check the most common types first, for speed
for key, it in item.items(): return item
ret[key] = self.validate_data(it, niter=niter+1, setmode=True) elif dtype == PackedDBobject:
return id2db(item)
elif dtype == tuple:
return tuple([iter_id2db(val) for val in item])
elif dtype in (dict, PackedDict):
return PackedDict(self, dict(zip([key for key in item.keys()],
[iter_id2db(val) for val in item.values()])))
elif hasattr(item, '__iter__'):
return PackedList(self, list(iter_id2db(val) for val in item))
else: else:
ret = PackedDict(self) return item
for key, it in item.items():
ret[key] = self.validate_data(it, niter=niter+1) typ, data = datatuple
if niter == 0:
ret.db_store = True if typ == 'simple':
elif is_iter(item): # single non-db objects
# Note: ALL other iterables except dicts and tuples are stored&retrieved as lists! return data
if setmode: elif typ == 'dbobj':
ret = [] # a single stored dbobj
for it in item: return id2db(data)
ret.append(self.validate_data(it, niter=niter+1,setmode=True)) elif typ == 'iter':
else: # all types of iterables
ret = PackedList(self) return iter_id2db(data)
for it in item:
ret.append(self.validate_data(it, niter=niter+1))
if niter == 0:
ret.db_store = True
elif has_parent('django.db.models.base.Model', item) or has_parent(PARENTS['typeclass'], item):
# db models must be stored as dbrefs
db_model = [parent for parent, path in PARENTS.items() if has_parent(path, item)]
#print "db_model", db_model
if db_model and db_model[0] == 'typeclass':
# the typeclass alone can't help us, we have to know the db object.
db_model = [parent for parent, path in PARENTS.items()
if has_parent(path, item.dbobj)]
#print "db_model2", db_model
if db_model:
# store the object in an easily identifiable container
ret = PackedDBobject(str(item.id), db_model[0])
else:
# not a valid object - some third-party class or primitive?
ret = item
else:
ret = item
return ret
def access(self, accessing_obj, access_type='read', default=False): def access(self, accessing_obj, access_type='read', default=False):
""" """
@ -707,6 +776,7 @@ class TypedObject(SharedMemoryModel):
#attribute_model_name = "Attribute" #attribute_model_name = "Attribute"
typeclass_paths = settings.OBJECT_TYPECLASS_PATHS typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
attribute_class = Attribute # replaced by relevant attribute class for child 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): def __eq__(self, other):
return other and hasattr(other, 'id') and self.id == other.id return other and hasattr(other, 'id') and self.id == other.id
@ -870,7 +940,7 @@ class TypedObject(SharedMemoryModel):
# no mudinfo channel is found. Log instead. # no mudinfo channel is found. Log instead.
cmessage = "\n".join(["[NO MUDINFO CHANNEL]: %s" % line for line in message.split('\n')]) cmessage = "\n".join(["[NO MUDINFO CHANNEL]: %s" % line for line in message.split('\n')])
logger.log_errmsg(cmessage) logger.log_errmsg(cmessage)
except Exception, e: except Exception:
if ServerConfig.objects.conf("server_starting_mode"): if ServerConfig.objects.conf("server_starting_mode"):
print cmessage print cmessage
else: else:
@ -1054,13 +1124,12 @@ class TypedObject(SharedMemoryModel):
attrib_obj = None attrib_obj = None
attrclass = self.attribute_class attrclass = self.attribute_class
try: try:
# use old attribute
attrib_obj = attrclass.objects.filter( attrib_obj = attrclass.objects.filter(
db_obj=self).filter(db_key__iexact=attribute_name)[0] db_obj=self).filter(db_key__iexact=attribute_name)[0]
except IndexError: except IndexError:
# no match; create new attribute # no match; create new attribute
new_attrib = attrclass(db_key=attribute_name, db_obj=self) attrib_obj = attrclass(db_key=attribute_name, db_obj=self)
new_attrib.value = new_value
return
# re-set an old attribute value # re-set an old attribute value
attrib_obj.value = new_value attrib_obj.value = new_value

View file

@ -25,7 +25,8 @@ DA = object.__delattr__
# full access anyway), so no protection against changing # full access anyway), so no protection against changing
# e.g. 'locks' or 'permissions' should go here. # e.g. 'locks' or 'permissions' should go here.
PROTECTED = ('id', 'dbobj', 'db', 'ndb', 'objects', 'typeclass', PROTECTED = ('id', 'dbobj', 'db', 'ndb', 'objects', 'typeclass',
'attr', 'save', 'delete') 'attr', 'save', 'delete', 'db_model_name','attribute_class',
'typeclass_paths')
# If this is true, all non-protected property assignments # If this is true, all non-protected property assignments
# are directly stored to a database attribute # are directly stored to a database attribute
@ -207,3 +208,5 @@ class TypeClass(object):
def __str__(self): def __str__(self):
"represent the object" "represent the object"
return self.key return self.key
def __unicode__(self):
return u"%s" % self.key

View file

@ -410,7 +410,6 @@ def create_player(name, email, password,
new_user = User.objects.create_superuser(name, email, password) new_user = User.objects.create_superuser(name, email, password)
else: else:
new_user = User.objects.create_user(name, email, password) new_user = User.objects.create_user(name, email, password)
try: try:
if not typeclass: if not typeclass:
typeclass = settings.BASE_PLAYER_TYPECLASS typeclass = settings.BASE_PLAYER_TYPECLASS
@ -464,7 +463,7 @@ def create_player(name, email, password,
player=new_player) player=new_player)
return new_character return new_character
return new_player return new_player
except Exception: except Exception,e:
# a failure in creating the character # a failure in creating the character
if not user: if not user:
# in there was a failure we clean up everything we can # in there was a failure we clean up everything we can