implement first filter updates for existing objects

This commit is contained in:
Laura Klünder 2017-06-15 00:07:19 +02:00
parent cc8b4510a2
commit c93240eca7
2 changed files with 50 additions and 6 deletions

View file

@ -85,6 +85,10 @@ class ChangeSet(models.Model):
else:
self.m2m_remove_existing.setdefault(model, {}).setdefault(change.obj_pk, set()).add(value)
def get_changed_values(self, model, name):
return tuple((pk, values[name])
for pk, values in self.updated_existing.get(model, {}).items() if name in values)
@classmethod
def qs_base(cls, hide_applied=True):
qs = cls.objects.prefetch_related('changes').select_related('author')

View file

@ -256,14 +256,54 @@ class BaseQueryWrapper(BaseWrapper):
def order_by(self, *args):
return self._wrap_queryset(self.get_queryset().order_by(*args))
def _filter_kwarg(self, name, value):
if name.endswith('__in'):
value = tuple((item._obj if isinstance(item, ModelInstanceWrapper) else item) for item in value)
def _filter_values(self, q, field_name, check):
other_values = self._changeset.get_changed_values(self._obj.model, field_name)
add_pks = []
remove_pks = []
for pk, new_value in other_values:
(add_pks if check(new_value) else remove_pks).append(pk)
return (q & ~Q(pk__in=remove_pks)) | Q(pk__in=add_pks)
if isinstance(value, ModelInstanceWrapper):
value = value._obj
def _filter_kwarg(self, filter_name, filter_value):
print(filter_name, '=', filter_value, sep='')
return Q(**{name: value})
segments = filter_name.split('__')
field_name = segments.pop(0)
try:
class_value = getattr(self._obj.model, field_name)
except AttributeError:
raise ValueError('%s has no attribute %s' % (self._obj.model, field_name))
q = Q(**{filter_name: filter_value})
if isinstance(class_value, ForwardManyToOneDescriptor):
if not segments:
raise NotImplementedError
filter_type = segments.pop(0)
if not segments and filter_type == 'in':
filter_name = field_name+'__pk__in'
filter_value = tuple(obj.pk for obj in filter_value)
filter_type = 'pk'
segments = ['in']
q = Q(**{filter_name: filter_value})
if filter_type == 'pk' and segments == ['in']:
return self._filter_values(q, field_name, lambda val: val in filter_value)
if segments:
raise NotImplementedError
if filter_type == 'isnull':
return self._filter_values(q, field_name, lambda val: (val is None) is filter_value)
raise NotImplementedError('cannot filter %s by %s (%s)' % (self._obj.model, filter_name, class_value))
if isinstance(filter_value, ModelInstanceWrapper):
filter_value = filter_value._obj
return Q(**{filter_name: filter_value})
def _filter_q(self, q):
result = Q(*((self._filter_q(c) if isinstance(c, Q) else self._filter_kwarg(*c)) for c in q.children))