Search code examples
djangodjango-templatesdjango-mpttmptt

Django MPTT maximum elements in recursetree


Is there a way to present a partial tree using Django-MPTT's {% recursetree %} without retrieving the entire tree from database? I need to show the first 20 nodes encountered by a Depth First Search.

Either of these (which do not retrieve the full tree) cause an exception:

# resulting querySet passed to {% recursetree %} in template
Thing.objects.all()[:20]

# directly sliced in template
{% recursetree all_nodes|slice:":20" %} 

AssertionError while rendering: Cannot reorder a query once a slice has been taken.

This on the other hand does work, but retrieves the entire tree:

 # resulting querySet passed to {% recursetree %} in template
 list(Thing.objects.all())[:20]

How can I do this without retrieving the entire tree form the DB?


Solution

  • MPTT uses pre-order (which is a depth-first search already.) So all you need to do is add a limit to your queryset before passing it to recursetree.

    MPTT calls order_by() if you pass a queryset to recursetree, but it can't do that if you pass a list. That behaviour is kind of confusing and has caused other people issues too.

    I've created a ticket on MPTT to address this.

    In the meantime, you can just do the slicing before the list() call:

    list(Thing.objects.all()[:20])
    

    That will do the limit in the database, then convert the queryset to a list, which you can pass to recursetree without it trying to reorder things.