On Thu, 2007-08-23 at 21:59 +0800, Russell Keith-Magee wrote:
[...]
> Generally speaking - you don't.
> 
> This is by design. Django tries very hard to prevent you from putting
> logic into a template. Logic and calculations belong in the view; the
> template shouldn't have any need for calculations. If you maintain
> this strict separation, it becomes possible to change the template
> without altering the view, and vice versa.
> 
> To this end, the Django template language is not, nor will ever be a
> Turing complete programming language. We have specifically avoided
> adding arithmetic operations, etc.
> There are a few very basic math filters - but they exist only to
> support display-based calculations. How many pixels wide does this DIV
> need to be, given the size of its component parts - that sort of
> thing.
> 
> If you think you need to do arithmetic in a template - think really
> hard about what you are doing. Are you actually trying to change a
> display feature, or are you changing the information that is being
> displayed? If it is the latter, the calculation should be in the view.

Hello,

Interestingly (to me, at least), I'm having issues with this very design
decision right now. Please bear with me, because this is a rather long
response.

While in general I agree with the whole "logic in views and display in
templates" idea, there are some very practical situations in which this
simply becomes a pedantic pain. And while in general Django is a very
nicely practical (yet still elegant) framework, I have to say I dislike
this approach quite a bit.

Here's why:

Let's say I have a set of objects, let's call them Parrots. Each Parrot
has an id, natch.

Now in my template, I'm building a list of these Parrots, and each row
in the list has a button that selects that Parrot when clicked. In
general, in the Javascript and HTML, this looks like this:

Button.create = function(id, label) {
  some script to turn that DOM element into a DHTML button
}

<div class="parrotRow">
  <span id="parrotButton-1"></span>
  <script>Button.create('parrotButton-1', 'Choose me!');</script>
Hi, I'm the Parrot named Moe, and I'm #1!
</div>
<div class="parrotRow">
  <span id="parrotButton-2"></span>
  <script>Button.create('parrotButton-2', 'Choose me!');</script>
Hi, I'm the Parrot named Schmoe, and I'm #2!
</div>

And so on.

The template might look like this:

{% for parrot in parrots %}
<div class="parrotRow">
  <span id="parrotButton-{{ parrot.id }}"></span>
  <script>Button.create('parrotButton-2',{% trans 'Choose me!')</script>
Hi, I'm the Parrot named {{parrot.name}}, and I'm #{{ parrot.id }}!
</div>
{% endfor %}

All well and good. But now let's say I'm an appropriately (read:
responsibly) lazy programmer, and I wish to make a template tag that
outputs button code with a particular ID.

Easy, you say! {% myButton theId, 'Choose me!' %}, with the appropriate
Python code (and parsers, and so on) behind it.

As far as "Choose me!" goes, I can do the ugettext translation in the
tag, of course. However... the obvious problem becomes this: how do I
get "parrotButton-1" into theId? I don't want to hardcode
"parrotButton-" in the Python code, because when I have a list of tree
sloths on the same page, that won't make much sense (nor will it work if
we have both Parrot #1 and Sloth #1 on the same page). 

I could write (or find) a tag that concatenates two strings, and places
the result in the context:

{% cat currentId "parrotButton-" parrot.id %}
{% myButton currentId %}

But what happens when I add other spanky new parameters to my button
tag, like "buttonText" and "buttonClass" and so on? Now I have to first
run a bunch of (possibly) specialized tags to put the values in the
context, and then call the myButton tag.

This reminds me horribly of the Bad Old Days of JSP, which I am
desperately trying to forget.

Ah, you say, but you're doing this wrong! Put this into your view code!

And here (finally) we get to my response to this thread: why on earth
would I put *template specific* code into my view? Now, instead of
having only some Javascript and a template that knows how to manipulate
it by creating the appropriate HTML, I have some Javascript, a template,
and a view that all have to know that the Javascript wants
"parrotButton-" + parrot.id... not only is this a pain, but it's a bad
idea. DRY and all that. Not only not only that, but I also have to
iterate my Parrots twice: once to set a bunch of constructed button IDs
somewhere, and once in the template to print them all out.

However, I don't *want* code in my view that knows about what my
Javascript and my HTML are doing in the first place. The string
"parrotButton-" + parrot.id has absolutely nothing to do with the data.
The view should keep its hands out of this. This is not logic, it's not
a calculation other than in the most remotest sense, and I'd really,
really like to keep this particular construction as close to where it is
used as possible. I also don't want a function on the Parrot itself that
knows to create "parrotButton-" + self.id... that's just silly. In fact,
my view code really shouldn't care if it's using an HTML template with
"Choose me!" buttons, an Excel template with a "Choose me!" macro, an
email with a "Choose me!" link, or a pigeon-carrier-wave cuneiform
tablet template with, er, "Choose me!" sticky notes made of Leicester
cheese and tar. It provides data, and whiz-bango
ala-peanut-butter-sandwiches-with-mayo, the *template* takes care of the
*formatting* specific to the task at hand.

Now what I'd like to do is this:

{% myButton '${"parrotButton-" + parrot.id}' %}

Problem sorted, and astute (but possibly mentally-scarred) readers who
have used a certain language and framework will note that this is how
JSP solved this particular problem: by adding the EL language to JSP
tags. Things got much simpler and nicer at that point in JSP Land (which
is still populated by a number of trolls, ogres, and generally
foul-smelling beasties, but at least not this particular foul-smelling
beastie). Tags encapsulate reusable logic, templates call those tags
with whatever they feel like, and life goes on quite smoothly as long as
the tags call the proper parsing routines to make sure the EL gets taken
care of.

Now since we're in Python Land (which for the most part is populated
only by a number of very pleasant and polite snakes), this should be
quite easy. In fact if I wanted to I'm sure I could come up with a
parser for my tag that ran every parm through a special "try to execute
this as Python" thinger. Well. That's what JSP went through... however,
the final, logical step, was to place that parsing *in the template
parser* so that every tag didn't have to be responsible for anticipating
how the template writer wished to use it. Et voila. Tags are easy,
templates are easy, and stuff gets reused where it ought to be reused.

Now of course, people could possibly misuse this functionality (*shock*
*horror*!) to do nasty things like writing Django templates to calculate
their income taxes. So? Let them. You're not their mother, they're big
boys and girls (if a bit daft), and the people who know enough not to
misuse such a feature to do their taxes will get on grandly by using it
properly to create selectable Parrots and Sloths instead.

Sorry for the long-winded semi-diatribe, but in my defense I've been
beating my head against this exact problem for a good while now. I'd
love to use template tags to reduce my repetition and reuse solid code
all over the place, but I'm being frustrated by this singular lack of
functionality. I will say this, however: it is only because the rest of
the Django template functionality is so darn good that I'm not just
throwing up my hands and using Cheetah or what have you. I love {%
extends %}, and filters, and being able to parse my tags any way I wish.
I just need a bit more...

What I'm hoping, however, is that this missive was moot, because you'll
say, "no, Scott, you should just do *this*:", followed by an elegant and
reasonable solution that I, as a relative newcomer to Django, have not
yet considered. Here's to your reply, and cheers!

Regards,
-scott anderson




> Yours,
> Russ Magee %-)



--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to