Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting and indexing into a list in a Django template?

How can you perform complex sorting on an object before passing it to the template? For example, here is my view:

@login_required
def overview(request):
   physicians = PhysicianGroup.objects.get(pk=physician_group).physicians

for physician in physicians.all():
    physician.service_patients.order_by('bed__room__unit', 'bed__room__order', 'bed__order')

return render_to_response('hospitalists/overview.html', RequestContext(request,  {'physicians': physicians,}))

The physicians object is not ordered correctly in the template. Why not?

Additionally, how do you index into a list inside the template? For example, (this doesn't work):

{% for note_type in note_types %}
   <div><h3>{{ note_type }}</h3>
   {% for notes in note_sets.index(parent.forloop.counter0) %}
   #only want to display the notes of this note_type!
      {% for note in notes %}
         <p>{{ note }}</p>
      {% endfor %}
   {% endfor %}
   </div>
{% endfor %}

Thanks a bunch, Pete

like image 770
slypete Avatar asked Jul 28 '09 01:07

slypete


3 Answers

As others have indicated, both of your problems are best solved outside the template -- either in the models, or in the view. One strategy would be to add helper methods to the relevant classes.

Getting a sorted list of a physician's patients:

class Physician(Model):
   ...
   def sorted_patients(self):
      return self.patients.order_by('bed__room__unit',
                                    'bed__room__order',
                                    'bed__order')

And in the template, use physician.sorted_patients rather than physician.patients.

For the "display the notes of this note_type", it sounds like you might want a notes method for the note_type class. From your description I'm not sure if this is a model class or not, but the principle is the same:

class NoteType:
   ...
   def notes(self):
      return <calculate note set>

And then the template:

{% for note_type in note_types %}
   <div><h3>{{ note_type }}</h3></div>
   {% for note in note_type.notes %}
      <p>{{ note }}</p>
   {% endfor %}
   </div>
{% endfor %}
like image 57
John Avatar answered Nov 14 '22 23:11

John


"I'd like to do this from within a template:"

Don't. Do it in the view function where it belongs.

Since the question is incomplete, it's impossible to guess at the data model and provide the exact solution.

results= physician.patients.order_by('bed__room__unit', 'bed__room__order', 'bed__order')

Should be sufficient. Provide results to the template for rendering. It's in the proper order.

If this isn't sorting properly (perhaps because of some model subtletly) then you always have this kind of alternative.

def by_unit_room_bed( patient ):
    return patient.bed.room.unit, patient.bed.room.order, patient.bed.order

patient_list = list( physician.patients )
patient_list.sort( key=by_unit_room_bed )

Provide patient_list to the template for rendering. It's in the proper order.

"how do you index into a list inside the template"

I'm not sure what you're trying to do, but most of the time, the answer is "Don't". Do it in the view function.

The template just iterate through simple lists filling in simple HTML templates.

If it seems too complex for a template, it is. Keep the template simple -- it's only presentation. The processing goes in the view function

like image 27
S.Lott Avatar answered Nov 14 '22 22:11

S.Lott


You should be able to construct the ordered query set in your view and pass it to your template:

def myview(request):
    patients = Physician.patients.order_by('bed__room__unit', 
                                           'bed__room__order', 
                                           'bed__order')
    return render_to_response('some_template.html',
                              dict(patients=patients), 
                              mimetype='text/html')

Your template can then loop over patients which will contain the ordered results. Does this not work for you?

EDIT: For indexing, just use the dot syntax: mylist.3 in a template becomes mylist[3] in python. See http://docs.djangoproject.com/en/dev/ref/templates/api/#rendering-a-context for more information.

like image 27
ars Avatar answered Nov 14 '22 23:11

ars