Fixed the issues with assigning to nested attribute-lists/dicts "in-situ", e.g. obj.db.mylist[1][2] = val. This now works as it should. I'm still not sure this behaviour is worth the fact that returning mylist from the attribute will actually return a nested structure of PackedLists/Dicts, and these will continue to save to the database whenever they are updated, also if not used in conjuction with db. Since this behaviour is what is already in the database, I'm committing this fix for the nested assignment error until I decide what to do about the other issue = val. This now works as it should. I'm still not sure this behaviour is worth the fact that returning mylist from the attribute will actually return a nested structure of PackedLists/Dicts, and these will continue to save to the database whenever they are updated, also if not used in conjuction with db. Since this behaviour is what is already in the database, I'm committing this fix for the nested assignment error until I decide what to do about the other issue..
This commit is contained in:
parent
9e2380decd
commit
9733a43a16
1 changed files with 54 additions and 17 deletions
|
|
@ -99,32 +99,47 @@ class PackedDict(dict):
|
||||||
order to allow custom updates to the dict.
|
order to allow custom updates to the dict.
|
||||||
|
|
||||||
db_obj - the Attribute object storing this dict.
|
db_obj - the Attribute object storing this dict.
|
||||||
|
|
||||||
|
The 'parent' property is set to 'init' at creation,
|
||||||
|
this stops the system from saving itself over and over
|
||||||
|
when first assigning the dict. Once initialization
|
||||||
|
is over, the Attribute from_attr() method will assign
|
||||||
|
the parent (or None, if at the root)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.db_obj = db_obj
|
self.db_obj = db_obj
|
||||||
|
self.parent = 'init'
|
||||||
super(PackedDict, self).__init__(*args, **kwargs)
|
super(PackedDict, self).__init__(*args, **kwargs)
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "{%s}" % ", ".join("%s:%s" % (key, str(val)) for key, val in self.items())
|
return "{%s}" % ", ".join("%s:%s" % (key, str(val)) for key, val in self.items())
|
||||||
|
def save(self):
|
||||||
|
"Relay save operation upwards in tree until we hit the root."
|
||||||
|
if self.parent == 'init':
|
||||||
|
pass
|
||||||
|
elif self.parent:
|
||||||
|
self.parent.save()
|
||||||
|
else:
|
||||||
|
self.db_obj.value = self
|
||||||
def __setitem__(self, *args, **kwargs):
|
def __setitem__(self, *args, **kwargs):
|
||||||
"assign item to this dict"
|
"assign item to this dict"
|
||||||
super(PackedDict, self).__setitem__(*args, **kwargs)
|
super(PackedDict, self).__setitem__(*args, **kwargs)
|
||||||
self.db_obj.value = self
|
self.save()
|
||||||
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_obj.value = self
|
self.save()
|
||||||
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_obj.value = self
|
self.save()
|
||||||
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_obj.value = self
|
self.save()
|
||||||
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_obj.value = self
|
self.save()
|
||||||
|
|
||||||
class PackedList(list):
|
class PackedList(list):
|
||||||
"""
|
"""
|
||||||
|
|
@ -137,43 +152,59 @@ class PackedList(list):
|
||||||
"""
|
"""
|
||||||
Sets up the packing list.
|
Sets up the packing list.
|
||||||
db_obj - the Attribute object storing this dict.
|
db_obj - the Attribute object storing this dict.
|
||||||
|
|
||||||
|
The 'parent' property is set to 'init' at creation,
|
||||||
|
this stops the system from saving itself over and over
|
||||||
|
when first assigning the dict. Once initialization
|
||||||
|
is over, the Attribute from_attr() method will assign
|
||||||
|
the parent (or None, if at the root)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.db_obj = db_obj
|
self.db_obj = db_obj
|
||||||
|
self.parent = 'init'
|
||||||
super(PackedList, self).__init__(*args, **kwargs)
|
super(PackedList, self).__init__(*args, **kwargs)
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "[%s]" % ", ".join(str(val) for val in self)
|
return "[%s]" % ", ".join(str(val) for val in self)
|
||||||
|
def save(self):
|
||||||
|
"Relay save operation upwards in tree until we hit the root."
|
||||||
|
if self.parent == 'init':
|
||||||
|
pass
|
||||||
|
elif self.parent:
|
||||||
|
self.parent.save()
|
||||||
|
else:
|
||||||
|
self.db_obj.value = self
|
||||||
def __setitem__(self, *args, **kwargs):
|
def __setitem__(self, *args, **kwargs):
|
||||||
"Custom setitem that stores changed list to database."
|
"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
|
self.save()
|
||||||
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_obj.value = self
|
self.save()
|
||||||
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_obj.value = self
|
self.save()
|
||||||
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_obj.value = self
|
self.save()
|
||||||
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_obj.value = self
|
self.save()
|
||||||
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_obj.value = self
|
self.save()
|
||||||
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_obj.value = self
|
self.save()
|
||||||
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_obj.value = self
|
self.save()
|
||||||
|
|
||||||
class Attribute(SharedMemoryModel):
|
class Attribute(SharedMemoryModel):
|
||||||
"""
|
"""
|
||||||
|
|
@ -457,7 +488,7 @@ class Attribute(SharedMemoryModel):
|
||||||
except mclass.DoesNotExist: # could happen if object was deleted in the interim.
|
except mclass.DoesNotExist: # could happen if object was deleted in the interim.
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def iter_id2db(item):
|
def iter_id2db(item, parent=None):
|
||||||
"""
|
"""
|
||||||
Recursively looping through stored iterables, replacing ids with actual objects.
|
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
|
We return PackedDict and PackedLists instead of normal lists; this is needed in order for
|
||||||
|
|
@ -472,10 +503,16 @@ class Attribute(SharedMemoryModel):
|
||||||
elif dtype == tuple:
|
elif dtype == tuple:
|
||||||
return tuple([iter_id2db(val) for val in item])
|
return tuple([iter_id2db(val) for val in item])
|
||||||
elif dtype in (dict, PackedDict):
|
elif dtype in (dict, PackedDict):
|
||||||
return PackedDict(self, dict(zip([key for key in item.keys()],
|
pdict = PackedDict(self)
|
||||||
[iter_id2db(val) for val in item.values()])))
|
pdict.update(dict(zip([key for key in item.keys()],
|
||||||
|
[iter_id2db(val, pdict) for val in item.values()])))
|
||||||
|
pdict.parent = parent
|
||||||
|
return pdict
|
||||||
elif hasattr(item, '__iter__'):
|
elif hasattr(item, '__iter__'):
|
||||||
return PackedList(self, list(iter_id2db(val) for val in item))
|
plist = PackedList(self)
|
||||||
|
plist.extend(list(iter_id2db(val, plist) for val in item))
|
||||||
|
plist.parent = parent
|
||||||
|
return plist
|
||||||
else:
|
else:
|
||||||
return item
|
return item
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue