OBS:Run migrations! Changed the comms.Msg.db_title field to db_header to better reflect its use.

This commit is contained in:
Griatch 2012-11-04 15:37:06 +01:00
parent a4a50fdb87
commit f3b50a20a8
5 changed files with 206 additions and 65 deletions

View file

@ -231,7 +231,7 @@ class MsgManager(models.Manager):
receiver_restrict = Q()
# filter by full text
if freetext:
fulltext_restrict = Q(db_title__icontains=freetext) | Q(db_message__icontains=freetext)
fulltext_restrict = Q(db_header__icontains=freetext) | Q(db_message__icontains=freetext)
else:
fulltext_restrict = Q()
# execute the query

View file

@ -7,13 +7,13 @@ from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding index on 'Channel', fields ['db_key']
db.create_index('comms_channel', ['db_key'])
def backwards(self, orm):
# Removing index on 'Channel', fields ['db_key']
db.delete_index('comms_channel', ['db_key'])

View file

@ -0,0 +1,139 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Msg.db_header'
db.add_column('comms_msg', 'db_header',
self.gf('django.db.models.fields.CharField')(db_index=True, max_length=128, null=True, blank=True),
keep_default=False)
if not db.dry_run:
for msg in orm.Msg.objects.all():
msg.db_header = msg.db_title
msg.save()
# Deleting field 'Msg.db_title'
db.delete_column('comms_msg', 'db_title')
def backwards(self, orm):
# Adding field 'Msg.db_title'
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'})
},
'comms.channel': {
'Meta': {'object_name': 'Channel'},
'db_aliases': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'db_desc': ('django.db.models.fields.CharField', [], {'max_length': '80', 'null': 'True', 'blank': 'True'}),
'db_keep_log': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'db_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'comms.externalchannelconnection': {
'Meta': {'object_name': 'ExternalChannelConnection'},
'db_channel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['comms.Channel']"}),
'db_external_config': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'db_external_key': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'db_external_send_code': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'db_is_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'comms.msg': {
'Meta': {'object_name': 'Msg'},
'db_date_sent': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
'db_header': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '128', 'null': 'True', 'blank': 'True'}),
'db_hide_from_channles': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'hide_from_channels_set'", 'null': 'True', 'to': "orm['comms.Channel']"}),
'db_hide_from_objects': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'hide_from_objects_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_hide_from_players': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'hide_from_players_set'", 'null': 'True', 'to': "orm['players.PlayerDB']"}),
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'db_message': ('django.db.models.fields.TextField', [], {}),
'db_receivers_channels': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'channel_set'", 'null': 'True', 'to': "orm['comms.Channel']"}),
'db_receivers_objects': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'receiver_object_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_receivers_players': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'receiver_player_set'", 'null': 'True', 'to': "orm['players.PlayerDB']"}),
'db_sender_external': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'db_index': 'True'}),
'db_sender_objects': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'sender_object_set'", 'null': 'True', 'db_index': 'True', 'to': "orm['objects.ObjectDB']"}),
'db_sender_players': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'sender_player_set'", 'null': 'True', 'db_index': 'True', 'to': "orm['players.PlayerDB']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'comms.playerchannelconnection': {
'Meta': {'object_name': 'PlayerChannelConnection'},
'db_channel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['comms.Channel']"}),
'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'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_is_connected': ('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_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 = ['comms']

View file

@ -75,11 +75,12 @@ class Msg(SharedMemoryModel):
db_receivers_objects = models.ManyToManyField('objects.ObjectDB', related_name='receiver_object_set', null=True, help_text="object receivers")
db_receivers_channels = models.ManyToManyField("Channel", related_name='channel_set', null=True, help_text="channel recievers")
# The actual message and a timestamp. The message field
# should itself handle eventual headers etc.
db_title = models.CharField('title', max_length=512, null=True, blank=True, db_index=True)
# header could be used for meta-info about the message if your system needs it, or as a separate
# store for the mail subject line maybe.
db_header = models.CharField('header', max_length=128, null=True, blank=True, db_index=True)
# the message body itself
db_message = models.TextField('messsage')
# send date
db_date_sent = models.DateTimeField('date sent', editable=False, auto_now_add=True, db_index=True)
# lock storage
db_lock_storage = models.CharField('locks', max_length=512, blank=True,
@ -209,23 +210,23 @@ class Msg(SharedMemoryModel):
self.save()
channels = property(__channels_get, __channels_set, __channels_del)
# title property (wraps db_title)
# header property (wraps db_header)
#@property
def __title_get(self):
def __header_get(self):
"Getter. Allows for value = self.message"
return self.db_title
return self.db_header
#@message.setter
def __title_set(self, value):
def __header_set(self, value):
"Setter. Allows for self.message = value"
if value:
self.db_title = value
self.db_header = value
self.save()
#@message.deleter
def __title_del(self):
def __header_del(self):
"Deleter. Allows for del self.message"
self.db_title = ""
self.db_header = ""
self.save()
title = property(__title_get, __title_set, __title_del)
header = property(__header_get, __header_set, __header_del)
# message property (wraps db_message)
#@property
@ -338,11 +339,12 @@ class TempMsg(object):
sender to be given.
"""
def __init__(self, senders=None, receivers=None, channels=None, message="", title="", lockstring="", hide_from=None):
def __init__(self, senders=None, receivers=None, channels=None, message="", header="", type="", lockstring="", hide_from=None):
self.senders = senders and make_iter(senders) or []
self.receivers = receivers and make_iter(receivers) or []
self.channels = channels and make_iter(channels) or []
self.title = title
self.type = type
self.header, header
self.message = message
self.lock_storage = lockstring
self.locks = LockHandler(self)
@ -544,7 +546,7 @@ class Channel(SharedMemoryModel):
"""
return PlayerChannelConnection.objects.has_player_connection(player, self)
def msg(self, msgobj, title=None, senders=None, persistent=True):
def msg(self, msgobj, header=None, senders=None, persistent=True):
"""
Send the given message to all players connected to channel. Note that
no permission-checking is done here; it is assumed to have been
@ -568,7 +570,7 @@ class Channel(SharedMemoryModel):
msg = TempMsg()
if senders:
msg.senders = make_iter(senders)
msg.title = title
msg.header = header
msg.message = msgobj
msg.channels = [self] # add this channel
else:
@ -586,11 +588,11 @@ class Channel(SharedMemoryModel):
logger.log_trace("Cannot send msg to connection '%s'" % conn)
return True
def tempmsg(self, message, title=None, senders=None):
def tempmsg(self, message, header=None, senders=None):
"""
A wrapper for sending non-persistent messages.
"""
self.msg(message, senders=senders, title=title, persistent=False)
self.msg(message, senders=senders, header=header, persistent=False)
def connect_to(self, player):
"Connect the user to this channel"

View file

@ -20,63 +20,63 @@ DA = object.__delattr__
class PackedDict(dict):
"""
Attribute helper class.
A variant of dict that stores itself to the database when
updating one of its keys. This is called and handled by
Attribute.validate_data().
A variant of dict that stores itself to the database when
updating one of its keys. This is called and handled by
Attribute.validate_data().
"""
def __init__(self, db_obj, *args, **kwargs):
"""
Sets up the packing dict. The db_store variable
is set by Attribute.validate_data() when returned in
order to allow custom updates to the dict.
order to allow custom updates to the dict.
db_obj - the Attribute object storing this dict.
"""
self.db_obj = db_obj
super(PackedDict, self).__init__(*args, **kwargs)
def __str__(self):
return "{%s}" % ", ".join("%s:%s" % (key, str(val)) for key, val in self.items())
def __setitem__(self, *args, **kwargs):
def __setitem__(self, *args, **kwargs):
"assign item to this dict"
super(PackedDict, self).__setitem__(*args, **kwargs)
self.db_obj.value = self
def clear(self, *args, **kwargs):
def clear(self, *args, **kwargs):
"Custom clear"
super(PackedDict, self).clear(*args, **kwargs)
self.db_obj.value = self
def pop(self, *args, **kwargs):
def pop(self, *args, **kwargs):
"Custom pop"
super(PackedDict, self).pop(*args, **kwargs)
self.db_obj.value = self
def popitem(self, *args, **kwargs):
def popitem(self, *args, **kwargs):
"Custom popitem"
super(PackedDict, self).popitem(*args, **kwargs)
self.db_obj.value = self
def update(self, *args, **kwargs):
def update(self, *args, **kwargs):
"Custom update"
super(PackedDict, self).update(*args, **kwargs)
self.db_obj.value = self
class PackedList(list):
"""
Attribute helper class.
A variant of list that stores itself to the database when
updating one of its keys. This is called and handled by
Attribute.validate_data().
A variant of list that stores itself to the database when
updating one of its keys. This is called and handled by
Attribute.validate_data().
"""
def __init__(self, db_obj, *args, **kwargs):
"""
Sets up the packing list.
Sets up the packing list.
db_obj - the Attribute object storing this dict.
"""
self.db_obj = db_obj
super(PackedList, self).__init__(*args, **kwargs)
def __str__(self):
return "[%s]" % ", ".join(str(val) for val in self)
def __setitem__(self, *args, **kwargs):
def __setitem__(self, *args, **kwargs):
"Custom setitem that stores changed list to database."
super(PackedList, self).__setitem__(*args, **kwargs)
super(PackedList, self).__setitem__(*args, **kwargs)
self.db_obj.value = self
def append(self, *args, **kwargs):
"Custom append"
@ -123,13 +123,13 @@ def to_attr(data):
(and any nested combination of them) this way, all other
iterables are stored and returned as lists.
data storage format:
data storage format:
(simple|dbobj|iter, <data>)
where
where
simple - a single non-db object, like a string or number
dbobj - a single dbobj
iter - any iterable object - will be looped over recursively
to convert dbobj->id.
to convert dbobj->id.
"""
@ -140,7 +140,7 @@ def to_attr(data):
"""
dtype = type(item)
if dtype in (basestring, int, float): # check the most common types first, for speed
return item
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":
@ -166,8 +166,8 @@ def to_attr(data):
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 ("dbobj", PackedDBobject(data.id, db_model_name, data.db_key))
elif hasattr(data, "__iter__"):
return ("iter", iter_db2id(data))
else:
return ("simple", data)
@ -175,21 +175,21 @@ def to_attr(data):
def from_attr(attr, datatuple):
"""
Retrieve data from a previously stored attribute. This
is always a dict with keys type and data.
is always a dict with keys type and data.
datatuple comes from the database storage and has
the following format:
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.
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
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.
is then a PackedList that saves the data on the fly.
"""
# nested functions
# nested functions
def id2db(data):
"""
Convert db-stored dbref back to object
@ -202,39 +202,39 @@ def from_attr(attr, datatuple):
try:
return mclass.objects.get(id=data.id)
except mclass.DoesNotExist: # could happen if object was deleted in the interim.
return None
return None
def iter_id2db(item):
"""
Recursively looping through stored iterables, replacing ids with actual objects.
We return PackedDict and PackedLists instead of normal lists; this is needed in order for
the user to do dynamic saving of nested in-place, such as obj.db.attrlist[2]=3. What is
stored in the database are however always normal python primitives.
stored in the database are however always normal python primitives.
"""
dtype = type(item)
if dtype in (basestring, int, float): # check the most common types first, for speed
return item
return item
elif dtype == PackedDBobject:
return id2db(item)
elif dtype == tuple:
elif dtype == tuple:
return tuple([iter_id2db(val) for val in item])
elif dtype in (dict, PackedDict):
return dict(zip([key for key in item.keys()],
[iter_id2db(val) for val in item.values()]))
elif hasattr(item, '__iter__'):
return list(iter_id2db(val) for val in item)
else:
return item
else:
return item
typ, data = datatuple
if typ == 'simple':
if typ == 'simple':
# single non-db objects
return data
elif typ == 'dbobj':
# a single stored dbobj
elif typ == 'dbobj':
# a single stored dbobj
return id2db(data)
elif typ == 'iter':
elif typ == 'iter':
# all types of iterables
return iter_id2db(data)
@ -249,9 +249,9 @@ class Migration(DataMigration):
val = pickle.loads(to_str(attr.db_value))
attr.db_value = to_unicode(pickle.dumps(to_str(to_attr(from_attr(attr, val)))))
attr.save()
except TypeError, RuntimeError:
pass
except TypeError, RuntimeError:
pass
def backwards(self, orm):
"Write your backwards methods here."
raise RuntimeError