Django

Code

Ticket #10590: nested_fieldsets.diff

File nested_fieldsets.diff, 9.0 kB (added by Archatas, 11 months ago)

The patch for nested fieldsets

  • django/contrib/admin/helpers.py

    old new  
    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

    old new  
    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

    old new  
    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

    old new  
    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

    old new  
    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