track m2m changes
This commit is contained in:
parent
66596aac63
commit
ff0922fe64
3 changed files with 56 additions and 8 deletions
|
@ -98,17 +98,26 @@ class ChangeSet(models.Model):
|
|||
for name, value in kwargs.items():
|
||||
setattr(change, name, value)
|
||||
change.save()
|
||||
print(repr(change))
|
||||
# print(repr(change))
|
||||
return change
|
||||
|
||||
def add_create(self, obj, author=None):
|
||||
change = self._new_change(author=author, action='create', model_class=type(obj._obj))
|
||||
obj.pk = 'c%d' % change.pk
|
||||
|
||||
def add_update(self, obj, name, value, author=None):
|
||||
return self._new_change(author=author, action='update', obj=obj,
|
||||
def _add_value(self, action, obj, name, value, author=None):
|
||||
return self._new_change(author=author, action=action, obj=obj,
|
||||
field_name=name, field_value=json.dumps(value, ensure_ascii=False))
|
||||
|
||||
def add_update(self, obj, name, value, author=None):
|
||||
return self._add_value('update', obj, name, value, author)
|
||||
|
||||
def add_m2m_add(self, obj, name, value, author=None):
|
||||
return self._add_value('m2m_add', obj, name, value, author)
|
||||
|
||||
def add_m2m_remove(self, obj, name, value, author=None):
|
||||
return self._add_value('m2m_remove', obj, name, value, author)
|
||||
|
||||
def add_delete(self, obj, author=None):
|
||||
return self._new_change(author=author, action='delete', obj=obj)
|
||||
|
||||
|
@ -183,8 +192,11 @@ class Change(models.Model):
|
|||
raise TypeError('existing_model_pk or created_object have to be set.')
|
||||
|
||||
@obj.setter
|
||||
def obj(self, value: models.Model):
|
||||
if isinstance(value, ModelInstanceWrapper) and isinstance(value.pk, str):
|
||||
def obj(self, value):
|
||||
if not isinstance(value, ModelInstanceWrapper):
|
||||
value = self.changeset.wrap(value)
|
||||
|
||||
if isinstance(value.pk, str):
|
||||
if value._changeset.id != self.changeset.pk:
|
||||
raise ValueError('value is a Change instance but belongs to a different changeset.')
|
||||
self.model_class = type(value._obj)
|
||||
|
@ -252,5 +264,9 @@ class Change(models.Model):
|
|||
result += 'Update object '+repr(self.obj)+': '+self.field_name+'='+self.field_value
|
||||
elif self.action == 'delete':
|
||||
result += 'Delete object '+repr(self.obj)
|
||||
elif self.action == 'm2m_add':
|
||||
result += 'Update (m2m) object '+repr(self.obj)+': '+self.field_name+'.add('+self.field_value+')'
|
||||
elif self.action == 'm2m_remove':
|
||||
result += 'Update (m2m) object '+repr(self.obj)+': '+self.field_name+'.remove('+self.field_value+')'
|
||||
result += '>'
|
||||
return result
|
||||
|
|
|
@ -226,7 +226,7 @@ def edit(request, pk=None, model=None, level=None, space=None, on_top_of=None, e
|
|||
obj.on_top_of = on_top_of
|
||||
|
||||
obj.save()
|
||||
# form.save_m2m()
|
||||
form.save_m2m()
|
||||
# request.changeset.changes.all().delete()
|
||||
|
||||
return redirect(ctx['back_url'])
|
||||
|
|
|
@ -19,6 +19,8 @@ class BaseWrapper:
|
|||
return ModelInstanceWrapper(self._changeset, instance, self._author)
|
||||
|
||||
def _wrap_manager(self, manager):
|
||||
if hasattr(manager, 'through'):
|
||||
return ManyRelatedManagerWrapper(self._changeset, manager, self._author)
|
||||
return ManagerWrapper(self._changeset, manager, self._author)
|
||||
|
||||
def _wrap_queryset(self, queryset):
|
||||
|
@ -37,8 +39,6 @@ class BaseWrapper:
|
|||
elif callable(value) and name not in self._allowed_callables:
|
||||
if not isinstance(self, ModelInstanceWrapper) or hasattr(models.Model, name):
|
||||
raise TypeError('Can not call %s.%s wrapped!' % (self._obj, name))
|
||||
|
||||
# print(self._obj, name, type(value), value)
|
||||
return value
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
|
@ -212,5 +212,37 @@ class ManagerWrapper(BaseQueryWrapper):
|
|||
pass
|
||||
|
||||
|
||||
class ManyRelatedManagerWrapper(ManagerWrapper):
|
||||
def _check_through(self):
|
||||
if not self._obj.through._meta.auto_created:
|
||||
raise AttributeError('Cannot do this an a ManyToManyField which specifies an intermediary model.')
|
||||
|
||||
def set(self, objs, author=None):
|
||||
if author is None:
|
||||
author = self._author
|
||||
|
||||
old_ids = set(self.values_list('pk', flat=True))
|
||||
new_ids = set(obj.pk for obj in objs)
|
||||
|
||||
self.remove(*(old_ids - new_ids))
|
||||
self.add(*(new_ids - old_ids))
|
||||
|
||||
def add(self, *objs, author=None):
|
||||
if author is None:
|
||||
author = self._author
|
||||
|
||||
for obj in objs:
|
||||
pk = (obj.pk if isinstance(obj, self._obj.model) else obj)
|
||||
self._changeset.add_m2m_add(self._obj.instance, name=self.prefetch_cache_name, value=pk, author=author)
|
||||
|
||||
def remove(self, *objs, author=None):
|
||||
if author is None:
|
||||
author = self._author
|
||||
|
||||
for obj in objs:
|
||||
pk = (obj.pk if isinstance(obj, self._obj.model) else obj)
|
||||
self._changeset.add_m2m_remove(self._obj.instance, name=self.prefetch_cache_name, value=pk, author=author)
|
||||
|
||||
|
||||
class QuerySetWrapper(BaseQueryWrapper):
|
||||
pass
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue