Should Django be HTML agnostic?

5 views
Skip to first unread message

Rob Hudson

unread,
Jan 11, 2007, 12:42:34 AM1/11/07
to Django developers
I posted a bug (http://code.djangoproject.com/ticket/3280) before I
left work which quickly got shot down by Adrian. :) He's right in
that it's a pretty general bug so I bring the conversation here. I'm
curious what the Django devs will make of my reasoning...

I realize some of these aren't directly related to whether Django
itself prefers XHTML. Some are more along the lines of how easy it
should be to work around Django if you prefer HTML4.

The following are what I think are valid reasons why Django should be
HTML agnostic.

1. Display code should be separate from logic. Ideally, all HTML would
be in template files that one could override if need be in their own
template directory, just like the admin templates. If django.forms did
this, that would be great. The only consideration I can think of is
what kind of load would this be to necessitate a file system call to
pull in the widget template or error template?

2. The argument against #1 that I've seen is usually that you can
subclass Something and write your own output. But in some ways, this
violates the DRY principle. The code to output a form widget, for
example, is already written, and in looking at what it would take, the
only change in the render() method would be the change of the HTML
itself.

3. Better "updatability": If there is a bug in Select(Widget) that was
fixed but I have MySelect(Widget) which is mostly the same except for
the HTML, I wouldn't get the fix unless I noticed and updated my code
as well. Whereas if Select(Widget) pulled in a template and I overrode
that template, the fix would come down just fine across all my
projects.

4. One of the reasons I've seen touted for the template system not
having access to Python methods and having it's own language is the
benefit of separating the programmer from the designer and that
designers shouldn't need to know Python to create templates in Django.
But they would if they want to manipulate forms or form error feedback.
This should be consistent.

If there's agreement, I'd be happy to help in the effort to make this
happen. Initially I suppose the discussion is whether this is worth it
at all. I also grepped the code looking for HTML tags and besides a
few places (the Django error page, for example) this is directed at
django.forms (newforms).

Thanks,
Rob

Michael Radziej

unread,
Jan 11, 2007, 10:24:15 AM1/11/07
to django-d...@googlegroups.com
Rob Hudson schrieb:

> I realize some of these aren't directly related to whether Django
> itself prefers XHTML. Some are more along the lines of how easy it
> should be to work around Django if you prefer HTML4.
>
> The following are what I think are valid reasons why Django should be
> HTML agnostic.

I'm not sure what you mean exactly with "HTML agnostic". Could you
explain it, please?


So long,

Michael
--
noris network AG - Deutschherrnstraße 15-19 - D-90429 Nürnberg -
Tel +49-911-9352-0 - Fax +49-911-9352-100

http://www.noris.de - The IT-Outsourcing Company

Andrew Durdin

unread,
Jan 11, 2007, 10:32:27 AM1/11/07
to Django developers
Rob Hudson wrote:
>
> 1. Display code should be separate from logic. Ideally, all HTML would
> be in template files that one could override if need be in their own
> template directory, just like the admin templates. If django.forms did
> this, that would be great.

The forms framework I wrote out of frustration with django.[old]forms
did this. I ended up with a number of tiny one-line templates. The
template for a TextField, for example, was:

<input type="{{ input_type|escape }}" id="{{ id|escape }}" class="{{
class_names|join:" "|escape }}" name="{{ widget_name|escape }}"
size="{{ size|escape }}" value="{{ data|escape }}" {% if maxlength
%}}maxlength="{{ maxlength|escape }}"{% endif %}{% if widget.readonly
%} readonly="readonly"{% endif %}{% if widget.disabled %}
disabled="disabled"{% endif %}/>

My motivation for this change was less to allow the use of valid HTML
(instead of XHTML), but to allow site-wide customisation of form
elements (i.e. in ways beyond what CSS can do).

> The only consideration I can think of is
> what kind of load would this be to necessitate a file system call to
> pull in the widget template or error template?

I don't think that's generally an issue. If the Template instance is
cached in the Widget instance, then each widget's template file need
only be loaded and parsed once; and I don't expect the extra rendering
will be a significant issue.

> 4. One of the reasons I've seen touted for the template system not
> having access to Python methods and having it's own language is the
> benefit of separating the programmer from the designer and that
> designers shouldn't need to know Python to create templates in Django.
> But they would if they want to manipulate forms or form error feedback.
> This should be consistent.

This is IMO the best argument for this change. Being able to have a
custom (but consistent site-wide) display of form labels & errors with
only template overrides would be very nice indeed.

Andrew

Rob Hudson

unread,
Jan 11, 2007, 11:18:02 AM1/11/07
to Django developers
Michael Radziej wrote:
> I'm not sure what you mean exactly with "HTML agnostic". Could you
> explain it, please?

Just that Django shouldn't favor XHTML over HTML4. But I'm actually
not too concerned if it comes with django.forms that default to XHTML,
but they are easily configurable or easy to override via templates. So
the title is a bit of a misnomer -- the bullet points explain what I'm
after better.

Cheers!

Waylan Limberg

unread,
Jan 11, 2007, 1:08:41 PM1/11/07
to django-d...@googlegroups.com
On 1/11/07, Andrew Durdin <adu...@gmail.com> wrote:
>
> Rob Hudson wrote:
> >
> > 1. Display code should be separate from logic. Ideally, all HTML would
> > be in template files that one could override if need be in their own
> > template directory, just like the admin templates. If django.forms did
> > this, that would be great.
>
> The forms framework I wrote out of frustration with django.[old]forms
> did this. I ended up with a number of tiny one-line templates. The
> template for a TextField, for example, was:
>
> <input type="{{ input_type|escape }}" id="{{ id|escape }}" class="{{
> class_names|join:" "|escape }}" name="{{ widget_name|escape }}"
> size="{{ size|escape }}" value="{{ data|escape }}" {% if maxlength
> %}}maxlength="{{ maxlength|escape }}"{% endif %}{% if widget.readonly
> %} readonly="readonly"{% endif %}{% if widget.disabled %}
> disabled="disabled"{% endif %}/>
>
Well if we look at the render method of a basic Input widget [1]:

74 def render(self, name, value, attrs=None):
75 if value is None: value = ''
76 final_attrs = self.build_attrs(attrs, type=self.input_type,
name=name)
77 if value != '': final_attrs['value'] = smart_unicode(value)
# Only add the 'value' attribute if a value is non-empty.
78 return u'<input%s />' % flatatt(final_attrs)

It should be easy to see that passing final_attrs into Andrew's
template would give the desired result (perhaps with a few
adjustments. It shouldn't be to hard for someone to hack up such a
variation. Then when defining the form, just point to the custom
widgets.

That said, Adrian pointed out elseware that he does not want to tie
the forms to the template system (keeping everything modular) which I
understand. However, if there was a way to pass final_attrs for each
field in a form to the template (perhaps as an optional behavior),
that would give template authors complete control over the layout of
their forms. Perhaps something like:

<input type="{{ form.somefield.input_type|escape }}" id="{{
form.somefield.id|escape }}"...

Throw in a few for loops and anyone could do whatever they wanted for
markup, maybe even use it with something other than (x)html.

Of course, when the template author just uses {{ form.somefield }} we
still get the current behavior. That will likely require most of the
code in `render` to be extracted out leaving `render` to just be the
final line, which would make overriding `render` as easy as
overriding the as_*() methods (as_p() as_ul() ...).

Any thoughts?

[1]: http://code.djangoproject.com/browser/django/trunk/django/newforms/widgets.py
--
----
Waylan Limberg
way...@gmail.com

Waylan Limberg

unread,
Jan 11, 2007, 1:39:16 PM1/11/07
to django-d...@googlegroups.com
On 1/11/07, Waylan Limberg <way...@gmail.com> wrote:

> However, if there was a way to pass final_attrs for each
> field in a form to the template (perhaps as an optional behavior),
> that would give template authors complete control over the layout of
> their forms.

I thing I approached that kind of backwards. Let me try another way:

So summarize the basics that everyone already knows: Currently, if a
Form instance is passed in the context to the template as `form`, if
we have:

{{ form }}

The entire form gets rendered (using as_table()). If we do:

{{ form.as_p }}

Then the whole form gets rendered using as_p(). Yet, for finer grained
control, if we do:

{{ form.field1 }}
{{ form.field2 }}
{{ form.field3 }}

or, perhaps more simply:

{{ for field in form }}
{{ field }}
{{ endfor }}

Then each field gets rendered with any surrounding html defined only
in the template.

Why not take that a step further and allow something like this:

{{ for field in form }}
{{ ifequal "text" field.input_type }}
<input type="{{ field.input_type }}" id="{{
field.id }}" ... />
{{ endif }}
{{ endfor }}

or perhaps:

<input {{ form.field1.flat_attrib }}>

James Bennett

unread,
Jan 11, 2007, 2:15:28 PM1/11/07
to django-d...@googlegroups.com
On 1/11/07, Waylan Limberg <way...@gmail.com> wrote:
> It should be easy to see that passing final_attrs into Andrew's
> template would give the desired result (perhaps with a few
> adjustments. It shouldn't be to hard for someone to hack up such a
> variation. Then when defining the form, just point to the custom
> widgets.

What worries me about this is that it becomes not a case of
configuration, but a case of "rewrite the widget classes and never use
the built-in versions". Which isn't something I particularly want to
do in order to coerce HTML4 out of newforms.

--
"May the forces of evil become confused on the way to your house."
-- George Carlin

Rob Hudson

unread,
Jan 11, 2007, 3:56:24 PM1/11/07
to Django developers
I think it's in the other thread, but what's the reason for wanting to
decouple forms from templates? I can think of 2 reasons:

1) Decoupling means you can change the way templates work and not have
to update the forms code. Counter argument: If you change the way
templates work you'd break a lot more than forms so this will likely be
a non-BC thing to do anyway. In and of itself, this isn't a great
argument against keeping things decoupled.

2) Allow the form widgets to be used outside of Django. If this is the
case, could it be that Django defaults to importing django.templates.
If that errors out, use standard Python Template Strings as a fall
back?


Another question. What would it look like if form HTML output type was
a config setting?

DEFAULT_HTML_DOCTYPE = "HTML4"

Then Django supports the common ones: XHTML and HTML4 (and others when
they come along). It's extra code for every HTML type but it keeps
things decoupled.

This still doesn't accomplish letting designers design forms by
changing templates, which I think is a good argument for widget
templates.

-Rob

Steve Hutton

unread,
Jan 14, 2007, 1:13:44 AM1/14/07
to django-d...@googlegroups.com
On 2007-01-11, Rob Hudson <treborhudson-> wrote:
>
> 2. The argument against #1 that I've seen is usually that you can
> subclass Something and write your own output. But in some ways, this
> violates the DRY principle. The code to output a form widget, for
> example, is already written, and in looking at what it would take, the
> only change in the render() method would be the change of the HTML
> itself.
>
> 3. Better "updatability": If there is a bug in Select(Widget) that was
> fixed but I have MySelect(Widget) which is mostly the same except for
> the HTML, I wouldn't get the fix unless I noticed and updated my code
> as well. Whereas if Select(Widget) pulled in a template and I overrode
> that template, the fix would come down just fine across all my
> projects.

Yes, in more general terms, this design violates the Single
Responsibility Principle [1]; the method designed to be overridden
has more than one reason to change: framework driven fixes/enhancements,
and user level changes to the details of the presentation (e.g. markup
type)

Conveniently, templatizing the markup is a readily available design
alternative which cleanly separates the responsiblities.

> 4. One of the reasons I've seen touted for the template system not
> having access to Python methods and having it's own language is the
> benefit of separating the programmer from the designer and that
> designers shouldn't need to know Python to create templates in Django.
> But they would if they want to manipulate forms or form error feedback.
> This should be consistent.

I think this point also has significant merit.

Steve
[1] http://en.wikipedia.org/wiki/Single_responsibility_principle

Reply all
Reply to author
Forward
0 new messages