Thursday, April 28, 2016

Possible bug in walk_items, django admin delete confirmation use case

Hi,

On Django 1.8 (at least, all I can currently check.)

The method walk_items at django/template/defaultfilters.py:682, uses a
look ahead that technically doesn't always work.

If you look at the function, and notice at the end this

if next_item:
yield next_item, None

That will yield back the next_item as if it's a string/leaf, with no
children, which IS NOT always the case. There is no check to see if
it has children, only item is checked.

Of course, in this use case, you are choosing to delete a single model
object, so it is safe to assume the first item in the walk will be a
string, and the next, if any, could be an array (children), or a
string (just the next item.) But, when recursively calling this
method on sublists, it is possible miss a list based simply on where
it comes in the items_list.

The problem is that the last case up there assumes because the
next_item wasn't a list, the next item after it won't be either,
because after that line, control goes back to top to get the "next"
element, after next_item, from the iterator.

I can't share code. But, if you create some levels of model
structure, I'm sure you can make this happen. I'm happy to help with
that, should it be necessary.

The fix I'm using ....

def walk_items(item_list):

class PushbackIterator(object):

def __init__(self, iter):
self.stash = []
self.iter = iter

def __iter__(self):
return self

def next(self):
if self.stash:
return self.stash.pop()
else:
return self.iter.next()

def push(self, item):
self.stash.append(item)

item_iterator = PushbackIterator(iter(item_list))

for item in item_iterator:
try:
next_item = next(item_iterator)
except StopIteration:
next_item = None
if not isinstance(next_item, six.string_types):
try:
iter(next_item)
except TypeError:
pass
else:
yield item, next_item
continue
yield item, None
if next_item:
item_iterator.push(next_item)

I monkey patched a fix for my project with this. Comments welcome.

Thanks
Gene

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/CAFXCamB4EAJ2uu3CjUqTJSxsp7Q%3DrTPBhZDn_ti21HoYftV18A%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment