views:

602

answers:

2

Hi all,

I've got a django model that contains a manytomany relationship, of the type,

class MyModel(models.Model):
  name = ..
  refby = models.ManyToManyField(MyModel2)
  ..

class MyModel2(..):
  name = ..
  date = ..

I need to render it in my template such that I am able to render all the mymodel2 objects that refer to mymodel. Currently, I do something like the following,

{% for i in mymodel_obj_list %}
  {{i.name}}
  {% for m in i.refby.all|dictsortreversed:"date"|slice:"3" %}
    {{.. }}
  {% endfor %}
  <div> <!--This div toggles hidden/visible, shows next 12-->
   {% for n in i.refby.all|dictsortreversed:"date"|slice:"3:15" %}
     {{.. }}
   {% endfor %}
  </div>
{% endfor %}

As the code suggests, I only want to show the latest 3 mymodel2 objects, sorted in reverse order by date, although the next 12 do get loaded.

Is this a very inefficient method of doing so? (Given that results for the refby.all could be a few 100s, and the total no of results in "mymodel_obj_list" is also in 100s - I use a paginator there).

In which case, whats the best method to pre-compute these refby's and render them to the template? Should I do the sorting and computation in the view, and then pass it? I wasn't sure how to do this in order to maintain my pagination.

View code looks something like,

obj_list = Table.objects.filter(..) # Few 100 records
pl = CustomPaginatorClass(obj_list...)

And I pass the pl to the page as mymodel_obj_list.

Thanks!

A: 

Should I do the sorting and computation in the view, and then pass it?

Yes, definitely.

It is not really a matter of performance (as Django's querysets are lazily evaluated, I suspect the final performance could be very similar in both cases) but of code organization.
Templates should not contain any business logic, only presentation. Of course, sometimes this model breaks down, but in general you should try as much as possible to keep into that direction.

Roberto Liffredo
Right. However, I'm still not too clear about the mechanics of passing this data in.. Given that mymodel.refby.all contains all of the references - how do I presort this information and pass it to mymodel?Perhaps keep a new class variable?
viksit
+3  A: 

I assume mymodel_obj_list is a QuerySet. You're accessing a foreign key field inside the loop, which means, by default, Django will look up each object's refby one at a time, when you access it. If you're displaying a lot of rows, this is extremely slow.

Call select_related on the QuerySet, to pull in all of these foreign key fields in advance.

http://docs.djangoproject.com/en/dev/ref/models/querysets/#id4

Glenn Maynard
Thanks! That looks exactly like what I need.. I'll check it out
viksit