views:

542

answers:

3

What is the correct way to do conditional formatting in Django?

I have a model that contains a date field, and I would like to display a list of records, but colour the rows depending on the value of that date field. For example, records that match today's date I want to be yellow, records that is before today I want green and ones after I want red.

Somewhere in Django you will need to do that comparison, comparing the current date with the date in the record.

I can see three different places that comparison could be done:

  1. Add a method to my model, for example, status(), that returns either 'past', 'present', 'future' and then use that in the template to colour the rows.
  2. In the view instead of returning a queryset to the template, pre-process the list and compare each record, build a new dict containing the 'past', 'present' and 'future' values to be used in the template
  3. Create a new template tag that does the comparison.

Which of these methods is the correct Django way of doing it? It sounds like conditional formating is something that would come up quite often, and since you can't do arbitrary comparisons in the template some other solution is needed.

The same would apply for simpler formatting rules, for example, if I wanted to display a list of student grades, and I wanted to make the ones higher than 80% green and the ones below 30% red.

+1  A: 

Since you are doing static comparison (no queries needed), you should go for the most DRY and easy to implement option. In this case, I would go for option 4, make a template filter. Then you could do value|filter to get the class you would need to set the background colour. Template filters are actually a bit simpler than template tags to implement.

googletorp
+1  A: 

I had a very similar requirement; as this is pretty connected to the business logic, I have added a model method to manage this kind of information, to be used then in the template:

{% if not bug.within_due_date %}bgcolor="OrangeRed"{% endif %}

It could also be obtained through a template tag or filter; but in my case, I felt the best place for the logic was inside the model; I would suggest you analyzing it in the same way.

Roberto Liffredo
+4  A: 

I'm a big fan of putting ALL "business" logic in the view function and ALL presentation in the templates/CSS.

Option 1 is ideal. You return a list of pairs: ( date, state ), where the state is the class name ("past", "present", "future").

Your template then uses the state information as the class for a <span>. Your CSS then provides the color coding for that span.

You are now free to change the rules without breaking the template. You can change the CSS without touching HTML or Python code.

{% for date,state in the_date_list %}
    <span class="{{state}}">date</span>
{% endfor %}
S.Lott
A good solution, however, with more than one model you would have to copy the model method over to every other model you want to do this with, making this route a bit wet.
googletorp
Either model inheritance or a utility function would reduce code duplication though.
andybak
@googletorp: The question didn't mention more than one model. The amount of code required for doing the assigning of class names is trivial and can certainly be either separate, reused function or part of a superclass.
S.Lott
Good solution but... Does it really cover the case when client side (browser) is in the different timezone than server (django server)? Would be interesting to know what's the best approach in the case if you need to do color-coding based on the client side time.
Oleg Sakharov