Ticket #535: django-admin-refactor-2.patch

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

updated patch

  • 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.existing_repr %}
     26                &nbsp;<strong>{{ bound_field.existing_repr|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);"> <img src="{% admin_media_prefix %}img/admin/selector-search.gif" width="16" height="16" alt="Lookup"></a>
     18        {% else  %}
     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/" class="add-another" id="add_{{ bound_field.label_name}}"> <img src="{% admin_media_prefix %}img/admin/icon_addlink.gif" width="10" height="10" alt="Add Another"/></a>
     21            {% endif %}
     22        {% endif %}
     23    {% endif %}
     24{% endif %}
     25   
     26
     27
  • 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
     6
     7from django.views.admin.main import BoundField
     8
     9class IncludeAdminScriptNode(template.Node):
     10      def __init__(self, var):
     11         self.var = var
     12 
     13      def render(self, context):
     14        resolved = template.resolve_variable(self.var, context)
     15        return '<script type="text/javascript" src="%s%s"></script>' % \
     16                (ADMIN_MEDIA_PREFIX, resolved)
     17         
     18class SubmitRowNode(template.Node):
     19      def __init__(self):
     20          pass
     21
     22      def render(self, context):
     23          change = context['change']
     24          add = context['add']
     25          show_delete = context['show_delete']
     26          ordered_objects = context['ordered_objects']
     27          save_as = context['save_as']
     28          has_delete_permission = context['has_delete_permission']
     29          is_popup = context['is_popup']
     30         
     31          t = ['<div class="submit-row">']
     32          onclick_attrib = ordered_objects and change and 'onclick="submitOrderForm();"' or ''
     33         
     34          if not is_popup:
     35                if has_delete_permission and (change or show_delete):
     36                   t.append('<p class="float-left"><a href="delete/" class="deletelink">Delete</a></p>')
     37                if change and save_as:
     38                   t.append('<input type="submit" value="Save as new" name="_saveasnew" %s/>' %  onclick_attrib)
     39                if (not save_as or add):
     40                   t.append('<input type="submit" value="Save and add another" name="_addanother" %s/>' %  onclick_attrib)
     41          t.append('<input type="submit" value="Save and continue editing" name="_continue" %s/>' %  onclick_attrib )
     42          t.append('<input type="submit" value="Save" class="default" %s/>' %  onclick_attrib)
     43          t.append('</div>\n')
     44         
     45          return ''.join(t)
     46
     47
     48
     49
     50class AdminFieldBoundNode(template.Node):
     51    def __init__(self, argument):
     52        self.argument = argument
     53   
     54    def render(self, context):
     55        argument_val = template.resolve_variable(self.argument, context)
     56        if (isinstance(argument_val, list)):
     57            bound_fields = argument_val
     58        else:
     59            bound_fields = [argument_val]
     60        add = context['add']
     61        change = context['change']
     62       
     63        context.push()
     64        context['bound_fields'] = bound_fields
     65        context['class_names'] = " ".join(self.get_class_names(bound_fields))
     66        t = template_loader.get_template("admin_field")
     67        output =  t.render(context)
     68        context.pop()
     69         
     70        return output
     71
     72    def get_class_names(self, bound_fields):
     73
     74        class_names = ['form-row']
     75        for bound_field in bound_fields:
     76            for f in bound_field.form_fields:
     77                if f.errors():
     78                    class_names.append('errors')
     79                    break
     80         
     81        # Assumes BooleanFields won't be stacked next to each other!
     82        if isinstance(bound_fields[0].field, meta.BooleanField):
     83            class_names.append('checkbox-row')
     84         
     85        return class_names
     86       
     87class FieldWidgetNode(template.Node):
     88    def __init__(self, bound_field_var):
     89        self.bound_field_var = bound_field_var
     90
     91    def render(self, context):
     92        bound_field = template.resolve_variable(self.bound_field_var, context)
     93        add = context['add']
     94        change = context['change']
     95       
     96        context.push()
     97        context['bound_field'] = bound_field
     98        t = template_loader.get_template("admin_field_widget")
     99        output =  t.render(context)
     100        context.pop()
     101         
     102        return output
     103
     104       
     105
     106class FieldWrapper(object):
     107    def __init__(self, field ):
     108        self.field = field
     109
     110    def needs_header(self):
     111        return not isinstance(self.field, meta.AutoField)
     112
     113    def header_class_attribute(self):
     114        return self.field.blank and ' class="optional"' or ''
     115
     116    def use_raw_id_admin(self):
     117         return isinstance(self.field.rel, (meta.ManyToOne, meta.ManyToMany)) \
     118                and self.field.rel.raw_id_admin
     119
     120class FormObjectWrapper(object):
     121    def __init__(self, obj, field_wrappers, i, object_name):
     122        self.obj = obj
     123        self.field_wrappers = field_wrappers
     124     
     125        form_prefix = '%s.%s.' % ( object_name, i)
     126     
     127        name_prefix = ''
     128     
     129        self.bound_fields = [ BoundField(0, fw.field, obj['original'], form_prefix,
     130                              name_prefix, True, self.resolve_form_fields(fw.field, name_prefix) ) \
     131                                for fw in self.field_wrappers ]
     132
     133   
     134    def resolve_form_fields(self,field, name_prefix):
     135        return [self.obj[name] for name in field.get_manipulator_field_names(name_prefix)]
     136
     137#HACK
     138    def has_errors(self):
     139        return max([ bool( len( self.obj[fw.field.name].errors() ) )  for fw in self.field_wrappers])
     140       
     141    def html_combined_error_list(self):
     142        return ''.join( [ self.obj[fw.field.name].html_error_list() for fw in self.field_wrappers])
     143
     144   
     145   
     146
     147class EditInlineNode(template.Node):
     148    def __init__(self, rel_var):
     149        self.rel_var = rel_var
     150   
     151    def render(self, context):
     152        relation = template.resolve_variable(self.rel_var, context)
     153        add, change = context['add'], context['change']
     154       
     155        context.push()
     156
     157        self.fill_context(relation, add, change, context)
     158       
     159        if relation.field.rel.edit_inline == meta.TABULAR:
     160            t = template_loader.get_template("admin_edit_inline_tabular")
     161        else:  # meta.STACKED
     162            t = template_loader.get_template("admin_edit_inline_stacked")   
     163       
     164        output = t.render(context)
     165       
     166        context.pop()
     167        return output
     168
     169       
     170    def fill_context(self, relation, add, change, context):
     171        field_wrapper_list = [FieldWrapper(f) for f in relation.obj.fields + relation.obj.many_to_many if f.editable and f != relation.field]
     172       
     173        var_name = relation.obj.object_name.lower()
     174       
     175        form_objects = template.resolve_variable('form.%s' % relation.obj.module_name , context)
     176        form_object_wrapper_list = [FormObjectWrapper(o,field_wrapper_list, i, var_name) for i,o in enumerate(form_objects)]
     177   
     178        context['field_wrapper_list'] = field_wrapper_list
     179        context['form_object_wrapper_list'] = form_object_wrapper_list
     180        context['num_headers'] = len(field_wrapper_list)
     181        context['original_row_needed'] = max([fw.use_raw_id_admin() for fw in field_wrapper_list])
     182        context['name_prefix'] = "%s." % (var_name,)
     183   
     184class FieldLabelNode(template.Node):
     185    def __init__(self, bound_field_var):
     186        self.bound_field_var = bound_field_var
     187       
     188    def render(self, context):
     189        bound_field = template.resolve_variable(self.bound_field_var, context)
     190        class_names = []
     191        if isinstance(bound_field.field, meta.BooleanField):
     192            class_names.append("vCheckboxLabel")
     193        else:
     194            if not bound_field.field.blank:
     195                class_names.append('required')
     196            if bound_field.index > 0:
     197                class_names.append('inline')
     198       
     199        class_str = class_names and ' class="%s"' % ' '.join(class_names) or ''
     200        return '<label for="%s"%s>%s:</label> ' % (bound_field.label_name, class_str, capfirst(bound_field.field.verbose_name) )
     201
     202class OutputAllNode(template.Node):
     203    def __init__(self, form_fields_var):
     204        self.form_fields_var = form_fields_var
     205   
     206    def render(self, context):
     207        form_fields = template.resolve_variable(self.form_fields_var, context)
     208        return ''.join([str(f) for f in form_fields])
     209
     210class AutoPopulatedFieldScriptNode(template.Node):
     211    def __init__(self, auto_pop_var):
     212        self.auto_pop_var = auto_pop_var
     213
     214    def render(self,context):
     215        auto_pop_fields = template.resolve_variable(self, context)
     216        change = context['change']
     217        for field in auto_populated_fields:
     218            t = []
     219            if change:
     220                t.append('document.getElementById("id_%s")._changed = true;' % field.name )
     221            else:
     222                t.append('document.getElementById("id_%s").onchange = function() { this._changed = true; };' % field.name)
     223
     224            add_values = ' + " " + '.join(['document.getElementById("id_%s").value' % g for g in field.prepopulate_from])
     225            for f in field.prepopulate_from:
     226                t.append("""
     227                         document.getElementById("id_%s").onkeyup = function() {
     228                                var e = document.getElementById("id_%s");
     229                                if(!e._changed) { e.value = URLify(%s, %s);}
     230                        }
     231                        """ % (f, field.name, add_values, field.maxlength)
     232                )
     233
     234        return ''.join(t)
     235
     236def do_include_admin_script(parser, token):
     237     tokens = token.contents.split()
     238     if len(tokens) != 2:
     239         raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0])
     240     
     241     return IncludeAdminScriptNode(tokens[1])
     242
     243def do_dummy(parser, token):
     244     return DummyNode(token.contents)
     245
     246def do_submit_row(parser, token):
     247     return SubmitRowNode()
     248
     249def do_admin_field_bound(parser, token):
     250    tokens = token.contents.split()
     251    if len(tokens) != 2:
     252        raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0])
     253    return AdminFieldBoundNode(tokens[1])
     254
     255
     256def do_field_label(parser, token):
     257    tokens = token.contents.split()
     258    if len(tokens) != 2:
     259        raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0])
     260    return FieldLabelNode(tokens[1])
     261
     262def do_field_widget(parser, token):
     263    tokens = token.contents.split()
     264    if len(tokens) != 2:
     265        raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0])
     266    return FieldWidgetNode(tokens[1])
     267
     268def do_output_all(parser, token):
     269    tokens = token.contents.split()
     270    if len(tokens) != 2:
     271        raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0])
     272    return OutputAllNode(tokens[1])
     273
     274
     275def do_edit_inline(parser, token):
     276    tokens = token.contents.split()
     277    if len(tokens) != 2:
     278        raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0])
     279    return EditInlineNode(tokens[1])
     280
     281def do_auto_populated_field_script(parser, token):
     282    tokens = token.contents.split()
     283    if len(tokens) != 2:
     284        raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0])
     285    return AutoPopulatedFieldScriptNode(tokens[1])
     286
     287
     288
     289template.register_tag('include_admin_script', do_include_admin_script)
     290template.register_tag('submit_row', do_submit_row )
     291template.register_tag('admin_field_bound', do_admin_field_bound)
     292template.register_tag('edit_inline', do_edit_inline)
     293template.register_tag('auto_populated_field_script', do_auto_populated_field_script)
     294template.register_tag('field_label', do_field_label)
     295template.register_tag('field_widget', do_field_widget)
     296template.register_tag('output_all', do_output_all)
     297         
     298         
  • 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        self._repr_filled = False
     576       
     577    def as_field_list(self):
     578        return [self.field]
     579
     580    def original_value(self):
     581        return self.original.__dict__[self.field.name]
     582       
     583    def _fetch_existing_repr(self, func_name):
     584        class_dict = self.original.__class__.__dict__
     585        func = class_dict.get(func_name)
     586        return func(self.original)
     587       
     588    def _fill_existing_repr(self):
     589        if self._repr_filled:
     590            return
     591        #HACK
     592        if isinstance(self.field.rel, meta.ManyToOne):
     593             func_name = 'get_%s' % self.field.name
     594             self._repr = self._fetch_existing_repr(func_name)
     595        elif isinstance(self.field.rel, meta.ManyToMany):
     596             func_name = 'get_%s_list' % self.field.name
     597             self._repr =  ",".join(self._fetch_existing_repr(func_name))
     598        self._repr_filled = True
     599             
     600    def existing_repr(self):
     601        self._fill_existing_repr()
     602        return self._repr
     603
     604    def __repr__(self):
     605        return repr(self.__dict__)
     606
     607   
     608
     609
     610class AdminFieldSet(object):
     611     def __init__(self, fieldset_name, options, bound_field_sets):
     612         self.name = fieldset_name
     613         self.options = options
     614         self.bound_field_sets = bound_field_sets
     615         self.classes = options.get('classes', '')
     616# self.fields = options['fields']
     617     
     618     def __repr__(self):
     619        return "Fieldset:(%s,%s)" % (self.name, self.bound_field_sets)
     620
     621class InlineRelatedObject(object):
     622     def __init__(self,obj, field):
     623        self.obj = obj
     624        self.field = field
     625       
     626
     627def bound_field_sets(opts, context, name_prefix):
     628    original = template.resolve_variable('original', context);
     629    form_prefix = ''
     630    fields = opts['fields']
     631    #raise repr(fields)
     632    bound_field_sets = [ [BoundField(i, f, original, form_prefix, name_prefix, False,
     633                                resolve_form_fields(f,name_prefix, context)) for i,f in enumerate(field)  ] for field in fields]
     634
     635    return bound_field_sets
     636
     637def resolve_form_fields(field, name_prefix, context):
     638   # raise repr(field.get_manipulator_field_names(name_prefix)) + "\n!!\n" + repr(context)
     639    return [template.resolve_variable(name, context) for name in field.get_manipulator_field_names(name_prefix)]
     640
     641
     642def fill_extra_context(opts, app_label, context, add=False, change=False, show_delete=False, form_url=''):
     643    admin_field_objs = opts.admin.get_field_objs(opts)
     644    ordered_objects = opts.get_ordered_objects()[:]
     645    auto_populated_fields = [f for f in opts.fields if f.prepopulate_from]
     646 
     647    javascript_imports = get_javascript_imports(opts,auto_populated_fields, ordered_objects, admin_field_objs);
     648   
     649    if ordered_objects:
     650        coltype = 'colMS'
     651    else:
     652        coltype = 'colM'
     653       
     654    has_absolute_url = hasattr(opts.get_model_module().Klass, 'get_absolute_url')
     655   
     656    form_enc_attrib = opts.has_field_type(meta.FileField) and 'enctype="multipart/form-data" ' or ''
     657
     658    admin_fieldsets = [AdminFieldSet(f, o, bound_field_sets(o, context, 'form.')) for f, o in admin_field_objs]
     659    inline_related_objects = [InlineRelatedObject(obj, field) for obj, field in opts.get_inline_related_objects()]
     660   
     661    ordered_object_names =   ' '.join(['object.%s' % o.pk.name for o in ordered_objects])
     662   
     663    extra_context = {
     664        'add': add,
     665        'change': change,
     666        'admin_field_objs' : admin_field_objs,
     667        'ordered_objects' : ordered_objects,
     668        'auto_populated_fields' : auto_populated_fields,
     669        'javascript_imports' : javascript_imports,
     670        'coltype' : coltype,
     671        'has_absolute_url': has_absolute_url,
     672        'form_enc_attrib': form_enc_attrib,
     673        'form_url' : form_url,
     674        'admin_fieldsets' : admin_fieldsets,
     675        'inline_related_objects': inline_related_objects,
     676        'ordered_object_names' : ordered_object_names,
     677        'content_type_id' : opts.get_content_type_id(),
     678        'save_on_top' : opts.admin.save_on_top,
     679        'verbose_name_plural': opts.verbose_name_plural,
     680        'save_as': opts.admin.save_as,
     681        'app_label': app_label,
     682        'object_name': opts.object_name,
     683        'has_delete_permission' : context['perms'][app_label][opts.get_delete_permission()]
     684    }
     685   
     686    context.update(extra_context)   
     687   
     688   
     689def add_stage_new(request, app_label, module_name, show_delete=False, form_url='', post_url='../', post_url_continue='../%s/', object_id_override=None):
     690    mod, opts = _get_mod_opts(app_label, module_name)
     691    if not request.user.has_perm(app_label + '.' + opts.get_add_permission()):
     692        raise PermissionDenied
     693    manipulator = mod.AddManipulator()
     694    if request.POST:
     695        new_data = request.POST.copy()
     696        if opts.has_field_type(meta.FileField):
     697            new_data.update(request.FILES)
     698        errors = manipulator.get_validation_errors(new_data)
     699        if not errors and not request.POST.has_key("_preview"):
     700            for f in opts.many_to_many:
     701                if f.rel.raw_id_admin:
     702                    new_data.setlist(f.name, new_data[f.name].split(","))
     703            manipulator.do_html2python(new_data)
     704            new_object = manipulator.save(new_data)
     705            pk_value = getattr(new_object, opts.pk.column)
     706            log.log_action(request.user.id, opts.get_content_type_id(), pk_value, repr(new_object), log.ADDITION)
     707            msg = 'The %s "%s" was added successfully.' % (opts.verbose_name, new_object)
     708            # Here, we distinguish between different save types by checking for
     709            # the presence of keys in request.POST.
     710            if request.POST.has_key("_continue"):
     711                request.user.add_message("%s You may edit it again below." % msg)
     712                if request.POST.has_key("_popup"):
     713                    post_url_continue += "?_popup=1"
     714                return HttpResponseRedirect(post_url_continue % pk_value)
     715            if request.POST.has_key("_popup"):
     716                return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %s, "%s");</script>' % \
     717                    (pk_value, repr(new_object).replace('"', '\\"')), mimetype='text/html; charset=utf-8')
     718            elif request.POST.has_key("_addanother"):
     719                request.user.add_message("%s You may add another %s below." % (msg, opts.verbose_name))
     720                return HttpResponseRedirect(request.path)
     721            else:
     722                request.user.add_message(msg)
     723                return HttpResponseRedirect(post_url)
     724        if request.POST.has_key("_preview"):
     725            manipulator.do_html2python(new_data)
     726    else:
     727        new_data = {}
     728        # Add default data.
     729        for f in opts.fields:
     730            if f.has_default():
     731                new_data.update( f.flatten_data(f.get_default()) )
     732            # In required many-to-one fields with only one available choice,
     733            # select that one available choice. Note: We have to check that
     734            # the length of choices is *2*, not 1, because SelectFields always
     735            # have an initial "blank" value.
     736            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:
     737                new_data[f.name] = manipulator[f.name].choices[1][0]
     738        # In required many-to-many fields with only one available choice,
     739        # select that one available choice.
     740        for f in opts.many_to_many:
     741            if not f.blank and not f.rel.edit_inline and not f.rel.raw_id_admin and len(manipulator[f.name].choices) == 1:
     742                new_data[f.name] = [manipulator[f.name].choices[0][0]]
     743        # Add default data for related objects.
     744        for rel_opts, rel_field in opts.get_inline_related_objects():
     745            var_name = rel_opts.object_name.lower()
     746            for i in range(rel_field.rel.num_in_admin):
     747                for f in rel_opts.fields + rel_opts.many_to_many:
     748                    if f.has_default():
     749                        for field_name in f.get_manipulator_field_names(''):
     750                            new_data['%s.%d.%s' % (var_name, i, field_name)] = f.get_default()
     751        # Override the defaults with request.GET, if it exists.
     752        new_data.update(request.GET)
     753        errors = {}
     754
     755    # Populate the FormWrapper.
     756    form = formfields.FormWrapper(manipulator, new_data, errors)
     757    for rel_opts, rel_field in opts.get_inline_related_objects():
     758        var_name = rel_opts.object_name.lower()
     759        wrapper = []
     760        for i in range(rel_field.rel.num_in_admin):
     761            collection = {}
     762            for f in rel_opts.fields + rel_opts.many_to_many:
     763                if f.editable and f != rel_field and not isinstance(f, meta.AutoField):
     764                    for field_name in f.get_manipulator_field_names(''):
     765                        full_field_name = '%s.%d.%s' % (var_name, i, field_name)
     766                        field = manipulator[full_field_name]
     767                        data = field.extract_data(new_data)
     768                        collection[field_name] = formfields.FormFieldWrapper(field, data, errors.get(full_field_name, []))
     769            wrapper.append(formfields.FormFieldCollection(collection))
     770        setattr(form, rel_opts.module_name, wrapper)
     771
     772    c = Context(request, {
     773        'title': 'Add %s' % opts.verbose_name,
     774        "form": form,
     775        "is_popup": request.REQUEST.has_key("_popup"),
     776    })
     777    if object_id_override is not None:
     778        c['object_id'] = object_id_override
     779    #raw_template = _get_template(opts, app_label, add=True, show_delete=show_delete, form_url=form_url)
     780#     return HttpResponse(raw_template, mimetype='text/plain')
     781   # t = template_loader.get_template_from_string(raw_template)
     782   
     783    fill_extra_context(opts, app_label, c, change=True)
     784    #raw_template = _get_template(opts, app_label, change=True)
     785    # return HttpResponse(raw_template, mimetype='text/plain')
     786    #t = template_loader.get_template_from_string(raw_template)
     787    t = template_loader.get_template("admin_change_form");
     788   
     789    return HttpResponse(t.render(c), mimetype='text/html; charset=utf-8')
     790
     791
     792
     793def change_stage_new(request, app_label, module_name, object_id):
     794    mod, opts = _get_mod_opts(app_label, module_name)
     795    if not request.user.has_perm(app_label + '.' + opts.get_change_permission()):
     796        raise PermissionDenied
     797    if request.POST and request.POST.has_key("_saveasnew"):
     798        return add_stage_new(request, app_label, module_name, form_url='../add/')
     799    try:
     800        manipulator = mod.ChangeManipulator(object_id)
     801    except ObjectDoesNotExist:
     802        raise Http404
     803
     804    inline_related_objects = opts.get_inline_related_objects()
     805    if request.POST:
     806        new_data = request.POST.copy()
     807        if opts.has_field_type(meta.FileField):
     808            new_data.update(request.FILES)
     809
     810        errors = manipulator.get_validation_errors(new_data)
     811        if not errors and not request.POST.has_key("_preview"):
     812            for f in opts.many_to_many:
     813                if f.rel.raw_id_admin:
     814                    new_data.setlist(f.name, new_data[f.name].split(","))
     815            manipulator.do_html2python(new_data)
     816            new_object = manipulator.save(new_data)
     817            pk_value = getattr(new_object, opts.pk.column)
     818
     819            # Construct the change message.
     820            change_message = []
     821            if manipulator.fields_added:
     822                change_message.append('Added %s.' % get_text_list(manipulator.fields_added, 'and'))
     823            if manipulator.fields_changed:
     824                change_message.append('Changed %s.' % get_text_list(manipulator.fields_changed, 'and'))
     825            if manipulator.fields_deleted:
     826                change_message.append('Deleted %s.' % get_text_list(manipulator.fields_deleted, 'and'))
     827            change_message = ' '.join(change_message)
     828            if not change_message:
     829                change_message = 'No fields changed.'
     830
     831            log.log_action(request.user.id, opts.get_content_type_id(), pk_value, repr(new_object), log.CHANGE, change_message)
     832            msg = 'The %s "%s" was changed successfully.' % (opts.verbose_name, new_object)
     833            if request.POST.has_key("_continue"):
     834                request.user.add_message("%s You may edit it again below." % msg)
     835                if request.REQUEST.has_key('_popup'):
     836                    return HttpResponseRedirect(request.path + "?_popup=1")
     837                else:
     838                    return HttpResponseRedirect(request.path)
     839            elif request.POST.has_key("_saveasnew"):
     840                request.user.add_message('The %s "%s" was added successfully. You may edit it again below.' % (opts.verbose_name, new_object))
     841                return HttpResponseRedirect("../%s/" % pk_value)
     842            elif request.POST.has_key("_addanother"):
     843                request.user.add_message("%s You may add another %s below." % (msg, opts.verbose_name))
     844                return HttpResponseRedirect("../add/")
     845            else:
     846                request.user.add_message(msg)
     847                return HttpResponseRedirect("../")
     848        if request.POST.has_key("_preview"):
     849            manipulator.do_html2python(new_data)
     850    else:
     851        # Populate new_data with a "flattened" version of the current data.
     852        new_data = {}
     853        obj = manipulator.original_object
     854        for f in opts.fields:
     855            new_data.update(f.flatten_data(getattr(obj, f.column)))
     856       
     857        for f in opts.many_to_many:
     858            get_list_func = getattr(obj, 'get_%s_list' % f.rel.singular)
     859            if f.rel.raw_id_admin:
     860                new_data[f.name] = ",".join([str(getattr(i, f.rel.to.pk.column)) for i in get_list_func()])
     861            elif not f.rel.edit_inline:
     862                new_data[f.name] = [getattr(i, f.rel.to.pk.column) for i in get_list_func()]
     863
     864        for rel_obj, rel_field in inline_related_objects:
     865            var_name = rel_obj.object_name.lower()
     866            for i, rel_instance in enumerate(getattr(obj, 'get_%s_list' % opts.get_rel_object_method_name(rel_obj, rel_field))()):
     867                for f in rel_obj.fields:
     868                    if f.editable and f != rel_field:
     869                        for k, v in f.flatten_data(getattr(rel_instance, f.column)).items():
     870                            new_data['%s.%d.%s' % (var_name, i, k)] = v
     871                for f in rel_obj.many_to_many:
     872                    new_data['%s.%d.%s' % (var_name, i, f.column)] = [j.id for j in getattr(rel_instance, 'get_%s_list' % f.rel.singular)()]
     873
     874        # If the object has ordered objects on its admin page, get the existing
     875        # order and flatten it into a comma-separated list of IDs.
     876        id_order_list = []
     877        for rel_obj in opts.get_ordered_objects():
     878            id_order_list.extend(getattr(obj, 'get_%s_order' % rel_obj.object_name.lower())())
     879        if id_order_list:
     880            new_data['order_'] = ','.join(map(str, id_order_list))
     881        errors = {}
     882
     883    # Populate the FormWrapper.
     884    form = formfields.FormWrapper(manipulator, new_data, errors)
     885    form.original = manipulator.original_object
     886    form.order_objects = []
     887    for rel_opts, rel_field in inline_related_objects:
     888        var_name = rel_opts.object_name.lower()
     889        wrapper = []
     890        orig_list = getattr(manipulator.original_object, 'get_%s_list' % opts.get_rel_object_method_name(rel_opts, rel_field))()
     891        count = len(orig_list) + rel_field.rel.num_extra_on_change
     892        if rel_field.rel.min_num_in_admin:
     893            count = max(count, rel_field.rel.min_num_in_admin)
     894        if rel_field.rel.max_num_in_admin:
     895            count = min(count, rel_field.rel.max_num_in_admin)
     896        for i in range(count):
     897            collection = {'original': (i < len(orig_list) and orig_list[i] or None)}
     898            for f in rel_opts.fields + rel_opts.many_to_many:
     899                if f.editable and f != rel_field:
     900                    for field_name in f.get_manipulator_field_names(''):
     901                        full_field_name = '%s.%d.%s' % (var_name, i, field_name)
     902                        field = manipulator[full_field_name]
     903                        data = field.extract_data(new_data)
     904                        collection[field_name] = formfields.FormFieldWrapper(field, data, errors.get(full_field_name, []))
     905            wrapper.append(formfields.FormFieldCollection(collection))
     906        setattr(form, rel_opts.module_name, wrapper)
     907        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:
     908            form.order_objects.extend(orig_list)
     909
     910    c = Context(request, {
     911        'title': 'Change %s' % opts.verbose_name,
     912        "form": form,
     913        'object_id': object_id,
     914        'original': manipulator.original_object,
     915        'is_popup' : request.REQUEST.has_key('_popup')
     916    })
     917
     918    fill_extra_context(opts, app_label, c, change=True)
     919   
     920    #raw_template = _get_template(opts, app_label, change=True)
     921    # return HttpResponse(raw_template, mimetype='text/plain')
     922    #t = template_loader.get_template_from_string(raw_template)
     923    t = template_loader.get_template("admin_change_form");
     924    return HttpResponse(t.render(c), mimetype='text/html; charset=utf-8')
     925
     926
    533927def _get_template(opts, app_label, add=False, change=False, show_delete=False, form_url=''):
    534928    admin_field_objs = opts.admin.get_field_objs(opts)
    535929    ordered_objects = opts.get_ordered_objects()[:]
     
    8021196        # Add default data.
    8031197        for f in opts.fields:
    8041198            if f.has_default():
    805                 new_data.update(_get_flattened_data(f, f.get_default()))
     1199                new_data.update( f.flatten_data(f.get_default()) )
    8061200            # In required many-to-one fields with only one available choice,
    8071201            # select that one available choice. Note: We have to check that
    8081202            # the length of choices is *2*, not 1, because SelectFields always
     
    8371231                if f.editable and f != rel_field and not isinstance(f, meta.AutoField):
    8381232                    for field_name in f.get_manipulator_field_names(''):
    8391233                        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, []))
     1234                        field = manipulator[full_field_name]
     1235                        data = field.extract_data(new_data)
     1236                        collection[field_name] = formfields.FormFieldWrapper(field, data, errors.get(full_field_name, []))
    8411237            wrapper.append(formfields.FormFieldCollection(collection))
    8421238        setattr(form, rel_opts.module_name, wrapper)
    8431239
     
    9151311        new_data = {}
    9161312        obj = manipulator.original_object
    9171313        for f in opts.fields:
    918             new_data.update(_get_flattened_data(f, getattr(obj, f.column)))
     1314            new_data.update(f.flatten_data(getattr(obj, f.column)))
    9191315        for f in opts.many_to_many:
    9201316            get_list_func = getattr(obj, 'get_%s_list' % f.rel.singular)
    9211317            if f.rel.raw_id_admin:
     
    9271323            for i, rel_instance in enumerate(getattr(obj, 'get_%s_list' % opts.get_rel_object_method_name(rel_obj, rel_field))()):
    9281324                for f in rel_obj.fields:
    9291325                    if f.editable and f != rel_field:
    930                         for k, v in _get_flattened_data(f, getattr(rel_instance, f.column)).items():
     1326                        for k, v in f.flatten_data(getattr(rel_instance, f.column)).items():
    9311327                            new_data['%s.%d.%s' % (var_name, i, k)] = v
    9321328                for f in rel_obj.many_to_many:
    9331329                    new_data['%s.%d.%s' % (var_name, i, f.column)] = [j.id for j in getattr(rel_instance, 'get_%s_list' % f.rel.singular)()]
     
    9601356                if f.editable and f != rel_field:
    9611357                    for field_name in f.get_manipulator_field_names(''):
    9621358                        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, []))
     1359                        field = manipulator[full_field_name]
     1360                        data = field.extract_data(new_data)
     1361                        collection[field_name] = formfields.FormFieldWrapper(field, data, errors.get(full_field_name, []))
    9641362            wrapper.append(formfields.FormFieldCollection(collection))
    9651363        setattr(form, rel_opts.module_name, wrapper)
    9661364        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