Ticket #535: django-admin-refactor.patch

File django-admin-refactor.patch, 53.9 KB (added by robert@…, 19 years ago)

1st cut of the change and add views refactored to templates

  • django/conf/urls/admin.py

     
    4848
    4949urlpatterns += (
    5050    # Metasystem admin pages
     51    ('^(?P<app_label>[^/]+)/(?P<module_name>[^/]+)/add/new/$', 'django.views.admin.main.add_stage_new'),
     52    ('^(?P<app_label>[^/]+)/(?P<module_name>[^/]+)/(?P<object_id>.+)/new/$', 'django.views.admin.main.change_stage_new'),
    5153    ('^(?P<app_label>[^/]+)/(?P<module_name>[^/]+)/$', 'django.views.admin.main.change_list'),
    5254    ('^(?P<app_label>[^/]+)/(?P<module_name>[^/]+)/add/$', 'django.views.admin.main.add_stage'),
    5355    ('^(?P<app_label>[^/]+)/(?P<module_name>[^/]+)/jsvalidation/$', 'django.views.admin.jsvalidation.jsvalidation'),
  • django/conf/admin_templates/admin_change_form.html

     
     1{% extends "base_site" %}
     2{% load admin_modify %}
     3{% load adminmedia %}
     4{% block extrahead %}
     5 
     6   {% for js in javascript_imports %}
     7      {% include_admin_script js %}
     8   {% endfor %}
     9
     10{% endblock %}
     11
     12{% block coltype %}{{ coltype }}{% endblock %}
     13
     14{% block bodyclass %}{{app_label}}-{{object_name.lower}} change-form{% endblock %}
     15
     16{% block breadcrumbs %}{% if not is_popup %}
     17<div class="breadcrumbs">
     18     <a href="../../../">Home</a> &rsaquo;
     19     <a href="../">{{verbose_name_plural|capfirst}}</a> &rsaquo;
     20     {% if add %}
     21        Add {{verbose_name}}
     22     {% else %}
     23        {{original|striptags|truncatewords:"18"}}
     24     {% endif %}
     25</div>
     26{% endif %}
     27{% endblock %}
     28
     29{% block content %}<div id="content-main">
     30{% if change %}
     31   {% if not is_popup %}
     32      <ul class="object-tools"><li><a href="history/" class="historylink">History</a></li>
     33      {% if has_absolute_url %}
     34         <li><a href="/r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">View on site</a></li>
     35      {% endif%}
     36      </ul>
     37   {% endif %}
     38{% endif %}
     39
     40<form {{ form_enc_attrib }} action='{{ form_url }}' method="post">
     41
     42{% if is_popup %}<input type="hidden" name="_popup" value="1">{% endif %}
     43
     44{% if save_on_top %}
     45   {% submit_row %}
     46{% endif %}
     47
     48{% if form.error_dict %}
     49   <p class="errornote">Please correct the error{{ form.error_dict.items|pluralize }} below.</p>
     50{% endif %}
     51<b>
     52</b>
     53{% for fieldset in admin_fieldsets %}
     54   <fieldset class="module aligned {{ fieldset.classes }}">
     55      {% if fieldset.name %}
     56         <h2>{{fieldset.name }}</h2>
     57      {% endif %}
     58      {% for bound_field_set in fieldset.bound_field_sets %}
     59         {% for bound_field in bound_field_set %}
     60            {% admin_field_bound bound_field %}
     61                {% for field in bound_field.form_fields %}
     62                    {% if field.needs_filter_script %}
     63                   <script type="text/javascript">
     64                     addEvent(window, load, function(e){
     65                            SelectFilter.init("id_{{f.name}}", {{ f.verbose_name}}, {{f.filterthing}});
     66                     }
     67                   </script>
     68                {% endif %}
     69            {% endfor %}
     70         {% endfor%}
     71      {% endfor %}
     72   </fieldset>
     73{% endfor %}
     74
     75{% if change %}
     76   {% if ordered_objects %}
     77   <fieldset class="module"><h2>Ordering</h2>
     78   <div class="form-row{% if form.order_.errors %} error{% endif %} ">
     79   {% if form.order_.errors %}{{ form.order_.html_error_list }}{% endif %}
     80   <p><label for="id_order_">Order:</label> {{ form.order_ }}</p>
     81   </div></fieldset>
     82   {% endif %}
     83{% endif %}
     84
     85{% for relation in inline_related_objects %}
     86    {% edit_inline relation %}
     87{% endfor %}
     88
     89{% submit_row %}
     90
     91{% if add %}
     92   <script type="text/javascript">document.getElementById("id_{{first_field}}").focus();</script>'
     93{% endif %}
     94
     95{% if auto_populated_fields %}
     96   <script type="text/javascript">
     97   {% auto_populated_field_script auto_populated_fields %}
     98   </script>
     99{% endif %}
     100
     101{% if change %}
     102   {% if ordered_objects %}
     103      {% if form.order_objects %}<ul id="orderthese">
     104          {% for object in form.order_objects %}
     105             <li id="p{% firstof ordered_object_names %}">
     106             <span id="handlep{% firstof ordered_object_names %}">{{ object|truncatewords:"5" }}</span>
     107             </li>
     108          {% endfor%}
     109      {% endif %}
     110   {% endif %}
     111{% endif%}
     112</form>
     113
     114{% endblock %}
  • django/conf/admin_templates/admin_edit_inline_stacked.html

     
     1<fieldset class="module aligned">
     2   {% for ow in form_object_wrapper_list %}
     3      <h2>{{relation.obj.verbose_name|capfirst }}&nbsp;#{{ forloop.counter }}</h2>
     4      {% if ow.show_url %}{% if ow.obj.original %}
     5      <p><a href="/r/{{ ow.obj.original.content_type_id }}/{{ ow.obj.original.id }}/">View on site</a></p>
     6      {% endif %}{% endif %}
     7      {% for bound_field in ow.bound_fields %}
     8         {% if bound_field.not_in_table %}
     9            {% field_widget bound_field %}
     10         {% else %}
     11            {% admin_field_bound bound_field %}
     12         {% endif %}
     13      {% endfor %}
     14    {%endfor%}
     15</fieldset>
     16
  • django/conf/admin_templates/admin_field.html

     
     1<div class="{{ class_names }}">
     2   {% for bound_field in bound_fields %}
     3      {% if bound_field.field.errors %}
     4         {{ bound_field.field.html_error_list }}
     5      {% endif %}
     6   {% endfor %}
     7
     8   {% for bound_field in bound_fields %}
     9      {% if bound_field.has_label_first %}
     10         {% field_label bound_field %}
     11      {% endif %}
     12     
     13      {% field_widget bound_field %}
     14
     15      {% if not bound_field.has_label_first %}
     16         {% field_label bound_field %}
     17      {% endif %}
     18
     19      {% if change %}
     20         {% if bound_field.field.primary_key %}
     21            {{ bound_field.original_value }}
     22         {% endif %}
     23
     24         {% if bound_field.raw_id_admin %}
     25            {% if bound_field.has_existing %}
     26                &nbsp;<strong>{{ bound_field.existing | truncatewords: "14" }}</strong>
     27            {% endif %}
     28         {% endif %}
     29      {% endif %}
     30
     31      {% if bound_field.field.help_text %}
     32        <p class="help">
     33           {{bound_field.field.help_text}}
     34        </p>
     35      {% endif %}
     36   {% endfor %}
     37
     38</div>
  • django/conf/admin_templates/admin_field_widget.html

     
     1{% if bound_field.is_date_time %}
     2   <p class="datetime">
     3      Date: {{ bound_field.form_fields.0 }}<br />
     4      Time: {{ bound_field.form_fields.1 }}
     5   </p>
     6{% else %}
     7    {% if bound_field.is_file_field %}
     8        {% if bound_field.original_value %}
     9            Currently: <a href="{{ bound_field.original_url }}" > {{ bound_field.original_value }} </a><br />
     10            Change: {% output_all bound_field.form_fields %}
     11        {% else %}
     12            {% output_all bound_field.form_fields %}
     13        {% endif %}
     14    {% else %}
     15        {% output_all bound_field.form_fields %}
     16        {% if bound_field.raw_id_admin %}
     17            <a href="../../../{{ bound_field.field.rel.to.app_label }}/{{ bound_field.field.rel.to.module_name }}/" class="related-lookup" id="lookup_{{bound_field.label_name}}" onclick="return showRelatedObjectLookupPopup(this);">
     18        {% endif %}
     19        {% if bound_field.needs_add_label %}
     20            <a href="../../../{{ bound_field.field.rel.to.app_label }}/{{ bound_field.field.rel.to.module_name }}/add/"
     21               class="add-another" id="add_{{ bound_field.label_name}}">
     22               <img src="{% admin_media_prefix %}img/admin/icon_addlink.gif" width="10" height="10" alt="Add Another"/>
     23            </a>
     24        {% endif %}
     25    {% endif %}
     26{% endif %}
     27   
     28
     29
  • django/conf/admin_templates/admin_edit_inline_tabular.html

     
     1<fieldset class="module">
     2   <h2>{{relation.obj.verbose_name_plural|capfirst}}</h2><table>
     3   <thead><tr>
     4   {% for fw in field_wrapper_list %}
     5      {% if fw.needs_header %}
     6         <th{{fw.header_class_attribute}}> {{fw.field.verbose_name|capfirst}}  </th>
     7      {% endif %}
     8   {% endfor %}
     9   {% for ow in form_object_wrapper_list %}
     10     
     11      {% if change %}{% if original_row_needed %}
     12         {% if ow.obj.original %}
     13            <tr class="row-label {% cycle row1,row2 %}"><td colspan="{{num_headers}}"><strong>{{ ow.obj.original }}</strong></tr>
     14         {% endif %}
     15      {% endif %}{% endif %}
     16      {% if ow.has_errors %}
     17         <tr class="errorlist"><td colspan="{{num_headers}}">
     18            {{ ow.html_combined_error_list }}
     19         </tr>
     20      {% endif %}
     21      <tr class="{% cycle row1,row2 %}">
     22      {% for bound_field in ow.bound_fields %}
     23         {% if not bound_field.not_in_table %}
     24         <td "{{ bound_field.cell_class_attribute}}">
     25            {% field_widget bound_field %}
     26         </td>
     27         {% endif %}
     28      {% endfor %}
     29      {% if ow.show_url %}<td>
     30         {% if ow.obj.original %}<a href="/r/{{ ow.obj.original.content_type_id }}/{{ ow.obj.original.id }}/">View on site</a>{% endif %}
     31      </td>{% endif %}
     32      </tr>
     33
     34   {% endfor %} </table>
     35
     36   {% for ow in form_object_wrapper_list %}
     37      {% for bound_field in ow.bound_fields %}
     38         {% if bound_field.not_in_table %}
     39            {% field_widget bound_field %}
     40         {% endif %}
     41      {% endfor %}
     42   {% endfor %}
     43</fieldset>
     44
  • django/core/formfields.py

     
    8787        must happen after validation because html2python functions aren't
    8888        expected to deal with invalid input.
    8989        """
    90         for field in self.fields:
    91             if new_data.has_key(field.field_name):
    92                 new_data.setlist(field.field_name,
    93                     [field.__class__.html2python(data) for data in new_data.getlist(field.field_name)])
    94             else:
    95                 try:
    96                     # individual fields deal with None values themselves
    97                     new_data.setlist(field.field_name, [field.__class__.html2python(None)])
    98                 except EmptyValue:
    99                     new_data.setlist(field.field_name, [])
     90        """
     91        for field in self.fields:
     92        """
    10093
     94        for field in self.fields:
     95            field.convert_post_data(new_data)
     96
    10197class FormWrapper:
    10298    """
    10399    A wrapper linking a Manipulator to the template system.
     
    114110    def __getitem__(self, key):
    115111        for field in self.manipulator.fields:
    116112            if field.field_name == key:
    117                 if hasattr(field, 'requires_data_list') and hasattr(self.data, 'getlist'):
    118                     data = self.data.getlist(field.field_name)
    119                 else:
    120                     data = self.data.get(field.field_name, None)
    121                 if data is None:
    122                     data = ''
    123                 return FormFieldWrapper(field, data, self.error_dict.get(field.field_name, []))
     113               
     114                data = field.extract_data(self.data)
     115               
     116                return FormFieldWrapper(field, data, self.error_dict.get(field.field_name, []))
    124117        raise KeyError
    125118
    126119    def has_errors(self):
     
    209202    def render(self, data):
    210203        raise NotImplementedError
    211204
     205    def get_member_name(self):
     206        return self.field_name
     207
     208    def extract_data(self, data_dict):
     209        if hasattr(self, 'requires_data_list') and hasattr(data_dict, 'getlist'):
     210            data = data_dict.getlist(self.get_member_name())
     211        else:
     212            data = data_dict.get(self.get_member_name(), None)
     213        if data is None:
     214            data = ''
     215        self.data_dict = data_dict 
     216        return data
     217
     218    def convert_post_data(self, new_data):
     219        name = self.get_member_name()
     220        if new_data.has_key(self.field_name):
     221            d = new_data.getlist(self.field_name)
     222            #del new_data[self.field_name]
     223            new_data.setlist(name,
     224                    [self.__class__.html2python(data)
     225                     for data in d])
     226        else:
     227            try:
     228               # individual fields deal with None values themselves
     229               new_data.setlist(name, [self.__class__.html2python(None)])
     230            except EmptyValue:
     231               new_data.setlist(name, [])
     232
    212233####################
    213234# GENERIC WIDGETS  #
    214235####################
     
    319340        output.append('  </select>')
    320341        return '\n'.join(output)
    321342
     343    def get_member_name(self):
     344        return "%s_id" % self.field_name
     345
    322346    def isValidChoice(self, data, form):
    323347        str_data = str(data)
    324348        str_choices = [str(item[0]) for item in self.choices]
  • django/core/meta/__init__.py

     
    592592            new_mod.get_latest = curry(function_get_latest, opts, new_class, does_not_exist_exception)
    593593
    594594        for f in opts.fields:
     595            if len(f.choices) != 0:
     596                # Add an accessor method to get to the human readable value
     597                func = curry(method_get_display_value, f)
     598                setattr(new_class, 'get_%s_display' % f.name , func)
    595599            if isinstance(f, DateField) or isinstance(f, DateTimeField):
    596600                # Add "get_next_by_thingie" and "get_previous_by_thingie" methods
    597601                # for all DateFields and DateTimeFields that cannot be null.
     
    782786        # If it does already exist, do an UPDATE.
    783787        if cursor.fetchone():
    784788            db_values = [f.get_db_prep_save(f.pre_save(getattr(self, f.column), False)) for f in non_pks]
    785             cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % (opts.db_table,
    786                 ','.join(['%s=%%s' % f.column for f in non_pks]), opts.pk.column),
     789            while 1:
     790                try:
     791                    idx = db_values.index('')
     792                    non_pks[idx:idx+1] = []
     793                    db_values[idx:idx +1] = []
     794                except: break
     795            cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % (opts.db_table,
     796                ','.join(['%s=%%s' % f.column for f in non_pks]), opts.pk.column),
    787797                db_values + [pk_val])
    788798        else:
    789799            record_exists = False
     
    9911001    kwargs['limit'] = 1
    9921002    return get_object_func(**kwargs)
    9931003
     1004# CHOICE-RELATED METHODS ###################
     1005
     1006def method_get_display_value(field, self):
     1007    value = getattr(self, field.name)
     1008    for (v, d) in field.choices:
     1009        if v==value:
     1010            return d
     1011    # Couldn't find it in the list
     1012    return value
     1013
    9941014# FILE-RELATED METHODS #####################
    9951015
    9961016def method_get_file_filename(field, self):
  • django/core/meta/fields.py

     
    263263        rel_obj = self.rel.to
    264264        return first_choice + [(getattr(x, rel_obj.pk.column), repr(x)) for x in rel_obj.get_model_module().get_list(**self.rel.limit_choices_to)]
    265265
     266    def flatten_data(self, val):
     267         """
     268             Returns a dictionary mapping the field's manipulator field names to its
     269             "flattened" string values for the admin view. "val" is an instance of the
     270             field's value.
     271         """
     272         return { self.get_db_column(): val}
     273       
     274 
    266275class AutoField(Field):
    267276    empty_strings_allowed = False
    268277    def __init__(self, *args, **kwargs):
     
    327336    def get_manipulator_field_objs(self):
    328337        return [formfields.DateField]
    329338
     339    def flatten_data(self, val):
     340        return {self.get_db_column(): (val is not None and val.strftime("%Y-%m-%d") or '')}
     341
    330342class DateTimeField(DateField):
    331343    def get_db_prep_save(self, value):
    332344        # Casts dates into string format for entry into database.
     
    356368            return datetime.datetime.combine(d, t)
    357369        return self.get_default()
    358370
     371    def flatten_data(self, val):
     372        date_field, time_field = self.get_manipulator_field_names('')
     373        return {date_field: (val is not None and val.strftime("%Y-%m-%d") or ''),
     374                time_field: (val is not None and val.strftime("%H:%M:%S") or '')}
     375
    359376class EmailField(Field):
    360377    def get_manipulator_field_objs(self):
    361378        return [formfields.EmailField]
     
    539556    def get_manipulator_field_objs(self):
    540557        return [formfields.TimeField]
    541558
     559    def flatten_data(self,val):
     560        return {self.get_db_column(): val}
     561
    542562class URLField(Field):
    543563    def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs):
    544564        if verify_exists:
  • django/templatetags/admin_modify.py

     
     1from django.core import template, template_loader, meta
     2from django.conf.settings import ADMIN_MEDIA_PREFIX
     3from django.utils.text import capfirst
     4from django.utils.html import escape
     5
     6use_raw_id_admin = lambda field: isinstance(field.rel, (meta.ManyToOne, meta.ManyToMany)) and field.rel.raw_id_admin
     7
     8
     9from django.views.admin.main import BoundField, resolve_form_fields
     10
     11class IncludeAdminScriptNode(template.Node):
     12      def __init__(self, var):
     13         self.var = var
     14 
     15      def render(self, context):
     16        resolved = template.resolve_variable(self.var, context)
     17        return '<script type="text/javascript" src="%s%s"></script>' % \
     18                (ADMIN_MEDIA_PREFIX, resolved)
     19         
     20class DummyNode(template.Node):
     21      def __init__(self, var):
     22          self.var = var
     23
     24      def render(self, context):
     25         #resolved = template.resolve_variable(self.var, context)
     26         return "<b> Dummy: %s</b>" % self.var
     27
     28def template_hack(t, context):
     29    raw = ''.join(t)
     30    template =  template_loader.get_template_from_string(raw)
     31    return template.render(context)
     32   
     33
     34class SubmitRowNode(template.Node):
     35      def __init__(self):
     36          pass
     37
     38      def render(self, context):
     39          change = context['change']
     40          add = context['add']
     41          show_delete = context['show_delete']
     42          ordered_objects = context['ordered_objects']
     43          save_as = context['save_as']
     44          has_delete_permission = context['has_delete_permission']
     45          is_popup = context['is_popup']
     46         
     47          t = ['<div class="submit-row">']
     48          onclick_attrib = ordered_objects and change and 'onclick="submitOrderForm();"' or ''
     49         
     50          if not is_popup:
     51                if has_delete_permission and (change or show_delete):
     52                   t.append('<p class="float-left"><a href="delete/" class="deletelink">Delete</a></p>')
     53                if change and save_as:
     54                   t.append('<input type="submit" value="Save as new" name="_saveasnew" %s/>' %  onclick_attrib)
     55                if (not save_as or add):
     56                   t.append('<input type="submit" value="Save and add another" name="_addanother" %s/>' %  onclick_attrib)
     57          t.append('<input type="submit" value="Save and continue editing" name="_continue" %s/>' %  onclick_attrib )
     58          t.append('<input type="submit" value="Save" class="default" %s/>' %  onclick_attrib)
     59          t.append('</div>\n')
     60         
     61          return ''.join(t)
     62
     63
     64
     65
     66class AdminFieldBoundNode(template.Node):
     67    def __init__(self, argument):
     68        self.argument = argument
     69   
     70    def render(self, context):
     71        argument_val = template.resolve_variable(self.argument, context)
     72        if (isinstance(argument_val, list)):
     73            bound_fields = argument_val
     74        else:
     75            bound_fields = [argument_val]
     76        add = context['add']
     77        change = context['change']
     78       
     79        context.push()
     80        context['bound_fields'] = bound_fields
     81        context['class_names'] = " ".join(self.get_class_names(bound_fields))
     82        t = template_loader.get_template("admin_field")
     83        output =  t.render(context)
     84        context.pop()
     85         
     86        return output
     87
     88    def get_class_names(self, bound_fields):
     89
     90        class_names = ['form-row']
     91        for bound_field in bound_fields:
     92            for f in bound_field.form_fields:
     93                if f.errors():
     94                    class_names.append('errors')
     95                    break
     96         
     97        # Assumes BooleanFields won't be stacked next to each other!
     98        if isinstance(bound_fields[0].field, meta.BooleanField):
     99            class_names.append('checkbox-row')
     100         
     101        return class_names
     102       
     103class FieldWidgetNode(template.Node):
     104    def __init__(self, bound_field_var):
     105        self.bound_field_var = bound_field_var
     106
     107    def render(self, context):
     108        bound_field = template.resolve_variable(self.bound_field_var, context)
     109        add = context['add']
     110        change = context['change']
     111       
     112        context.push()
     113        context['bound_field'] = bound_field
     114        t = template_loader.get_template("admin_field_widget")
     115        output =  t.render(context)
     116        context.pop()
     117         
     118        return output
     119
     120       
     121
     122class FieldWrapper(object):
     123    def __init__(self, field ):
     124        self.field = field
     125
     126    def needs_header(self):
     127        return not isinstance(self.field, meta.AutoField)
     128
     129    def header_class_attribute(self):
     130        return self.field.blank and ' class="optional"' or ''
     131
     132     
     133
     134class FormObjectWrapper(object):
     135    def __init__(self, obj, field_wrappers, i, object_name):
     136        self.obj = obj
     137        self.field_wrappers = field_wrappers
     138     
     139        form_prefix = '%s.%s.' % ( object_name, i)
     140     
     141        name_prefix = ''
     142     
     143        self.bound_fields = [ BoundField(0, fw.field, obj['original'], form_prefix,
     144                              name_prefix, True, self.resolve_form_fields(fw.field, name_prefix) ) \
     145                                for fw in self.field_wrappers ]
     146
     147   
     148    def resolve_form_fields(self,field, name_prefix):
     149        return [self.obj[name] for name in field.get_manipulator_field_names(name_prefix)]
     150
     151#HACK
     152    def has_errors(self):
     153        return max([ bool( len( self.obj[fw.field.name].errors() ) )  for fw in self.field_wrappers])
     154       
     155    def html_combined_error_list(self):
     156        return ''.join( [ self.obj[fw.field.name].html_error_list() for fw in self.field_wrappers])
     157
     158   
     159   
     160
     161class EditInlineNode(template.Node):
     162    def __init__(self, rel_var):
     163        self.rel_var = rel_var
     164   
     165    def render(self, context):
     166        relation = template.resolve_variable(self.rel_var, context)
     167        add, change = context['add'], context['change']
     168       
     169        context.push()
     170
     171        self.fill_context_tabular(relation, add, change, context)
     172       
     173        if relation.field.rel.edit_inline == meta.TABULAR:
     174            t = template_loader.get_template("admin_edit_inline_tabular")
     175        else:  # meta.STACKED
     176            t = template_loader.get_template("admin_edit_inline_stacked")   
     177       
     178        output = t.render(context)
     179        #    t = self.get_template(relation, add, change, context)
     180        #    return '<pre>%s</pre>' % escape(''.join(t))
     181        #    return template_hack(t, context)
     182       
     183        context.pop()
     184        return output
     185
     186       
     187    def fill_context_tabular(self, relation, add, change, context):
     188        field_wrapper_list = [FieldWrapper(f) for f in relation.obj.fields + relation.obj.many_to_many if f.editable and f != relation.field]
     189       
     190        var_name = relation.obj.object_name.lower()
     191       
     192        form_objects = template.resolve_variable('form.%s' % relation.obj.module_name , context)
     193        form_object_wrapper_list = [FormObjectWrapper(o,field_wrapper_list, i, var_name) for i,o in enumerate(form_objects)]
     194   
     195        context['field_wrapper_list'] = field_wrapper_list
     196        context['form_object_wrapper_list'] = form_object_wrapper_list
     197        context['num_headers'] = len(field_wrapper_list)
     198        context['original_row_needed'] = max([use_raw_id_admin(fw.field) for fw in field_wrapper_list])
     199        context['name_prefix'] = "%s." % (var_name,)
     200   
     201class FieldLabelNode(template.Node):
     202    def __init__(self, bound_field_var):
     203        self.bound_field_var = bound_field_var
     204       
     205    def render(self, context):
     206        bound_field = template.resolve_variable(self.bound_field_var, context)
     207        class_names = []
     208        if isinstance(bound_field.field, meta.BooleanField):
     209            class_names.append("vCheckboxLabel")
     210        else:
     211            if not bound_field.field.blank:
     212                class_names.append('required')
     213            if bound_field.index > 0:
     214                class_names.append('inline')
     215       
     216        class_str = class_names and ' class="%s"' % ' '.join(class_names) or ''
     217        return '<label for="%s"%s>%s:</label> ' % (bound_field.label_name, class_str, capfirst(bound_field.field.verbose_name) )
     218
     219class OutputAllNode(template.Node):
     220    def __init__(self, form_fields_var):
     221        self.form_fields_var = form_fields_var
     222   
     223    def render(self, context):
     224        form_fields = template.resolve_variable(self.form_fields_var, context)
     225        return ''.join([str(f) for f in form_fields])
     226
     227class AutoPopulatedFieldScript(template.Node):
     228    def __init__(self, auto_pop_var):
     229        self.auto_pop_var = auto_pop_var
     230
     231    def render(self,context):
     232        auto_pop_fields = template.resolve_variable(self, context)
     233        change = context['change']
     234        for field in auto_populated_fields:
     235            t = []
     236            if change:
     237                t.append('document.getElementById("id_%s")._changed = true;' % field.name )
     238            else:
     239                t.append('document.getElementById("id_%s").onchange = function() { this._changed = true; };' % field.name
     240
     241            add_values = ' + " " + ' join(['document.getElementById("id_%s").value' % g for g in field.prepopulate_from])
     242            for f in field.prepopulate_from:
     243                t.append("""
     244                         document.getElementById("id_%s").onkeyup = function() {
     245                                var e = document.getElementById("id_%s");
     246                                if(!e._changed) { e.value = URLify(%s, %s);}
     247                        }
     248                        """ % (f, field.name, add_values, field.maxlength))
     249                )
     250
     251        return ''.join(t)
     252
     253def do_include_admin_script(parser, token):
     254     tokens = token.contents.split()
     255     if len(tokens) != 2:
     256         raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0])
     257     
     258     return IncludeAdminScriptNode(tokens[1])
     259
     260def do_dummy(parser, token):
     261     return DummyNode(token.contents)
     262
     263def do_submit_row(parser, token):
     264     return SubmitRowNode()
     265
     266def do_admin_field_bound(parser, token):
     267    tokens = token.contents.split()
     268    if len(tokens) != 2:
     269        raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0])
     270    return AdminFieldBoundNode(tokens[1])
     271
     272
     273def do_field_label(parser, token):
     274    tokens = token.contents.split()
     275    if len(tokens) != 2:
     276        raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0])
     277    return FieldLabelNode(tokens[1])
     278
     279def do_field_widget(parser, token):
     280    tokens = token.contents.split()
     281    if len(tokens) != 2:
     282        raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0])
     283    return FieldWidgetNode(tokens[1])
     284
     285def do_output_all(parser, token):
     286    tokens = token.contents.split()
     287    if len(tokens) != 2:
     288        raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0])
     289    return OutputAllNode(tokens[1])
     290
     291
     292def do_edit_inline(parser, token):
     293    tokens = token.contents.split()
     294    if len(tokens) != 2:
     295        raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0])
     296    return EditInlineNode(tokens[1])
     297
     298def do_auto_populated_field_script(parser, token):
     299    tokens = token.contents.split()
     300    if len(tokens) != 2:
     301        raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0])
     302    return AutoPopulatedFieldScriptNode(tokens[1])
     303
     304
     305
     306template.register_tag('include_admin_script', do_include_admin_script)
     307template.register_tag('submit_row', do_submit_row )
     308template.register_tag('admin_field_bound', do_admin_field_bound)
     309template.register_tag('edit_inline', do_edit_inline)
     310template.register_tag('auto_populated_field_script', do_auto_populated_field_script)
     311template.register_tag('field_label', do_field_label)
     312template.register_tag('field_widget', do_field_widget)
     313template.register_tag('output_all', do_output_all)
     314         
     315         
  • django/views/admin/main.py

     
    11# Generic admin views, with admin templates created dynamically at runtime.
    22
    3 from django.core import formfields, meta, template_loader
     3from django.core import formfields, meta, template_loader, template
    44from django.core.exceptions import Http404, ObjectDoesNotExist, PermissionDenied
    55from django.core.extensions import DjangoContext as Context
    66from django.models.auth import log
     
    493493    })
    494494    return HttpResponse(t.render(c), mimetype='text/html; charset=utf-8')
    495495
    496 def _get_flattened_data(field, val):
    497     """
    498     Returns a dictionary mapping the field's manipulator field names to its
    499     "flattened" string values for the admin view. "val" is an instance of the
    500     field's value.
    501     """
    502     if isinstance(field, meta.DateTimeField):
    503         date_field, time_field = field.get_manipulator_field_names('')
    504         return {date_field: (val is not None and val.strftime("%Y-%m-%d") or ''),
    505                 time_field: (val is not None and val.strftime("%H:%M:%S") or '')}
    506     elif isinstance(field, meta.DateField):
    507         return {field.name: (val is not None and val.strftime("%Y-%m-%d") or '')}
    508     elif isinstance(field, meta.TimeField):
    509         return {field.name: (val is not None and val.strftime("%H:%M:%S") or '')}
    510     else:
    511         return {field.name: val}
    512 
    513496use_raw_id_admin = lambda field: isinstance(field.rel, (meta.ManyToOne, meta.ManyToMany)) and field.rel.raw_id_admin
    514497
    515498def _get_submit_row_template(opts, app_label, add, change, show_delete, ordered_objects):
     
    530513    t.append('</div>\n')
    531514    return t
    532515
     516def get_javascript_imports(opts,auto_populated_fields, ordered_objects, admin_field_objs):
     517# Put in any necessary JavaScript imports.
     518    js = ['js/core.js', 'js/admin/RelatedObjectLookups.js']
     519    if auto_populated_fields:
     520        js.append('js/urlify.js')
     521    if opts.has_field_type(meta.DateTimeField) or opts.has_field_type(meta.TimeField) or opts.has_field_type(meta.DateField):
     522        js.extend(['js/calendar.js', 'js/admin/DateTimeShortcuts.js'])
     523    if ordered_objects:
     524        js.extend(['js/getElementsBySelector.js', 'js/dom-drag.js' , 'js/admin/ordering.js'])
     525    if opts.admin.js:
     526        js.extend(opts.admin.js)
     527    seen_collapse = False
     528    for _, options in admin_field_objs:
     529        if not seen_collapse and 'collapse' in options.get('classes', ''):
     530            seen_collapse = True
     531            js.append('js/admin/CollapsedFieldsets.js' )
     532        try:
     533            for field_list in options['fields']:
     534                for f in field_list:
     535                    if f.rel and isinstance(f, meta.ManyToManyField) and f.rel.filter_interface:
     536                        js.extend(['js/SelectBox.js' , 'js/SelectFilter2.js'])
     537                        raise StopIteration
     538        except StopIteration:
     539            break
     540    return js
     541
     542def auto_populate_field_script():
     543    for field in auto_populated_fields:
     544            if change:
     545                t.append('document.getElementById("id_%s")._changed = true;' % field.name)
     546            else:
     547                t.append('document.getElementById("id_%s").onchange = function() { this._changed = true; };' % field.name)
     548            for f in field.prepopulate_from:
     549                t.append('document.getElementById("id_%s").onkeyup = function() { var e = document.getElementById("id_%s"); if (!e._changed) { e.value = URLify(%s, %s);}};' % \
     550                    (f, field.name, ' + " " + '.join(['document.getElementById("id_%s").value' % g for g in field.prepopulate_from]), field.maxlength))
     551 
     552class BoundField(object):
     553    def __init__(self, index, field, original, form_prefix, name_prefix, rel, form_fields):
     554        self.index = index
     555        self.field = field
     556        self.hack_prefix = 'form.' + form_prefix
     557        self.label_name = 'id_%s%s' % (form_prefix, field.get_manipulator_field_names('')[0])
     558        self.has_label_first = not isinstance(self.field, meta.BooleanField)
     559        self.original = original
     560        self.raw_id_admin = use_raw_id_admin(field)
     561        self.name_prefix = name_prefix
     562        self.rel = rel
     563        self.is_date_time = isinstance(field, meta.DateTimeField)
     564        self.is_file_field = isinstance(field, meta.FileField)
     565        self.needs_add_label = field.rel and isinstance(field.rel, meta.ManyToOne) and field.rel.to.admin
     566        self.not_in_table = isinstance(self.field, meta.AutoField)
     567        self.form_fields = form_fields
     568       
     569        classes = []
     570        if(self.raw_id_admin):
     571            classes.append('nowrap')
     572      #  if(self.field.errors()):
     573      #      classes.append('error')
     574        self.cell_class_attribute = ' '.join(classes)   
     575       
     576    def as_field_list(self):
     577        return [self.field]
     578
     579    def original_value(self):
     580        return self.original.__dict__[self.field.name]
     581       
     582    def fill_existing_repr(self):
     583        if self._repr_filled:
     584            return
     585        #HACK
     586        if isinstance(field.rel, meta.ManyToOne):
     587             self._obj = original.__class__.__dict__['get_%s' % self.field.name](original)
     588             self._repr = obj
     589        elif isinstance(field.rel, meta.ManyToMany):
     590             self._obj = original.__class__.__dict__['get_%s_list' % self.field.name ](original)
     591             self._repr =  "".join(obj)
     592        self._repr_filled = True
     593             
     594    def has_existing_repr(self):
     595        self.fill_existing_repr()
     596        return self._obj and True or False
     597
     598    def existing_repr(self):
     599        self.fill_existing_repr()
     600        return self._repr
     601
     602    def __repr__(self):
     603        return repr(self.__dict__)
     604
     605   
     606
     607
     608class AdminFieldSet(object):
     609     def __init__(self, fieldset_name, options, bound_field_sets):
     610         self.name = fieldset_name
     611         self.options = options
     612         self.bound_field_sets = bound_field_sets
     613         self.classes = [] + options['classes']
     614# self.fields = options['fields']
     615     
     616     def __repr__(self):
     617        return "Fieldset:(%s,%s)" % (self.name, self.bound_field_sets)
     618
     619class InlineRelatedObject(object):
     620     def __init__(self,obj, field):
     621        self.obj = obj
     622        self.field = field
     623       
     624
     625def bound_field_sets(opts, context, name_prefix):
     626    original = template.resolve_variable('original', context);
     627    form_prefix = ''
     628    fields = opts['fields']
     629    #raise repr(fields)
     630    bound_field_sets = [ [BoundField(i, f, original, form_prefix, name_prefix, False,
     631                                resolve_form_fields(f,name_prefix, context)) for i,f in enumerate(field)  ] for field in fields]
     632
     633    return bound_field_sets
     634
     635def resolve_form_fields(field, name_prefix, context):
     636   # raise repr(field.get_manipulator_field_names(name_prefix)) + "\n!!\n" + repr(context)
     637    return [template.resolve_variable(name, context) for name in field.get_manipulator_field_names(name_prefix)]
     638
     639
     640def fill_extra_context(opts, app_label, context, add=False, change=False, show_delete=False, form_url=''):
     641    admin_field_objs = opts.admin.get_field_objs(opts)
     642    ordered_objects = opts.get_ordered_objects()[:]
     643    auto_populated_fields = [f for f in opts.fields if f.prepopulate_from]
     644 
     645    javascript_imports = get_javascript_imports(opts,auto_populated_fields, ordered_objects, admin_field_objs);
     646   
     647    if ordered_objects:
     648        coltype = 'colMS'
     649    else:
     650        coltype = 'colM'
     651       
     652    has_absolute_url = hasattr(opts.get_model_module().Klass, 'get_absolute_url')
     653   
     654    form_enc_attrib = opts.has_field_type(meta.FileField) and 'enctype="multipart/form-data" ' or ''
     655
     656    admin_fieldsets = [AdminFieldSet(f, o, bound_field_sets(o, context, 'form.')) for f, o in admin_field_objs]
     657    inline_related_objects = [InlineRelatedObject(obj, field) for obj, field in opts.get_inline_related_objects()]
     658   
     659    ordered_object_names =   ' '.join(['object.%s' % o.pk.name for o in ordered_objects])
     660   
     661    extra_context = {
     662        'add': add,
     663        'change': change,
     664        'admin_field_objs' : admin_field_objs,
     665        'ordered_objects' : ordered_objects,
     666        'auto_populated_fields' : auto_populated_fields,
     667        'javascript_imports' : javascript_imports,
     668        'coltype' : coltype,
     669        'has_absolute_url': has_absolute_url,
     670        'form_enc_attrib': form_enc_attrib,
     671        'form_url' : form_url,
     672        'admin_fieldsets' : admin_fieldsets,
     673        'inline_related_objects': inline_related_objects,
     674        'ordered_object_names' : ordered_object_names,
     675        'content_type_id' : opts.get_content_type_id(),
     676        'save_on_top' : opts.admin.save_on_top,
     677        'verbose_name_plural': opts.verbose_name_plural,
     678        'save_as': opts.admin.save_as,
     679        'app_label': app_label,
     680        'object_name': opts.object_name,
     681        'has_delete_permission' = context['perms'][app_label][opts.get_delete_permission()
     682    }
     683   
     684    context.update(extra_context)   
     685   
     686   
     687def add_stage_new(request, app_label, module_name, show_delete=False, form_url='', post_url='../', post_url_continue='../%s/', object_id_override=None):
     688    mod, opts = _get_mod_opts(app_label, module_name)
     689    if not request.user.has_perm(app_label + '.' + opts.get_add_permission()):
     690        raise PermissionDenied
     691    manipulator = mod.AddManipulator()
     692    if request.POST:
     693        new_data = request.POST.copy()
     694        if opts.has_field_type(meta.FileField):
     695            new_data.update(request.FILES)
     696        errors = manipulator.get_validation_errors(new_data)
     697        if not errors and not request.POST.has_key("_preview"):
     698            for f in opts.many_to_many:
     699                if f.rel.raw_id_admin:
     700                    new_data.setlist(f.name, new_data[f.name].split(","))
     701            manipulator.do_html2python(new_data)
     702            new_object = manipulator.save(new_data)
     703            pk_value = getattr(new_object, opts.pk.column)
     704            log.log_action(request.user.id, opts.get_content_type_id(), pk_value, repr(new_object), log.ADDITION)
     705            msg = 'The %s "%s" was added successfully.' % (opts.verbose_name, new_object)
     706            # Here, we distinguish between different save types by checking for
     707            # the presence of keys in request.POST.
     708            if request.POST.has_key("_continue"):
     709                request.user.add_message("%s You may edit it again below." % msg)
     710                if request.POST.has_key("_popup"):
     711                    post_url_continue += "?_popup=1"
     712                return HttpResponseRedirect(post_url_continue % pk_value)
     713            if request.POST.has_key("_popup"):
     714                return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %s, "%s");</script>' % \
     715                    (pk_value, repr(new_object).replace('"', '\\"')), mimetype='text/html; charset=utf-8')
     716            elif request.POST.has_key("_addanother"):
     717                request.user.add_message("%s You may add another %s below." % (msg, opts.verbose_name))
     718                return HttpResponseRedirect(request.path)
     719            else:
     720                request.user.add_message(msg)
     721                return HttpResponseRedirect(post_url)
     722        if request.POST.has_key("_preview"):
     723            manipulator.do_html2python(new_data)
     724    else:
     725        new_data = {}
     726        # Add default data.
     727        for f in opts.fields:
     728            if f.has_default():
     729                new_data.update( f.flatten_data(f.get_default()) )
     730            # In required many-to-one fields with only one available choice,
     731            # select that one available choice. Note: We have to check that
     732            # the length of choices is *2*, not 1, because SelectFields always
     733            # have an initial "blank" value.
     734            elif not f.blank and ((isinstance(f.rel, meta.ManyToOne) and not f.rel.raw_id_admin) or f.choices) and len(manipulator[f.name].choices) == 2:
     735                new_data[f.name] = manipulator[f.name].choices[1][0]
     736        # In required many-to-many fields with only one available choice,
     737        # select that one available choice.
     738        for f in opts.many_to_many:
     739            if not f.blank and not f.rel.edit_inline and not f.rel.raw_id_admin and len(manipulator[f.name].choices) == 1:
     740                new_data[f.name] = [manipulator[f.name].choices[0][0]]
     741        # Add default data for related objects.
     742        for rel_opts, rel_field in opts.get_inline_related_objects():
     743            var_name = rel_opts.object_name.lower()
     744            for i in range(rel_field.rel.num_in_admin):
     745                for f in rel_opts.fields + rel_opts.many_to_many:
     746                    if f.has_default():
     747                        for field_name in f.get_manipulator_field_names(''):
     748                            new_data['%s.%d.%s' % (var_name, i, field_name)] = f.get_default()
     749        # Override the defaults with request.GET, if it exists.
     750        new_data.update(request.GET)
     751        errors = {}
     752
     753    # Populate the FormWrapper.
     754    form = formfields.FormWrapper(manipulator, new_data, errors)
     755    for rel_opts, rel_field in opts.get_inline_related_objects():
     756        var_name = rel_opts.object_name.lower()
     757        wrapper = []
     758        for i in range(rel_field.rel.num_in_admin):
     759            collection = {}
     760            for f in rel_opts.fields + rel_opts.many_to_many:
     761                if f.editable and f != rel_field and not isinstance(f, meta.AutoField):
     762                    for field_name in f.get_manipulator_field_names(''):
     763                        full_field_name = '%s.%d.%s' % (var_name, i, field_name)
     764                        field = manipulator[full_field_name]
     765                        data = field.extract_data(new_data)
     766                        collection[field_name] = formfields.FormFieldWrapper(field, data, errors.get(full_field_name, []))
     767            wrapper.append(formfields.FormFieldCollection(collection))
     768        setattr(form, rel_opts.module_name, wrapper)
     769
     770    c = Context(request, {
     771        'title': 'Add %s' % opts.verbose_name,
     772        "form": form,
     773        "is_popup": request.REQUEST.has_key("_popup"),
     774    })
     775    if object_id_override is not None:
     776        c['object_id'] = object_id_override
     777    #raw_template = _get_template(opts, app_label, add=True, show_delete=show_delete, form_url=form_url)
     778#     return HttpResponse(raw_template, mimetype='text/plain')
     779   # t = template_loader.get_template_from_string(raw_template)
     780   
     781    fill_extra_context(opts, app_label, c, change=True)
     782    #raw_template = _get_template(opts, app_label, change=True)
     783    # return HttpResponse(raw_template, mimetype='text/plain')
     784    #t = template_loader.get_template_from_string(raw_template)
     785    t = template_loader.get_template("admin_change_form");
     786   
     787    return HttpResponse(t.render(c), mimetype='text/html; charset=utf-8')
     788
     789
     790
     791def change_stage_new(request, app_label, module_name, object_id):
     792    mod, opts = _get_mod_opts(app_label, module_name)
     793    if not request.user.has_perm(app_label + '.' + opts.get_change_permission()):
     794        raise PermissionDenied
     795    if request.POST and request.POST.has_key("_saveasnew"):
     796        return add_stage_new(request, app_label, module_name, form_url='../add/')
     797    try:
     798        manipulator = mod.ChangeManipulator(object_id)
     799    except ObjectDoesNotExist:
     800        raise Http404
     801
     802    inline_related_objects = opts.get_inline_related_objects()
     803    if request.POST:
     804        new_data = request.POST.copy()
     805        if opts.has_field_type(meta.FileField):
     806            new_data.update(request.FILES)
     807
     808        errors = manipulator.get_validation_errors(new_data)
     809        if not errors and not request.POST.has_key("_preview"):
     810            for f in opts.many_to_many:
     811                if f.rel.raw_id_admin:
     812                    new_data.setlist(f.name, new_data[f.name].split(","))
     813            manipulator.do_html2python(new_data)
     814            new_object = manipulator.save(new_data)
     815            pk_value = getattr(new_object, opts.pk.column)
     816
     817            # Construct the change message.
     818            change_message = []
     819            if manipulator.fields_added:
     820                change_message.append('Added %s.' % get_text_list(manipulator.fields_added, 'and'))
     821            if manipulator.fields_changed:
     822                change_message.append('Changed %s.' % get_text_list(manipulator.fields_changed, 'and'))
     823            if manipulator.fields_deleted:
     824                change_message.append('Deleted %s.' % get_text_list(manipulator.fields_deleted, 'and'))
     825            change_message = ' '.join(change_message)
     826            if not change_message:
     827                change_message = 'No fields changed.'
     828
     829            log.log_action(request.user.id, opts.get_content_type_id(), pk_value, repr(new_object), log.CHANGE, change_message)
     830            msg = 'The %s "%s" was changed successfully.' % (opts.verbose_name, new_object)
     831            if request.POST.has_key("_continue"):
     832                request.user.add_message("%s You may edit it again below." % msg)
     833                if request.REQUEST.has_key('_popup'):
     834                    return HttpResponseRedirect(request.path + "?_popup=1")
     835                else:
     836                    return HttpResponseRedirect(request.path)
     837            elif request.POST.has_key("_saveasnew"):
     838                request.user.add_message('The %s "%s" was added successfully. You may edit it again below.' % (opts.verbose_name, new_object))
     839                return HttpResponseRedirect("../%s/" % pk_value)
     840            elif request.POST.has_key("_addanother"):
     841                request.user.add_message("%s You may add another %s below." % (msg, opts.verbose_name))
     842                return HttpResponseRedirect("../add/")
     843            else:
     844                request.user.add_message(msg)
     845                return HttpResponseRedirect("../")
     846        if request.POST.has_key("_preview"):
     847            manipulator.do_html2python(new_data)
     848    else:
     849        # Populate new_data with a "flattened" version of the current data.
     850        new_data = {}
     851        obj = manipulator.original_object
     852        for f in opts.fields:
     853            new_data.update(f.flatten_data(getattr(obj, f.column)))
     854       
     855        for f in opts.many_to_many:
     856            get_list_func = getattr(obj, 'get_%s_list' % f.rel.singular)
     857            if f.rel.raw_id_admin:
     858                new_data[f.name] = ",".join([str(getattr(i, f.rel.to.pk.column)) for i in get_list_func()])
     859            elif not f.rel.edit_inline:
     860                new_data[f.name] = [getattr(i, f.rel.to.pk.column) for i in get_list_func()]
     861
     862        for rel_obj, rel_field in inline_related_objects:
     863            var_name = rel_obj.object_name.lower()
     864            for i, rel_instance in enumerate(getattr(obj, 'get_%s_list' % opts.get_rel_object_method_name(rel_obj, rel_field))()):
     865                for f in rel_obj.fields:
     866                    if f.editable and f != rel_field:
     867                        for k, v in f.flatten_data(getattr(rel_instance, f.column)).items():
     868                            new_data['%s.%d.%s' % (var_name, i, k)] = v
     869                for f in rel_obj.many_to_many:
     870                    new_data['%s.%d.%s' % (var_name, i, f.column)] = [j.id for j in getattr(rel_instance, 'get_%s_list' % f.rel.singular)()]
     871
     872        # If the object has ordered objects on its admin page, get the existing
     873        # order and flatten it into a comma-separated list of IDs.
     874        id_order_list = []
     875        for rel_obj in opts.get_ordered_objects():
     876            id_order_list.extend(getattr(obj, 'get_%s_order' % rel_obj.object_name.lower())())
     877        if id_order_list:
     878            new_data['order_'] = ','.join(map(str, id_order_list))
     879        errors = {}
     880
     881    # Populate the FormWrapper.
     882    form = formfields.FormWrapper(manipulator, new_data, errors)
     883    form.original = manipulator.original_object
     884    form.order_objects = []
     885    for rel_opts, rel_field in inline_related_objects:
     886        var_name = rel_opts.object_name.lower()
     887        wrapper = []
     888        orig_list = getattr(manipulator.original_object, 'get_%s_list' % opts.get_rel_object_method_name(rel_opts, rel_field))()
     889        count = len(orig_list) + rel_field.rel.num_extra_on_change
     890        if rel_field.rel.min_num_in_admin:
     891            count = max(count, rel_field.rel.min_num_in_admin)
     892        if rel_field.rel.max_num_in_admin:
     893            count = min(count, rel_field.rel.max_num_in_admin)
     894        for i in range(count):
     895            collection = {'original': (i < len(orig_list) and orig_list[i] or None)}
     896            for f in rel_opts.fields + rel_opts.many_to_many:
     897                if f.editable and f != rel_field:
     898                    for field_name in f.get_manipulator_field_names(''):
     899                        full_field_name = '%s.%d.%s' % (var_name, i, field_name)
     900                        field = manipulator[full_field_name]
     901                        data = field.extract_data(new_data)
     902                        collection[field_name] = formfields.FormFieldWrapper(field, data, errors.get(full_field_name, []))
     903            wrapper.append(formfields.FormFieldCollection(collection))
     904        setattr(form, rel_opts.module_name, wrapper)
     905        if rel_opts.order_with_respect_to and rel_opts.order_with_respect_to.rel and rel_opts.order_with_respect_to.rel.to == opts:
     906            form.order_objects.extend(orig_list)
     907
     908    c = Context(request, {
     909        'title': 'Change %s' % opts.verbose_name,
     910        "form": form,
     911        'object_id': object_id,
     912        'original': manipulator.original_object,
     913        'is_popup' : request.REQUEST.has_key('_popup')
     914    })
     915
     916    fill_extra_context(opts, app_label, c, change=True)
     917   
     918    #raw_template = _get_template(opts, app_label, change=True)
     919    # return HttpResponse(raw_template, mimetype='text/plain')
     920    #t = template_loader.get_template_from_string(raw_template)
     921    t = template_loader.get_template("admin_change_form");
     922    return HttpResponse(t.render(c), mimetype='text/html; charset=utf-8')
     923
     924
    533925def _get_template(opts, app_label, add=False, change=False, show_delete=False, form_url=''):
    534926    admin_field_objs = opts.admin.get_field_objs(opts)
    535927    ordered_objects = opts.get_ordered_objects()[:]
     
    8021194        # Add default data.
    8031195        for f in opts.fields:
    8041196            if f.has_default():
    805                 new_data.update(_get_flattened_data(f, f.get_default()))
     1197                new_data.update( f.flatten_data(f.get_default()) )
    8061198            # In required many-to-one fields with only one available choice,
    8071199            # select that one available choice. Note: We have to check that
    8081200            # the length of choices is *2*, not 1, because SelectFields always
     
    8371229                if f.editable and f != rel_field and not isinstance(f, meta.AutoField):
    8381230                    for field_name in f.get_manipulator_field_names(''):
    8391231                        full_field_name = '%s.%d.%s' % (var_name, i, field_name)
    840                         collection[field_name] = formfields.FormFieldWrapper(manipulator[full_field_name], new_data.get(full_field_name, ''), errors.get(full_field_name, []))
     1232                        field = manipulator[full_field_name]
     1233                        data = field.extract_data(new_data)
     1234                        collection[field_name] = formfields.FormFieldWrapper(field, data, errors.get(full_field_name, []))
    8411235            wrapper.append(formfields.FormFieldCollection(collection))
    8421236        setattr(form, rel_opts.module_name, wrapper)
    8431237
     
    9151309        new_data = {}
    9161310        obj = manipulator.original_object
    9171311        for f in opts.fields:
    918             new_data.update(_get_flattened_data(f, getattr(obj, f.column)))
     1312            new_data.update(f.flatten_data(getattr(obj, f.column)))
    9191313        for f in opts.many_to_many:
    9201314            get_list_func = getattr(obj, 'get_%s_list' % f.rel.singular)
    9211315            if f.rel.raw_id_admin:
     
    9271321            for i, rel_instance in enumerate(getattr(obj, 'get_%s_list' % opts.get_rel_object_method_name(rel_obj, rel_field))()):
    9281322                for f in rel_obj.fields:
    9291323                    if f.editable and f != rel_field:
    930                         for k, v in _get_flattened_data(f, getattr(rel_instance, f.column)).items():
     1324                        for k, v in f.flatten_data(getattr(rel_instance, f.column)).items():
    9311325                            new_data['%s.%d.%s' % (var_name, i, k)] = v
    9321326                for f in rel_obj.many_to_many:
    9331327                    new_data['%s.%d.%s' % (var_name, i, f.column)] = [j.id for j in getattr(rel_instance, 'get_%s_list' % f.rel.singular)()]
     
    9601354                if f.editable and f != rel_field:
    9611355                    for field_name in f.get_manipulator_field_names(''):
    9621356                        full_field_name = '%s.%d.%s' % (var_name, i, field_name)
    963                         collection[field_name] = formfields.FormFieldWrapper(manipulator[full_field_name], new_data.get(full_field_name, f.get_default()), errors.get(full_field_name, []))
     1357                        field = manipulator[full_field_name]
     1358                        data = field.extract_data(new_data)
     1359                        collection[field_name] = formfields.FormFieldWrapper(field, data, errors.get(full_field_name, []))
    9641360            wrapper.append(formfields.FormFieldCollection(collection))
    9651361        setattr(form, rel_opts.module_name, wrapper)
    9661362        if rel_opts.order_with_respect_to and rel_opts.order_with_respect_to.rel and rel_opts.order_with_respect_to.rel.to == opts:
Back to Top