pennersr / django-pagemore

KISS approach to a "Load more" style AJAX paginator
BSD 3-Clause "New" or "Revised" License
54 stars 17 forks source link

Error using pagemore with a chained queryset #5

Open caumons opened 11 years ago

caumons commented 11 years ago

When using a "chained queryset" to do the pagination (obtained through itertools.chain method) the following exception is raised: Exception Value: 'itertools.chain' object has no attribute '__getitem__'.

Is there an easy way to get it working? I'm not sure if calling list() on the chained object before calling pagemore would be the best solution, because it will evaluate the queryset and this could cause a lot of overhead :S Thanks in advance!

Here's the full stacktrace:

Traceback:
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response
  115.                         response = callback(request, *callback_args, **callback_kwargs)
File "/media/dades/Enric/Documentos/workspace/EurekaStart/EurekaStart/views.py" in home
  19.             'contents': Content.actives.priority_filter(request.user),
File "/usr/local/lib/python2.7/dist-packages/django/shortcuts/__init__.py" in render
  53.     return HttpResponse(loader.render_to_string(*args, **kwargs),
File "/usr/local/lib/python2.7/dist-packages/django/template/loader.py" in render_to_string
  177.         return t.render(context_instance)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  140.             return self._render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in _render
  134.         return self.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  830.                 bit = self.render_node(node, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py" in render_node
  74.             return node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py" in render
  124.         return compiled_parent._render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in _render
  134.         return self.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  830.                 bit = self.render_node(node, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py" in render_node
  74.             return node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py" in render
  63.             result = block.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  830.                 bit = self.render_node(node, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py" in render_node
  74.             return node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py" in render
  63.             result = block.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  830.                 bit = self.render_node(node, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py" in render_node
  74.             return node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py" in render
  156.         return self.render_template(self.template, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py" in render_template
  138.         output = template.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  140.             return self._render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in _render
  134.         return self.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  830.                 bit = self.render_node(node, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py" in render_node
  74.             return node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py" in render
  124.         return compiled_parent._render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in _render
  134.         return self.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  830.                 bit = self.render_node(node, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py" in render_node
  74.             return node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  1146.                     context[self.target_var] = func(*resolved_args, **resolved_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django_pagemore-0.1.0-py2.7.egg/pagemore/templatetags/pagemore.py" in more_paginator
  131.     return paginator.get_context_data()
File "/usr/local/lib/python2.7/dist-packages/django_pagemore-0.1.0-py2.7.egg/pagemore/templatetags/pagemore.py" in get_context_data
  27.         objects, next_val = self.paginate()
File "/usr/local/lib/python2.7/dist-packages/django_pagemore-0.1.0-py2.7.egg/pagemore/templatetags/pagemore.py" in paginate
  106.         objects = self.objects[page0*self.per_page:1+page*self.per_page]

Exception Type: TypeError at /es/
Exception Value: 'itertools.chain' object has no attribute '__getitem__'
pennersr commented 11 years ago

The filtering strategy (see README) only supports true querysets, as it leaves it up to the DB to retrieve the proper objects for the page. This will not work when you start chaining together things.

So, your best bet is to use the slicing strategy. This has been tested with both lists and querysets. To make it work with iterators you may need to detect the iterator and turn it into a list so that it can be sliced, over here:

https://github.com/pennersr/django-pagemore/blob/master/pagemore/templatetags/pagemore.py#L106

caumons commented 11 years ago

I've done further investigations on this issue. At the moment of reporting it I was already using the slice strategy.

My conclusion is that using a chain object is "a pain in the ass". The main reason is than once you have iterated over its elements, you can't rewind the pointer, so you can't iterate it again and we need to do this here. So I'm afraid using chain objects would be a really hard implementation, if really possible. See following question in SO:

http://stackoverflow.com/questions/18232132/python-itertools-chain-object-has-no-attribute-getitem

Then, if chained objects are actually impossible to use, the best approach seems to be a real list object, containing the items to be paginated (not querysets). The main problem here is the high use of memory if there are thousands of records involved. In the following question in SO (below), I haven't found a better way to do this than using lists. What I'm doing now to avoid really huge use of resources is to actually limit the queries, before calling list on the chained querysets.

items_to_paginate = list(itertools.chain(queryset_1, queryset_2, queryset_3))

http://stackoverflow.com/questions/18235419/how-to-chain-django-querysets-preserving-individual-order