5
\$\begingroup\$

The main view in my (toy!) Todo app is, of course, to display the list of tasks. These are grouped by some criterion, and the tasks structure below is actually a list of pairs (header, list of tasks).

{% for tasks in tasks %}
    <p class="list-header">{{ tasks.0 }}:</p>
    <ul>
    {% for t in tasks.1 %}
        <li>
            <span class="
                {% if t.priority >= 1 %}prio-medium{% endif %}
                {% if t.priority >= 2 %}prio-high{% endif %}
                ">
                {{ t.description }}
            </span>
            {% if t.due_date %}
                due, 
                <span class="
                    {% if t.days_to_due_date < 15 %}date-soon{% endif %}
                    {% if t.days_to_due_date < 3 %}date-very-soon{% endif %}
                    {% if t.days_to_due_date < 0 %}date-overdue{% endif %}
                    ">
                    {{ t.relative_due_date }}
                </span>
            {% endif %}
            - 
            {% if not t.done %}
                <a href="/yata/{{ t.id }}/mark_done/">Done!</a>
            {% else %}
                <a href="/yata/{{ t.id }}/mark_not_done/">Not done!</a>
            {% endif %}
            - 
            <a href="/yata/{{ t.id }}/edit/">Edit</a>
        </li>
    {% endfor %}
    </ul>
{% empty %}
    <p class="list-header">Cool! Nothing to do...</p>
{% endfor %}

In particular, I'm wondering if deciding which CSS class to assign is considered to be the view function's role, or if it's correct to put it in the template.

Similarly, I'm also wondering about the presence of several URLs in the template. Would they be better in the tasks structure itself? Or should they be provided through some methods in the Task class? After all, relative_due_date is already a function that's only used for display (it returns a string like 'Yesterday', 'Tomorrow' or 'In 3 days'). And shouldn't I use reverse()?

\$\endgroup\$
5
\$\begingroup\$
  1. I would suggest moving the CSS selection logic to a custom template tag or even a filter, e.g. <span class="{{ t|due_date_color }}">{{ t.relative_due_date }}</span>. After that your templates will look much cleaner and that logic would still belong to the presentation part of MVT (Model, View, Template).

  2. You can split your tuple in the definition of the loop so that you don't redefine the tasks variable. {% for header, task_list in tasks %} ....

  3. Use reverse URLs, no question about it. You'd hate the day you have to change them otherwise :) Go even further, use URL namespaces.

\$\endgroup\$
3
\$\begingroup\$

I'd only add one thing to rassie's great list: while choosing which CSS class to assign to tasks that are due "soon" certainly belongs to the presentation layer (view or template), the fact that tasks due between 4 and 14 days from now are due "soon" belongs to the model. If each task here is an object, you can add isDueSoon(), isDueVerySoon(), and isOverdue() to encapsulate this logic in one logical place.

You'll be happy you did this when you write unit tests for your task class and again when your boss asks you to build a REST API for working with tasks from a native iPhone app.

\$\endgroup\$
1
\$\begingroup\$

I would move that conditional logic in the span tags to the view. Have your view pass the template a modified version of tasks.1, where each task instead of being the original datum is now the modified version that the template could use raw. For example, instead of passing your template t.priority as an integer, pass it as the actual CSS class that you'll be using. Same as t.days_to_due_date.

Personally, I hate editing templates, because I haven't configured my text editor to play nice with them yet :-). As a consequence, I usually move everything out of the template and into the view that I can. Same situation with your URL's. I'm not sure if this is best practice, but I like to leave my template as clean as possible.

As for your question about reverse(), I'd have to have more context to answer.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.