Fixed an issue where saving an attribute/tag would make duplicates.

This commit is contained in:
Kelketek Rritaa 2014-06-28 18:01:00 -05:00
parent a6187ed997
commit a1b596a847
3 changed files with 41 additions and 24 deletions

View file

@ -1,14 +1,9 @@
from django.contrib import admin from django.contrib import admin
from django.contrib.admin import ModelAdmin from django.contrib.admin import ModelAdmin
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.forms import Textarea
from src.typeclasses.models import Attribute, Tag from src.typeclasses.models import Attribute, Tag
class PickledWidget(Textarea):
pass
class TagAdmin(admin.ModelAdmin): class TagAdmin(admin.ModelAdmin):
fields = ('db_key', 'db_category', 'db_data') fields = ('db_key', 'db_category', 'db_data')
@ -26,7 +21,7 @@ class AttributeInline(admin.TabularInline):
""" """
# Set this to the through model of your desired M2M when subclassing. # Set this to the through model of your desired M2M when subclassing.
model = None model = None
extra = 3 extra = 1
#form = AttributeForm #form = AttributeForm
fields = ('attribute', 'key', 'value', 'strvalue') fields = ('attribute', 'key', 'value', 'strvalue')
raw_id_fields = ('attribute',) raw_id_fields = ('attribute',)

View file

@ -34,6 +34,7 @@ import weakref
from django.db import models from django.db import models
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.conf import settings from django.conf import settings
from django.db.models import Q
from django.utils.encoding import smart_str from django.utils.encoding import smart_str
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
@ -46,7 +47,8 @@ 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 from src.utils import logger
from src.utils.utils import make_iter, is_iter, to_str, inherits_from, LazyLoadHandler from src.utils.utils import (
make_iter, is_iter, to_str, inherits_from, LazyLoadHandler)
from src.utils.dbserialize import to_pickle, from_pickle from src.utils.dbserialize import to_pickle, from_pickle
from src.utils.picklefield import PickledObjectField from src.utils.picklefield import PickledObjectField
@ -69,7 +71,6 @@ _DA = object.__delattr__
# #
#------------------------------------------------------------ #------------------------------------------------------------
#class Attribute(SharedMemoryModel):
class Attribute(SharedMemoryModel): class Attribute(SharedMemoryModel):
""" """
Abstract django model. Abstract django model.
@ -99,20 +100,33 @@ class Attribute(SharedMemoryModel):
# These database fields are all set using their corresponding properties, # These database fields are all set using their corresponding properties,
# named same as the field, but withtout the db_* prefix. # named same as the field, but withtout the db_* prefix.
db_key = models.CharField('key', max_length=255, db_index=True) db_key = models.CharField('key', max_length=255, db_index=True)
# access through the value property db_value = PickledObjectField(
db_value = PickledObjectField('value', null=True) 'value', null=True,
# string-specific storage for quick look-up help_text="The data returned when the attribute is accessed. Must be "
db_strvalue = models.TextField('strvalue', null=True, blank=True) "written as a Python literal if editing through the admin "
# optional categorization of attribute "interface.")
db_category = models.CharField('category', max_length=128, db_index=True, blank=True, null=True) db_strvalue = models.TextField(
'strvalue', null=True, blank=True,
help_text="String-specific storage for quick look-up")
db_category = models.CharField(
'category', max_length=128, db_index=True, blank=True, null=True,
help_text="Optional categorization of attribute.")
# Lock storage # Lock storage
db_lock_storage = models.TextField('locks', blank=True) db_lock_storage = models.TextField(
# Which model of object this Attribute is attached to (A natural key like objects.dbobject) 'locks', blank=True,
db_model = models.CharField('model', max_length=32, db_index=True, blank=True, null=True) help_text="Lockstrings for this object are stored here.")
db_model = models.CharField(
'model', max_length=32, db_index=True, blank=True, null=True,
help_text="Which model of object this attribute is attached to (A "
"natural key like objects.dbobject). You should not change "
"this value unless you know what you are doing.")
# subclass of Attribute (None or nick) # subclass of Attribute (None or nick)
db_attrtype = models.CharField('attrtype', max_length=16, db_index=True, blank=True, null=True) db_attrtype = models.CharField(
'attrtype', max_length=16, db_index=True, blank=True, null=True,
help_text="Subclass of Attribute (None or nick)")
# 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()
@ -226,10 +240,14 @@ class AttributeHandler(object):
self._cache = None self._cache = None
def _recache(self): def _recache(self):
if not self._attrtype:
attrtype = Q(db_attrtype=None) | Q(db_attrtype='')
else:
attrtype = Q(db_attrtype=self._attrtype)
self._cache = dict(("%s-%s" % (to_str(attr.db_key).lower(), self._cache = dict(("%s-%s" % (to_str(attr.db_key).lower(),
attr.db_category.lower() if attr.db_category else None), attr) attr.db_category.lower() if attr.db_category else None), attr)
for attr in getattr(self.obj, self._m2m_fieldname).filter( for attr in getattr(self.obj, self._m2m_fieldname).filter(
db_model=self._model, db_attrtype=self._attrtype)) db_model=self._model).filter(attrtype))
#set_attr_cache(self.obj, self._cache) # currently only for testing #set_attr_cache(self.obj, self._cache) # currently only for testing
def has(self, key, category=None): def has(self, key, category=None):
@ -551,12 +569,16 @@ class TagHandler(object):
self._model = "%s.%s" % ContentType.objects.get_for_model(obj).natural_key() self._model = "%s.%s" % ContentType.objects.get_for_model(obj).natural_key()
self._cache = None self._cache = None
def _recache(self): def _recache(self):
"Update cache from database field" "Update cache from database field"
if not self._tagtype:
tagtype = Q(db_tagtype='') | Q(db_tagtype__isnull=True)
else:
tagtype = Q(db_tagtype=self._tagtype)
self._cache = dict(("%s-%s" % (tag.db_key, tag.db_category), tag) self._cache = dict(("%s-%s" % (tag.db_key, tag.db_category), tag)
for tag in getattr(self.obj, self._m2m_fieldname).filter( for tag in getattr(
db_model=self._model, db_tagtype=self._tagtype)) self.obj, self._m2m_fieldname).filter(
db_model=self._model).filter(tagtype))
def add(self, tag, category=None, data=None): def add(self, tag, category=None, data=None):
"Add a new tag to the handler. Tag is a string or a list of strings." "Add a new tag to the handler. Tag is a string or a list of strings."

View file

@ -161,7 +161,7 @@ class PickledFormField(CharField):
value = 'None' value = 'None'
try: try:
return literal_eval(value) return literal_eval(value)
except ValueError: except (ValueError, SyntaxError):
raise ValidationError(self.error_messages['invalid']) raise ValidationError(self.error_messages['invalid'])