Ticket #10590: nested_fieldsets.diff

File nested_fieldsets.diff, 9.0 KB (added by Archatas, 11 years ago)

The patch for nested fieldsets

  • django/contrib/admin/helpers.py

     
    4141    media = property(_media)
    4242
    4343class Fieldset(object):
    44     def __init__(self, form, name=None, fields=(), classes=(), description=None):
     44    is_fieldset = True
     45    def __init__(self, form, name=None, fields=(), classes=(), description=None, level=0):
    4546        self.form = form
    4647        self.name, self.fields = name, fields
    4748        self.classes = u' '.join(classes)
    4849        self.description = description
     50        self.level = level
    4951
    5052    def _media(self):
    5153        if 'collapse' in self.classes:
     
    5557
    5658    def __iter__(self):
    5759        for field in self.fields:
    58             yield Fieldline(self.form, field)
     60            if (len(field)==2 and isinstance(field[1], dict)):
     61                # nested fieldset
     62                yield Fieldset(self.form,
     63                    name=field[0],
     64                    fields=field[1].get("fields", ()),
     65                    classes=field[1].get("classes", ()),
     66                    description=field[1].get("description", ()),
     67                    level=self.level + 1,
     68                    )
     69            else:
     70                # field name or a tuple of field names
     71                yield Fieldline(self.form, field)
    5972
    6073class Fieldline(object):
    6174    def __init__(self, form, field):
     
    175188        for field in self.fields:
    176189            if fk and fk.name == field:
    177190                continue
    178             yield Fieldline(self.form, field)
     191            if (len(field)==2 and isinstance(field[1], dict)):
     192                # nested fieldset
     193                yield Fieldset(self.form,
     194                    name=field[0],
     195                    fields=field[1].get("fields", ()),
     196                    classes=field[1].get("classes", ()),
     197                    description=field[1].get("description", ()),
     198                    level=self.level + 1,
     199                    )
     200            else:
     201                # field name or a tuple of field names
     202                yield Fieldline(self.form, field)
    179203           
    180204class AdminErrorList(forms.util.ErrorList):
    181205    """
  • django/contrib/admin/media/css/forms.css

     
    123123    width: 450px;
    124124}
    125125
     126/* NESTED FIELDSETS */
     127
     128fieldset fieldset {
     129    margin: 10px;
     130}
     131
    126132/* COLLAPSED FIELDSETS */
    127133
    128134fieldset.collapsed * {
  • django/contrib/admin/templates/admin/includes/fieldset.html

     
    11<fieldset class="module aligned {{ fieldset.classes }}">
    2   {% if fieldset.name %}<h2>{{ fieldset.name }}</h2>{% endif %}
    3   {% if fieldset.description %}<div class="description">{{ fieldset.description|safe }}</div>{% endif %}
    4   {% for line in fieldset %}
    5       <div class="form-row{% if line.errors %} errors{% endif %} {% for field in line %}{{ field.field.name }} {% endfor %} ">
    6       {{ line.errors }}
    7       {% for field in line %}
    8       <div{% if not line.fields|length_is:"1" %} class="field-box"{% endif %}>
    9           {% if field.is_checkbox %}
    10               {{ field.field }}{{ field.label_tag }}
    11           {% else %}
    12               {{ field.label_tag }}{{ field.field }}
    13           {% endif %}
    14           {% if field.field.field.help_text %}<p class="help">{{ field.field.field.help_text|safe }}</p>{% endif %}
    15       </div>
    16       {% endfor %}
    17       </div>
    18   {% endfor %}
     2    {% if fieldset.name %}<h2>{{ fieldset.name }}</h2>{% endif %}
     3    {% if fieldset.description %}<div class="description">{{ fieldset.description|safe }}</div>{% endif %}
     4    {% for line in fieldset %}
     5        {% if line.is_fieldset %}
     6            {% include_parsed "admin/includes/fieldset.html" with line as fieldset %}
     7        {% else %}
     8            <div class="form-row{% if line.errors %} errors{% endif %} {% for field in line %}{{ field.field.name }} {% endfor %} ">
     9            {{ line.errors }}
     10            {% for field in line %}
     11                <div{% if not line.fields|length_is:"1" %} class="field-box"{% endif %}>
     12                  {% if field.is_checkbox %}
     13                      {{ field.field }}{{ field.label_tag }}
     14                  {% else %}
     15                      {{ field.label_tag }}{{ field.field }}
     16                  {% endif %}
     17                  {% if field.field.field.help_text %}<p class="help">{{ field.field.field.help_text|safe }}</p>{% endif %}
     18                </div>
     19            {% endfor %}
     20            </div>
     21        {% endif %}
     22    {% endfor %}
    1923</fieldset>
  • django/contrib/admin/util.py

     
    4747    field_names = []
    4848    for name, opts in fieldsets:
    4949        for field in opts['fields']:
    50             # type checking feels dirty, but it seems like the best way here
    51             if type(field) == tuple:
    52                 field_names.extend(field)
     50            if isinstance(field, (tuple, list)):
     51                if len(field)==2 and isinstance(field[1], dict):
     52                    # it's a nested fieldset
     53                    field_names.extend(flatten_fieldsets((field,)))
     54                else:
     55                    # it's a tuple of field names
     56                    field_names.extend(field)
    5357            else:
     58                # it's a field name
    5459                field_names.append(field)
    5560    return field_names
    5661
  • django/template/defaulttags.py

     
    88except NameError:
    99    from django.utils.itercompat import reversed     # Python 2.3 fallback
    1010
     11from django.template import loader, RequestContext, Template
    1112from django.template import Node, NodeList, Template, Context, Variable
    1213from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END, COMMENT_TAG_START, COMMENT_TAG_END
    1314from django.template import get_library, Library, InvalidTemplateLibrary
     
    432433        context.pop()
    433434        return output
    434435
     436class ParsedIncludeNode(Node):
     437    def __init__(self, tag_name, template_path, extra):
     438        self.tag_name = tag_name
     439        self.template_path = template_path
     440        self.extra = extra
     441    def render(self, context):
     442        template_path = self.template_path.resolve(context)
     443        context_vars = {}
     444        for d in list(context):
     445            for var, val in d.items():
     446                context_vars[var] = val
     447        for var, val in self.extra:
     448            context_vars[var] = val.resolve(context)
     449        return loader.render_to_string(template_path, context_vars)
     450
    435451#@register.tag
    436452def autoescape(parser, token):
    437453    """
     
    11711187    parser.delete_first_token()
    11721188    return WithNode(var, name, nodelist)
    11731189do_with = register.tag('with', do_with)
     1190
     1191#@register.tag
     1192def do_include_parsed(parser, token):
     1193    """
     1194    Parses the defined template with the current context variables and also the ones passed to the template tag. The included template might extend some other template.
     1195
     1196    Usage::
     1197
     1198        {% include_parsed <template_path> [with <value1> as <variable1>[ and <value2> as <variable2>[ and ...]] %}
     1199   
     1200    Examples::
     1201
     1202        {% include_parsed "people/item_person.html" %}
     1203        {% include_parsed path with membership.user.get_profile as person and membership.persongroup as persongroup %}
     1204
     1205    """   
     1206    bits = token.split_contents()
     1207    tag_name = bits.pop(0)
     1208    try:
     1209        template_path = bits.pop(0)
     1210        extra = [] # a tuple of variables names and values to parse before passing to the template
     1211        if bits:
     1212            bits.pop(0) # remove the word "with"
     1213            while bits:
     1214                val = bits.pop(0)
     1215                bits.pop(0) # remove the word "as"
     1216                var = bits.pop(0)
     1217                extra.append((var, parser.compile_filter(val)))
     1218                if bits:
     1219                    bits.pop(0) # remove the word "and"
     1220                   
     1221    except ValueError:
     1222        raise template.TemplateSyntaxError, "include_parsed tag requires a following syntax: {% include_parsed <template_path> [with <value1> as <variable1>[ and <value2> as <variable2>[ and ...]] %}"
     1223    return ParsedIncludeNode(parser.compile_filter(tag_name), parser.compile_filter(template_path), extra)
     1224   
     1225do_include_parsed = register.tag('include_parsed', do_include_parsed)
     1226
Back to Top