Saqib Ali
Saqib Ali

Reputation: 12615

How to add custom data to Django MPTT model for recursetree template tag

This question about MPTT objects and usage of the {% recursetree %} template tag is related to this one.

My Django Model:

from mptt.models import MPTTModel, TreeForeignKey
class myModel(MPTTModel):
    myIntA = models.IntegerField(default=0)   
    myParent = TreeForeignKey('self', null=True, blank=True, related_name='children')

My View:

myModelList = myModel.objects.all()
for i in range(len(myModelList)):
    myModelList[i].myIntB = i

return render(
    request, 
    'myApp/myTemplate.html', 
    Context(
        {
            "myModels": myModelList,
        }
    )
)

Is the above legal? You can see that I added a variable myIntB to each myModel object. However when I try to print myIntB in the template below, nothing shows up.

How can I access myIntB from the template? It is not a field I have defined for this model, nor do I want it to be. I just want myModel to be augmented with this extra variable during rendering of this particular template. The problem is that I don't see anyway to do so with the recursetree template tag.

My Template:

{% load mptt_tags %}
<ul>
    {% recursetree nodes %}
        <li>
            {{node.id}} {{node.myIntA} {{node.myIntB}}
            {% if not node.is_leaf_node %}
                <ul>
                    {{ children }}
                </ul>
            {% endif %}
        </li>
    {% endrecursetree %}
</ul>

Upvotes: 0

Views: 1558

Answers (1)

craigds
craigds

Reputation: 2157

The recursetree tag calls .order_by on your queryset, if it's actually a queryset.

This copies the queryset, does another query and re-fetches all the objects from the database. Your extra attribute no longer exists on the new objects.

The easiest way to fix this is probably to call list() on your queryset before passing it to recursetree. Then mptt will assume the ordering is already done and won't re-order the queryset.

myModelList = list(myModel.objects.order_by('tree_id', 'lft'))
for i, obj in enumerate(myModelList):
    obj.myIntB = i

return render(
    request, 
    'myApp/myTemplate.html', 
    Context({"myModels": myModelList})
)

Upvotes: 1

Related Questions