16

I'm new to Django and MPTT and having hard time figuring out how to get all leaf nodes and send them directly to Form class. For example, I have created MPTT Category Model, and have hierarchy like this:

  • Category1
    • Category2
    • Category3
  • Category4
    • Category5
    • Category6

So I want only to get leaf categories(cat2,3,5,6).My Form class looks something like this:

class UploadForm(forms.Form):
    description = forms.CharField(max_length=50)
    category = mpttform.TreeNodeMultipleChoiceField(queryset=Category.objects.all())
    file = forms.FileField() 

And with queryset=Category.objects.all() I get exactly the same thing above - all Categories and its children.Is there a way I can get only leaf nodes(children), but leaf nodes from ALL categories, not from specific Category instance ? Thanks.

Zed
  • 5,683
  • 11
  • 49
  • 81

5 Answers5

21

not used django mptt in a while, but given that a leaf node may be identified by right == left + 1, you should be able to filter for this using an F() expression

second
  • 28,029
  • 7
  • 75
  • 76
  • 8
    Thanks!The solution is Category.objects.filter(lft=F('rght')-1) – Zed Jun 02 '12 at 15:10
  • I thought this was working for me w/ Django 1.4.5 & Django MPTT 0.5.5, but realized it was still returning root nodes. Looks like Category.objects.filter(level__gt=0) is a better way, no? – Nate Beaty Mar 08 '13 at 19:36
15
Category.objects.filter(children__isnull=True)
Arpit Singh
  • 3,387
  • 2
  • 17
  • 11
  • I don't know if this solution has any performance hits, but this is simple and straightforward! To be clear `children` in this case is the `related_name` of whatever you called your parent relationship on the MPTT model. – RSmithlal Jun 19 '20 at 21:02
2

Unoptimal solution:

Category.objects.filter(id__in=[category.id for category in Category.objects.all() if category.is_leaf_node()])
MrKsn
  • 1,185
  • 1
  • 16
  • 27
0

My little snippet for django mptt

from django.db import models

class CategoryManager(models.Manager):
    def get_leaf(self, level=2):
        return self.filter(level__lte=level).order_by('tree_id','lft').all()

class Category(models.Model):
     objects = CategoryManager()

profit, use it: Catalog.objects.get_leaf()

0xdeface
  • 259
  • 2
  • 11
0

From docs:

is_leaf_node()

Returns True if this model instance is a leaf node (it has no children), False otherwise.

D Kuzmanovic
  • 35
  • 1
  • 5