On Sun, Apr 3, 2011 at 11:46 PM, Gregor Müllegger <gre...@muellegger.de> wrote:
> Hi,
>
> 2011/4/2 Russell Keith-Magee <russ...@keith-magee.com>:
>> On Fri, Apr 1, 2011 at 11:57 PM, Gregor Müllegger <gre...@muellegger.de> 
>> wrote:
>> Firstly, while it looks fine for a small example, I can see how it
>> would rapidly deteriorate if you have lots of fields, or lots of
>> custom field requirements for each field. Django's template language
>> doesn't allow you to split tags over multiple lines, so what happens
>> when my tag runs over 80 characters (this simple example is already a
>> 69 characters)?
>
> (Having the possibility of multiline tags would be nice in many other cases as
> well ... but that's another topic :-)

I'm not convinced it would be nice. Template tags are intended to be
short and pithy, not space in which you can define your own
domain-specific language. My feeling is that if a template tag
proposal needs to invoke the "if only tags could span multiple lines"
clause, the tag is already doing too much in it's definition.

The one exception I will grant to this is comments -- requiring {%
comment %} {% endcomment %}, or {# #} on every line is just daft,
IMHO. However, it's a daftness that hasn't progressed into enough of
an itch to drive me to scratch it myself. It's also unrelated to your
proposal :-)

> I don't see the use of more than two or three modifiers in a template tag in a
> day to day use.

Well.. I gave you an example -- a form with 10 fields, and I want to
render 8 of them.

> However it's of course possible to produce complex statements
> that would need to span multiple lines. And it's already possible with the
> syntax described in the proposal.
>
> You can use a {% formblock %} to extract the modifiers out of the form tag:
>
>    {% formblock using layout "uni_form" %}
>    {% formblock using widget template "calendar" for myform.birthday %}
>        {% form myform using fields "firstname" "lastname" "birthday" %}
>    {% endformblock %}
>    {% endformblock %}
>
> Some might not like the syntax since you would encourage another level of
> indention and another two lines for the closing tags. But you can use the
> "configure" statement as described in the media handling section of my
> proposal:
>
>    {% form myform configure layout "uni_form" %}
>    {% form myform configure widget template "calendar" for myform.birthday %}
>    {% form myform using fields "firstname" "lastname" "birthday" %}

I hadn't quite grasped how you were using formblock in your previous
example. I now see what you're trying to do, and it makes a lot more
sense. However, I'm not completely sold on certain aspects of this
syntax.

In particular, I have two objections:
 * it feels like it's trying to cram too much into a single template tag.
 * it requires a lot of duplication of "form myform configure" or
"formblock myform using"

Consider a slight variation that uses more tags:

{% form myform configure %}
    {% layout "uni_form" %}
    {% widget "calendar" for DateField %}
    {% autocomplete "lastname" from "/users/lastnames" %}
{% endform %}

Then, when it comes time to render:

{% form myform using %}
    {% field "firstname" %}
    <p>And some HTML decoration</p>
    {% field "lastname" %}
{% endform %}

or, using an iterative approach:

{% form myform using %}
    {% for field in myform %}
        {% field field %}
    {% endfor %}
{% endform %}

or, using default layout:

{% form myform %}

This approach:
 * cuts down on the duplication, either in the form of indented form
blocks, or in duplicated 'tag opening' content
 * avoids the need for a DSL embedded in the tag definition
 * avoids potential grammar ambiguities -- the less grammar there is
in a tag, the less likely there will be edge cases in the parsing.

>> Secondly, you appear to be using a single template tag for rendering
>> both forms *and* fields. Is there a motivation behind this?
>
> Yes there is :-) The motiviation is, that {% form myform.birthday %} is just a
> shorthand for {% form myform using fields "birthday" %}. You can also use it
> to iterate over a form (like in your example below) and outputting it field by
> field:
>
>    {% for field in myform %}
>        {% form field %}
>    {% endfor %}
>
> I also don't see a need for an extra {% formfield %} tag. I don't see any
> cases in which a {% formfield %} would be shorter, more flexible, easier to
> use. It might be more readable, but I think it would end up as a stripped down
> copy/alias of the form tag.

See my previous comments about cramming everything into a single tag.
Also, there's an implementation issue here; if the first argument to
form can be a field or a form, then your implementation will need to
have logic to differentiate the two -- either isinstance checks, or
duck-type checks. Either way, it's a problem that is avoided by being
explicit: {% form %} operates on forms, {% field %} operates on
fields.

>> Rendering modifiers
>> ~~~~~~~~~~~~~~~~~~~~
>>
> But like I already wrote above: I see your concerns with adding yet another
> registry that might not be used very often. I would agree on dropping that
> feature if you think its better to skip this until users demand it afterwards.

I think this might be the better approach. Your proposal is already
fairly ambitious, especially if it's going to include a reworking of
admin's rendering. And, to that end, reworking admin's rendering
should prove a useful testbed for whether it is needed at all.

Also -- some food for thought; the reason that a registry is needed
here is because you're defining an extension api for a monolithic {%
form %} tag. If the rendering strategy used multiple tags, modifiers
could also be defined as template tags:

{% form myform %}
    {% mymodifier foo %}
{% endform %}

Then you don't need a separate registry; a "modifier" just becomes a
template tag operating on the API exposed by the form rendering API
(presumably a set of known objects in the local context of the form
tag). If an end user wants a rendering modifier, they just define
their own template tag and use it in a {% form configure %} block.

>> Form rows
>> ~~~~~~~~~
>>
>> If you look at the existing as_* form layout tools, there is a
>> distinction between gross form layout, and the layout of an individual
>> form row.
>>
>> {{ form_header }}
>> {% for field in form %}
>>    {{ pre_field }}}
>>    {{ field }}
>>    {{ post_field }}
>> {% endfor %}
>> {{ form_footer }}
>>
>> Conceptually, the rendering for pre/post field could vary depending on
>> the field. How is this handled in your proposal? Is it part of the
>> form renderer? Or part of the widget rendering? This overlaps with
>> your discussion about error templates -- since errors (and their
>> rendering) is one of the major pre/post rendering activities for both
>> forms and fields.
>
> I'm not sure if I get your example right. Is it representing the output of a
> "as_*" method? I looked into the django/forms/forms.py code again and I'm
> quite sure that there is no header or footer of a form rendered. I also don't
> see many usecases of including a header and a footer into the layout (like a
> wrapping <table> or <ul> element) since this is very different from form to
> form. One might want the wrapping <table> the other wants to put two forms
> into one <table> element etc.

I wasn't thinking so much about the <table> rendering, as some of the
other non-row rendering details.

For example, non-form errors currently have a rendering style that is
defined in code (although they are programmatically exposed in a way
that makes them compatible with templates). This is something that
isn't definable on a per-row basis, but it is tied to a form.

A second example -- handling of hidden fields. Again, these aren't
strictly row-based, but they do impact on the rendering of the form as
a whole.

> The rest of the example in between would be rendered in the "row.html"
> template of the form layout. E.g. the forms/layouts/table/row.html might look
> like:
>
>    <tr><th>{{ field.label_tag }}</th>
>    <td>
>        {{ field.errors }}
>        {{ field }}
>        {{ field.help_text }}
>    </td></tr>
>
> So you could define any pre_field and post_field stuff you want. I have also
> not found a case in which the current rendering makes decisions based on the
> field type. I think the admin does it (e.g. for checkboxes) but also in the
> template level? Maybe you can give me a more specific hint on what you mean.

Exceptions in radiobutton and checkbox rendering have historically
been the thorn in my side whenever I look at Django's form library, so
I'm just trying to think outside the box and think of the ways people
may want to twist form rendering. I don't really have a specific use
case in mind here.

>> CSS/Media
>> ~~~~~~~~~
>>
>> I'm not wild about the idea of having to include the same form content
>> twice in order to get CSS and JS included as where it is required.
>
> What do you mean by including the same form content twice? Do you mean the
> duplicate use of the form tag? I thought I had solved this via the "configure"
> statement. This will record all the used options so that you don't have to
> duplicate the changes made to the form.

Understood -- the flaw was in my understanding of your proposal.

>> Secondly, it may be possible to play a trick on the template compiler.
>> Jonas Obrist suggested this trick to me at Djangocon (US) last year;
>> however, I haven't had a chance to dig into it any more.
...
> That sounds HUGE and pretty cool. I had something like this in mind but
> skipped the idea quickly because I thought that it's not be possible.
> Especially with template inheritance. But if thats really possible
> (theoretically) ... I will at least try it out since it would solve the media
> handling problem in a very elegant way for the user.

Its certainly worth a couple of days investigation to see if it's
possible or plausible.

Two more thoughts that have occurred to me:

Firstly, from the point of view of proving the viability of your API,
it might be worth collecting a selection of pathological use cases
that can be used as a testbed. For example:

 * A form with 30 widgets
 * A form with only hidden widgets
 * A form with multiple date widgets, all using a calendar widget
except for the last one
 * A page that contains two forms

In effect, this is a set of conceptual test cases for your API -- in
fact, it might even form the basis for your programatic test suite.

Secondly: formsets. Are you intending to tackle formsets in this
proposal? It's ok if you don't -- omitting formsets would be a good
way to limit scope for the purposes of GSoC. However, I suspect the
formset use case will ultimately be important for trunk inclusion.
Even if you're not intending to tackle formsets, it's probably worth
mentioning them in your proposal.

In summary: I think you've got a strong proposal here. I've also taken
a look at your new proposal timeline, and it looks good to me. There
are certainly details to work out, and although they may appear
significant on first impression, I think they're mostly cosmetic. A
decision about using nested multiple tags or a single tag will
certainly affect your implementation, but doesn't fundamentally alter
the idea that you're driving at here: customizing the form rendering
using templates. As long as your submission acknowledges the fact that
there are some API issues still need to be resolved, I think your
proposal is in reasonably good shape.

Good luck with your final submission!

Yours
Russ Magee %-)

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

Reply via email to