Ticket #535: django-admin-refactor-4.patch
File django-admin-refactor-4.patch, 64.5 KB (added by , 19 years ago) |
---|
-
django/conf/urls/admin.py
48 48 49 49 urlpatterns += ( 50 50 # 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'), 51 53 ('^(?P<app_label>[^/]+)/(?P<module_name>[^/]+)/$', 'django.views.admin.main.change_list'), 52 54 ('^(?P<app_label>[^/]+)/(?P<module_name>[^/]+)/add/$', 'django.views.admin.main.add_stage'), 53 55 ('^(?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> › 19 <a href="../">{{verbose_name_plural|capfirst}}</a> › 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 86 {% for relation in inline_related_objects %} 87 {% edit_inline relation %} 88 {% endfor %} 89 90 {% submit_row %} 91 92 {% if add %} 93 <script type="text/javascript">document.getElementById("id_{{first_field}}").focus();</script>' 94 {% endif %} 95 96 {% if auto_populated_fields %} 97 <script type="text/javascript"> 98 {% auto_populated_field_script auto_populated_fields %} 99 </script> 100 {% endif %} 101 102 {% if change %} 103 {% if ordered_objects %} 104 {% if form.order_objects %}<ul id="orderthese"> 105 {% for object in form.order_objects %} 106 <li id="p{% firstof ordered_object_names %}"> 107 <span id="handlep{% firstof ordered_object_names %}">{{ object|truncatewords:"5" }}</span> 108 </li> 109 {% endfor%} 110 {% endif %} 111 {% endif %} 112 {% endif%} 113 </form> 114 115 {% 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.opts.verbose_name|capfirst }} #{{ 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 <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.opts.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/conf/settings.py
26 26 if not me.SETTINGS_MODULE: # If it's set but is an empty string. 27 27 raise KeyError 28 28 except KeyError: 29 raise EnvironmentError, "Environment variable %s is undefined." % ENVIRONMENT_VARIABLE29 raise EnvironmentError, "Environment variable %s is undefined." % (ENVIRONMENT_VARIABLE) 30 30 31 31 try: 32 32 mod = __import__(me.SETTINGS_MODULE, '', '', ['']) -
django/core/formfields.py
87 87 must happen after validation because html2python functions aren't 88 88 expected to deal with invalid input. 89 89 """ 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 """ 100 93 94 for field in self.fields: 95 field.convert_post_data(new_data) 96 101 97 class FormWrapper: 102 98 """ 103 99 A wrapper linking a Manipulator to the template system. 104 100 This allows dictionary-style lookups of formfields. It also handles feeding 105 101 prepopulated data and validation error messages to the formfield objects. 106 102 """ 107 def __init__(self, manipulator, data, error_dict ):103 def __init__(self, manipulator, data, error_dict, edit_inline = False): 108 104 self.manipulator, self.data = manipulator, data 109 105 self.error_dict = error_dict 106 self._inline_collections = None 107 self.edit_inline = edit_inline 110 108 111 109 def __repr__(self): 112 return repr(self. data)110 return repr(self.__dict__) 113 111 114 112 def __getitem__(self, key): 115 113 for field in self.manipulator.fields: 116 114 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, [])) 115 116 data = field.extract_data(self.data) 117 118 return FormFieldWrapper(field, data, self.error_dict.get(field.field_name, [])) 119 if self.edit_inline: 120 self.fill_inline_collections() 121 for inline_collection in self._inline_collections: 122 if inline_collection.name == key: 123 return inline_collection 124 124 125 raise KeyError 125 126 127 def fill_inline_collections(self): 128 if not self._inline_collections: 129 ic = [] 130 i = 0 131 related_objects = self.manipulator.get_inline_related_objects_wrapped() 132 for rel_obj in related_objects: 133 i += 1 134 data = rel_obj.extract_data(self.data) 135 inline_collection = InlineObjectCollection(self.manipulator, rel_obj, data, self.error_dict) 136 ic.append(inline_collection) 137 self._inline_collections = ic 138 139 140 126 141 def has_errors(self): 127 142 return self.error_dict != {} 128 143 … … 155 170 else: 156 171 return '' 157 172 173 158 174 class FormFieldCollection(FormFieldWrapper): 159 175 "A utility class that gives the template access to a dict of FormFieldWrappers" 160 176 def __init__(self, formfield_dict): … … 177 193 errors.extend(field.errors()) 178 194 return errors 179 195 196 197 198 199 200 class InlineObjectCollection: 201 "An object that acts like a list of form field collections." 202 def __init__(self, parent_manipulator, rel_obj, data, errors): 203 self.parent_manipulator = parent_manipulator 204 self.rel_obj = rel_obj 205 self.data = data 206 self.errors = errors 207 self._collections = None 208 self.name = rel_obj.name 209 210 def __len__(self): 211 self.fill() 212 return self._collections.__len__() 213 214 def __getitem__(self, k): 215 self.fill() 216 return self._collections.__getitem__(k) 217 218 def __setitem__(self, k, v): 219 self.fill() 220 return self._collections.__setitem__(k,v) 221 222 def __delitem__(self, k): 223 self.fill() 224 return self._collections.__delitem__(k) 225 226 def __iter__(self): 227 self.fill() 228 return self._collections.__iter__() 229 230 def fill(self): 231 if self._collections: 232 return 233 else: 234 var_name = self.rel_obj.opts.object_name.lower() 235 wrapper = [] 236 orig = hasattr(self.parent_manipulator, 'original_object') and self.parent_manipulator.original_object or None 237 orig_list = self.rel_obj.get_list(orig) 238 for i, instance in enumerate(orig_list): 239 collection = {'original': instance } 240 for f in self.rel_obj.editable_fields(): 241 for field_name in f.get_manipulator_field_names(''): 242 full_field_name = '%s.%d.%s' % (var_name, i, field_name) 243 field = self.parent_manipulator[full_field_name] 244 data = field.extract_data(self.data) 245 collection[field_name] = FormFieldWrapper(field, data, self.errors.get(full_field_name, [])) 246 wrapper.append(FormFieldCollection(collection)) 247 self._collections = wrapper 248 180 249 class FormField: 181 250 """Abstract class representing a form field. 182 251 … … 209 278 def render(self, data): 210 279 raise NotImplementedError 211 280 281 def get_member_name(self): 282 return self.field_name 283 284 def extract_data(self, data_dict): 285 if hasattr(self, 'requires_data_list') and hasattr(data_dict, 'getlist'): 286 data = data_dict.getlist(self.get_member_name()) 287 else: 288 data = data_dict.get(self.get_member_name(), None) 289 if data is None: 290 data = '' 291 self.data_dict = data_dict 292 return data 293 294 def convert_post_data(self, new_data): 295 name = self.get_member_name() 296 if new_data.has_key(self.field_name): 297 d = new_data.getlist(self.field_name) 298 #del new_data[self.field_name] 299 new_data.setlist(name, 300 [self.__class__.html2python(data) 301 for data in d]) 302 else: 303 try: 304 # individual fields deal with None values themselves 305 new_data.setlist(name, [self.__class__.html2python(None)]) 306 except EmptyValue: 307 new_data.setlist(name, []) 308 212 309 #################### 213 310 # GENERIC WIDGETS # 214 311 #################### … … 319 416 output.append(' </select>') 320 417 return '\n'.join(output) 321 418 419 def get_member_name(self): 420 return "%s_id" % self.field_name 421 322 422 def isValidChoice(self, data, form): 323 423 str_data = str(data) 324 424 str_choices = [str(item[0]) for item in self.choices] -
django/core/meta/__init__.py
146 146 class BadKeywordArguments(Exception): 147 147 pass 148 148 149 150 class InlineRelatedObject(object): 151 def __init__(self,parent_opts, opts, field): 152 self.parent_opts = parent_opts 153 self.opts = opts 154 self.field = field 155 self.name = opts.module_name 156 157 def flatten_data(self,obj = None): 158 var_name = self.opts.object_name.lower() 159 new_data = {} 160 rel_instances = self.get_list(obj) 161 162 for i, rel_instance in enumerate(rel_instances): 163 instance_data = {} 164 for f in self.opts.fields + self.opts.many_to_many: 165 field_data = f.flatten_data(rel_instance) 166 if hasattr(f, 'editable') and f.editable and f != self.field: 167 for name, value in field_data.items(): 168 instance_data['%s.%d.%s' % (var_name, i, name)] = value 169 new_data.update(instance_data) 170 171 return new_data 172 173 def extract_data(self, data): 174 "Pull out the data meant for inline objects of this class, ie anything starting with our module name" 175 return data # TODO 176 177 def get_list(self, parent_instance = None): 178 "Get the list of this type of object from an instance of the parent class" 179 if parent_instance != None: 180 func_name = 'get_%s_list' % self.parent_opts.get_rel_object_method_name(self.opts, self.field) 181 func = getattr(parent_instance, func_name) 182 list = func() 183 184 count = len(list) + self.field.rel.num_extra_on_change 185 if self.field.rel.min_num_in_admin: 186 count = max(count, self.field.rel.min_num_in_admin) 187 if self.field.rel.max_num_in_admin: 188 count = min(count, self.field.rel.max_num_in_admin) 189 190 change = count - len(list) 191 if change > 0: 192 return list + [None for _ in range(change)] 193 if change < 0: 194 return list[:change] 195 else: # Just right 196 return list 197 else: 198 return [None for _ in range(self.field.rel.num_in_admin)] 199 200 201 def editable_fields(self): 202 "Get the fields in this class that should be edited inline" 203 return [f for f in self.opts.fields + self.opts.many_to_many if f.editable and f != self.field ] 204 205 def __repr__(self): 206 return "<InlineRelatedObject: %s related to %s>" % ( self.name, self.field.name) 207 208 209 149 210 class Options: 150 211 def __init__(self, module_name='', verbose_name='', verbose_name_plural='', db_table='', 151 212 fields=None, ordering=None, unique_together=None, admin=None, has_related_links=False, … … 317 378 def get_inline_related_objects(self): 318 379 return [(a, b) for a, b in self.get_all_related_objects() if b.rel.edit_inline] 319 380 381 def get_inline_related_objects_wrapped(self): 382 return [InlineRelatedObject(self, opts, field) for opts, field in self.get_all_related_objects() if field.rel.edit_inline] 383 384 def get_data_holders(self): 385 return self.fields + self.many_to_many + self.get_inline_related_objects_wrapped() 386 320 387 def get_all_related_many_to_many_objects(self): 321 388 module_list = get_installed_model_modules() 322 389 rel_objs = [] … … 592 659 new_mod.get_latest = curry(function_get_latest, opts, new_class, does_not_exist_exception) 593 660 594 661 for f in opts.fields: 662 if len(f.choices) != 0: 663 # Add an accessor method to get to the human readable value 664 func = curry(method_get_display_value, f) 665 setattr(new_class, 'get_%s_display' % f.name , func) 595 666 if isinstance(f, DateField) or isinstance(f, DateTimeField): 596 667 # Add "get_next_by_thingie" and "get_previous_by_thingie" methods 597 668 # for all DateFields and DateTimeFields that cannot be null. … … 782 853 # If it does already exist, do an UPDATE. 783 854 if cursor.fetchone(): 784 855 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), 856 while 1: 857 try: 858 idx = db_values.index('') 859 non_pks[idx:idx+1] = [] 860 db_values[idx:idx +1] = [] 861 except: break 862 cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % (opts.db_table, 863 ','.join(['%s=%%s' % f.column for f in non_pks]), opts.pk.column), 787 864 db_values + [pk_val]) 788 865 else: 789 866 record_exists = False … … 991 1068 kwargs['limit'] = 1 992 1069 return get_object_func(**kwargs) 993 1070 1071 # CHOICE-RELATED METHODS ################### 1072 1073 def method_get_display_value(field, self): 1074 value = getattr(self, field.name) 1075 for (v, d) in field.choices: 1076 if v==value: 1077 return d 1078 # Couldn't find it in the list 1079 return value 1080 994 1081 # FILE-RELATED METHODS ##################### 995 1082 996 1083 def method_get_file_filename(field, self): … … 1386 1473 man.__module__ = MODEL_PREFIX + '.' + opts.module_name # Set this explicitly, as above. 1387 1474 man.__init__ = curry(manipulator_init, opts, add, change) 1388 1475 man.save = curry(manipulator_save, opts, klass, add, change) 1476 man.get_inline_related_objects_wrapped = curry(manipulator_get_inline_related_objects_wrapped, opts, klass, add, change) 1477 man.flatten_data = curry(manipulator_flatten_data, opts, klass, add, change) 1389 1478 for field_name_list in opts.unique_together: 1390 1479 setattr(man, 'isUnique%s' % '_'.join(field_name_list), curry(manipulator_validator_unique_together, field_name_list, opts)) 1391 1480 for f in opts.fields: … … 1582 1671 getattr(new_object, 'set_%s_order' % rel_opts.object_name.lower())(order) 1583 1672 return new_object 1584 1673 1674 def manipulator_get_inline_related_objects_wrapped(opts, klass, add, change, self): 1675 return opts.get_inline_related_objects_wrapped() 1676 1677 def manipulator_flatten_data(opts, klass, add, change, self): 1678 new_data = {} 1679 obj = change and self.original_object or None 1680 for f in opts.get_data_holders(): 1681 new_data.update(f.flatten_data(obj)) 1682 return new_data 1683 1585 1684 def manipulator_validator_unique_together(field_name_list, opts, self, field_data, all_data): 1586 1685 from django.utils.text import get_text_list 1587 1686 field_list = [opts.get_field(field_name) for field_name in field_name_list] -
django/core/meta/fields.py
180 180 else: 181 181 if self.radio_admin: 182 182 field_objs = [formfields.RadioSelectField] 183 params['choices'] = self.get_choices(include_blank=self.blank, blank_choice=BLANK_CHOICE_NONE)184 183 params['ul_class'] = get_ul_class(self.radio_admin) 185 184 else: 186 185 if self.null: 187 186 field_objs = [formfields.NullSelectField] 188 187 else: 189 188 field_objs = [formfields.SelectField] 190 params['choices'] = self.get_choices()189 params['choices'] = self.get_choices_default() 191 190 elif self.choices: 192 191 if self.radio_admin: 193 192 field_objs = [formfields.RadioSelectField] 194 params['choices'] = self.get_choices(include_blank=self.blank, blank_choice=BLANK_CHOICE_NONE)195 193 params['ul_class'] = get_ul_class(self.radio_admin) 196 194 else: 197 195 field_objs = [formfields.SelectField] 198 params['choices'] = self.get_choices() 196 197 params['choices'] = self.get_choices_default() 199 198 else: 200 199 field_objs = self.get_manipulator_field_objs() 201 200 … … 255 254 val = None 256 255 return val 257 256 257 258 258 def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH): 259 259 "Returns a list of tuples used as SelectField choices for this field." 260 260 261 first_choice = include_blank and blank_choice or [] 261 262 if self.choices: 262 263 return first_choice + list(self.choices) 263 264 rel_obj = self.rel.to 264 265 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)] 265 266 267 def get_choices_default(self): 268 if(self.radio_admin): 269 return self.get_choices(include_blank=self.blank, blank_choice=BLANK_CHOICE_NONE) 270 else: 271 return self.get_choices() 272 273 def _get_val_from_obj(self, obj): 274 if obj: 275 return getattr(obj, self.column) 276 else: 277 return self.get_default() 278 279 def flatten_data(self, obj = None): 280 """ 281 Returns a dictionary mapping the field's manipulator field names to its 282 "flattened" string values for the admin view. Obj is the instance to extract the 283 values from. 284 """ 285 return { self.get_db_column(): self._get_val_from_obj(obj)} 286 287 266 288 class AutoField(Field): 267 289 empty_strings_allowed = False 268 290 def __init__(self, *args, **kwargs): … … 327 349 def get_manipulator_field_objs(self): 328 350 return [formfields.DateField] 329 351 352 def flatten_data(self, obj = None): 353 val = self._get_val_from_obj(obj) 354 return {self.get_db_column(): (val is not None and val.strftime("%Y-%m-%d") or '')} 355 330 356 class DateTimeField(DateField): 331 357 def get_db_prep_save(self, value): 332 358 # Casts dates into string format for entry into database. … … 356 382 return datetime.datetime.combine(d, t) 357 383 return self.get_default() 358 384 385 def flatten_data(self,obj = None): 386 val = self._get_val_from_obj(obj) 387 date_field, time_field = self.get_manipulator_field_names('') 388 return {date_field: (val is not None and val.strftime("%Y-%m-%d") or ''), 389 time_field: (val is not None and val.strftime("%H:%M:%S") or '')} 390 359 391 class EmailField(Field): 360 392 def get_manipulator_field_objs(self): 361 393 return [formfields.EmailField] … … 539 571 def get_manipulator_field_objs(self): 540 572 return [formfields.TimeField] 541 573 574 def flatten_data(self,obj = None): 575 val = self._get_val_from_obj(obj) 576 return {self.get_db_column(): (val is not None and val.strftime("%H:%M:%S") or '')} 577 542 578 class URLField(Field): 543 579 def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs): 544 580 if verify_exists: … … 592 628 def get_manipulator_field_objs(self): 593 629 return [formfields.IntegerField] 594 630 631 def flatten_data(self, obj = None): 632 if not obj: 633 # In required many-to-one fields with only one available choice, 634 # select that one available choice. Note: We have to check that 635 # the length of choices is *2*, not 1, because SelectFields always 636 # have an initial "blank" value. 637 if not self.blank and not self.rel.raw_id_admin and self.choices: 638 choice_list = self.get_choices_default() 639 if len(choice_list) == 2: 640 return { self.name : choice_list[1][0] } 641 return Field.flatten_data(self, obj) 642 595 643 class ManyToManyField(Field): 596 644 def __init__(self, to, **kwargs): 597 645 kwargs['verbose_name'] = kwargs.get('verbose_name', to._meta.verbose_name_plural) … … 609 657 if self.rel.raw_id_admin: 610 658 return [formfields.CommaSeparatedIntegerField] 611 659 else: 612 choices = self.get_choices (include_blank=False)660 choices = self.get_choices_default() 613 661 return [curry(formfields.SelectMultipleField, size=min(max(len(choices), 5), 15), choices=choices)] 614 662 663 def get_choices_default(self): 664 Field.get_choices(self, include_blank=False) 665 615 666 def get_m2m_db_table(self, original_opts): 616 667 "Returns the name of the many-to-many 'join' table." 617 668 return '%s_%s' % (original_opts.db_table, self.name) … … 632 683 len(badkeys) == 1 and badkeys[0] or tuple(badkeys), 633 684 len(badkeys) == 1 and "is" or "are") 634 685 686 def flatten_data(self, obj = None): 687 new_data = {} 688 if obj: 689 get_list_func = getattr(obj, 'get_%s_list' % self.rel.singular) 690 instance_ids = [getattr(instance, self.rel.to.pk.column) for instance in get_list_func()] 691 if self.rel.raw_id_admin: 692 new_data[self.name] = ",".join([str(id) for id in instance_ids]) 693 elif not f.rel.edit_inline: 694 new_data[self.name] = instance_ids 695 else: 696 # In required many-to-many fields with only one available choice, 697 # select that one available choice. 698 if not self.blank and not self.rel.edit_inline and not self.rel.raw_id_admin and self.choices: 699 choice_list = self.get_choices_default() 700 if len(choice_list) == 1: 701 new_data[self.name] = [choices_list[0][0]] 702 return new_data 703 704 635 705 class OneToOneField(IntegerField): 636 706 def __init__(self, to, to_field=None, **kwargs): 637 707 kwargs['verbose_name'] = kwargs.get('verbose_name', 'ID') … … 714 784 Returns self.fields, except with fields as Field objects instead of 715 785 field names. If self.fields is None, defaults to putting every 716 786 non-AutoField field with editable=True in a single fieldset. 787 788 returns a list of lists of name, dict 789 the dict has attribs 'fields' and maybe 'classes'. 790 fields is a list of subclasses of Field. 791 792 Return value needs to be encapsulated. 717 793 """ 718 794 if self.fields is None: 719 795 field_struct = ((None, {'fields': [f.name for f in opts.fields + opts.many_to_many if f.editable and not isinstance(f, AutoField)]}),) -
django/core/defaulttags.py
2 2 3 3 import sys 4 4 import template 5 import template_loader 5 6 6 7 class CommentNode(template.Node): 7 8 def render(self, context): … … 223 224 return '' # Fail silently for invalid included templates. 224 225 return output 225 226 227 class IncludeNode(template.Node): 228 def __init__(self, template_path): 229 self.template_path = template_path 230 231 def render(self, context): 232 try: 233 t = template_loader.get_template(self.template_path) 234 return t.render(context) 235 except: 236 return '' # Fail silently for invalid included templates. 237 238 226 239 class LoadNode(template.Node): 227 240 def __init__(self, taglib): 228 241 self.taglib = taglib … … 600 613 raise template.TemplateSyntaxError, "Second (optional) argument to %s tag must be 'parsed'" % bits[0] 601 614 return SsiNode(bits[1], parsed) 602 615 616 def do_include(parser, token): 617 """ 618 Loads a template using standard resolution mechanisms, and renders it in the current context. 619 """ 620 bits = token.contents.split() 621 parsed = False 622 if len(bits) != 2: 623 raise template.TemplateSyntaxError, "'include' tag takes one argument: the path to the template to be included" 624 return IncludeNode(bits[1]) 625 603 626 def do_load(parser, token): 604 627 """ 605 628 Load a custom template tag set. … … 755 778 template.register_tag('ifnotequal', lambda parser, token: do_ifequal(parser, token, True)) 756 779 template.register_tag('if', do_if) 757 780 template.register_tag('ifchanged', do_ifchanged) 781 template.register_tag('include', do_include) 758 782 template.register_tag('regroup', do_regroup) 759 783 template.register_tag('ssi', do_ssi) 760 784 template.register_tag('load', do_load) -
django/templatetags/admin_modify.py
1 from django.core import template, template_loader, meta 2 from django.conf.settings import ADMIN_MEDIA_PREFIX 3 from django.utils.text import capfirst 4 from django.utils.html import escape 5 6 7 from django.views.admin.main import BoundField 8 9 class 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 18 class 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 50 class 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 87 class 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 106 class 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 120 class 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 147 class 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.editable_fields()] 172 173 var_name = relation.opts.object_name.lower() 174 175 form = template.resolve_variable('form', context) 176 form_objects = form[relation.opts.module_name] 177 form_object_wrapper_list = [FormObjectWrapper(o,field_wrapper_list, i, var_name) for i,o in enumerate(form_objects)] 178 179 context['field_wrapper_list'] = field_wrapper_list 180 context['form_object_wrapper_list'] = form_object_wrapper_list 181 context['num_headers'] = len(field_wrapper_list) 182 context['original_row_needed'] = max([fw.use_raw_id_admin() for fw in field_wrapper_list]) 183 context['name_prefix'] = "%s." % (var_name,) 184 185 class FieldLabelNode(template.Node): 186 def __init__(self, bound_field_var): 187 self.bound_field_var = bound_field_var 188 189 def render(self, context): 190 bound_field = template.resolve_variable(self.bound_field_var, context) 191 class_names = [] 192 if isinstance(bound_field.field, meta.BooleanField): 193 class_names.append("vCheckboxLabel") 194 else: 195 if not bound_field.field.blank: 196 class_names.append('required') 197 if bound_field.index > 0: 198 class_names.append('inline') 199 200 class_str = class_names and ' class="%s"' % ' '.join(class_names) or '' 201 return '<label for="%s"%s>%s:</label> ' % (bound_field.label_name, class_str, capfirst(bound_field.field.verbose_name) ) 202 203 class OutputAllNode(template.Node): 204 def __init__(self, form_fields_var): 205 self.form_fields_var = form_fields_var 206 207 def render(self, context): 208 form_fields = template.resolve_variable(self.form_fields_var, context) 209 return ''.join([str(f) for f in form_fields]) 210 211 class AutoPopulatedFieldScriptNode(template.Node): 212 def __init__(self, auto_pop_var): 213 self.auto_pop_var = auto_pop_var 214 215 def render(self,context): 216 auto_pop_fields = template.resolve_variable(self, context) 217 change = context['change'] 218 for field in auto_populated_fields: 219 t = [] 220 if change: 221 t.append('document.getElementById("id_%s")._changed = true;' % field.name ) 222 else: 223 t.append('document.getElementById("id_%s").onchange = function() { this._changed = true; };' % field.name) 224 225 add_values = ' + " " + '.join(['document.getElementById("id_%s").value' % g for g in field.prepopulate_from]) 226 for f in field.prepopulate_from: 227 t.append(""" 228 document.getElementById("id_%s").onkeyup = function() { 229 var e = document.getElementById("id_%s"); 230 if(!e._changed) { e.value = URLify(%s, %s);} 231 } 232 """ % (f, field.name, add_values, field.maxlength) 233 ) 234 235 return ''.join(t) 236 237 def do_include_admin_script(parser, token): 238 tokens = token.contents.split() 239 if len(tokens) != 2: 240 raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0]) 241 242 return IncludeAdminScriptNode(tokens[1]) 243 244 def do_dummy(parser, token): 245 return DummyNode(token.contents) 246 247 def do_submit_row(parser, token): 248 return SubmitRowNode() 249 250 def do_admin_field_bound(parser, token): 251 tokens = token.contents.split() 252 if len(tokens) != 2: 253 raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0]) 254 return AdminFieldBoundNode(tokens[1]) 255 256 257 def do_field_label(parser, token): 258 tokens = token.contents.split() 259 if len(tokens) != 2: 260 raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0]) 261 return FieldLabelNode(tokens[1]) 262 263 def do_field_widget(parser, token): 264 tokens = token.contents.split() 265 if len(tokens) != 2: 266 raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0]) 267 return FieldWidgetNode(tokens[1]) 268 269 def do_output_all(parser, token): 270 tokens = token.contents.split() 271 if len(tokens) != 2: 272 raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0]) 273 return OutputAllNode(tokens[1]) 274 275 276 def do_edit_inline(parser, token): 277 tokens = token.contents.split() 278 if len(tokens) != 2: 279 raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0]) 280 return EditInlineNode(tokens[1]) 281 282 def do_auto_populated_field_script(parser, token): 283 tokens = token.contents.split() 284 if len(tokens) != 2: 285 raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0]) 286 return AutoPopulatedFieldScriptNode(tokens[1]) 287 288 289 290 template.register_tag('include_admin_script', do_include_admin_script) 291 template.register_tag('submit_row', do_submit_row ) 292 template.register_tag('admin_field_bound', do_admin_field_bound) 293 template.register_tag('edit_inline', do_edit_inline) 294 template.register_tag('auto_populated_field_script', do_auto_populated_field_script) 295 template.register_tag('field_label', do_field_label) 296 template.register_tag('field_widget', do_field_widget) 297 template.register_tag('output_all', do_output_all) 298 299 -
django/views/admin/main.py
1 1 # Generic admin views, with admin templates created dynamically at runtime. 2 2 3 from django.core import formfields, meta, template_loader 3 from django.core import formfields, meta, template_loader, template 4 4 from django.core.exceptions import Http404, ObjectDoesNotExist, PermissionDenied 5 5 from django.core.extensions import DjangoContext as Context 6 6 from django.models.auth import log … … 493 493 }) 494 494 return HttpResponse(t.render(c)) 495 495 496 def _get_flattened_data(field, val):497 """498 Returns a dictionary mapping the field's manipulator field names to its499 "flattened" string values for the admin view. "val" is an instance of the500 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 513 496 use_raw_id_admin = lambda field: isinstance(field.rel, (meta.ManyToOne, meta.ManyToMany)) and field.rel.raw_id_admin 514 497 515 498 def _get_submit_row_template(opts, app_label, add, change, show_delete, ordered_objects): … … 530 513 t.append('</div>\n') 531 514 return t 532 515 516 def 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 542 class BoundField(object): 543 def __init__(self, index, field, original, form_prefix, name_prefix, rel, form_fields): 544 self.index = index 545 self.field = field 546 self.hack_prefix = 'form.' + form_prefix 547 self.label_name = 'id_%s%s' % (form_prefix, field.get_manipulator_field_names('')[0]) 548 self.has_label_first = not isinstance(self.field, meta.BooleanField) 549 self.original = original 550 self.raw_id_admin = use_raw_id_admin(field) 551 self.name_prefix = name_prefix 552 self.rel = rel 553 self.is_date_time = isinstance(field, meta.DateTimeField) 554 self.is_file_field = isinstance(field, meta.FileField) 555 self.needs_add_label = field.rel and isinstance(field.rel, meta.ManyToOne) and field.rel.to.admin 556 self.not_in_table = isinstance(self.field, meta.AutoField) 557 self.form_fields = form_fields 558 559 classes = [] 560 if(self.raw_id_admin): 561 classes.append('nowrap') 562 # if(self.field.errors()): 563 # classes.append('error') 564 self.cell_class_attribute = ' '.join(classes) 565 self._repr_filled = False 566 567 def as_field_list(self): 568 return [self.field] 569 570 def original_value(self): 571 return self.original.__dict__[self.field.name] 572 573 def _fetch_existing_repr(self, func_name): 574 class_dict = self.original.__class__.__dict__ 575 func = class_dict.get(func_name) 576 return func(self.original) 577 578 def _fill_existing_repr(self): 579 if self._repr_filled: 580 return 581 #HACK 582 if isinstance(self.field.rel, meta.ManyToOne): 583 func_name = 'get_%s' % self.field.name 584 self._repr = self._fetch_existing_repr(func_name) 585 elif isinstance(self.field.rel, meta.ManyToMany): 586 func_name = 'get_%s_list' % self.field.name 587 self._repr = ",".join(self._fetch_existing_repr(func_name)) 588 self._repr_filled = True 589 590 def existing_repr(self): 591 self._fill_existing_repr() 592 return self._repr 593 594 def __repr__(self): 595 return repr(self.__dict__) 596 597 598 599 600 class AdminFieldSet(object): 601 def __init__(self, fieldset_name, options, bound_field_sets): 602 self.name = fieldset_name 603 self.options = options 604 self.bound_field_sets = bound_field_sets 605 self.classes = options.get('classes', '') 606 # self.fields = options['fields'] 607 608 def __repr__(self): 609 return "Fieldset:(%s,%s)" % (self.name, self.bound_field_sets) 610 611 612 def bound_field_sets(opts, context, name_prefix): 613 original = template.resolve_variable('original', context); 614 form_prefix = '' 615 fields = opts['fields'] 616 bound_field_sets = [ [BoundField(i, f, original, form_prefix, name_prefix, False, 617 resolve_form_fields(f,name_prefix, context)) for i,f in enumerate(field) ] for field in fields] 618 619 return bound_field_sets 620 621 def resolve_form_fields(field, name_prefix, context): 622 return [template.resolve_variable(name, context) for name in field.get_manipulator_field_names(name_prefix)] 623 624 625 def fill_extra_context(opts, app_label, context, add=False, change=False, show_delete=False, form_url=''): 626 admin_field_objs = opts.admin.get_field_objs(opts) 627 ordered_objects = opts.get_ordered_objects()[:] 628 auto_populated_fields = [f for f in opts.fields if f.prepopulate_from] 629 630 javascript_imports = get_javascript_imports(opts,auto_populated_fields, ordered_objects, admin_field_objs); 631 632 if ordered_objects: 633 coltype = 'colMS' 634 else: 635 coltype = 'colM' 636 637 has_absolute_url = hasattr(opts.get_model_module().Klass, 'get_absolute_url') 638 639 form_enc_attrib = opts.has_field_type(meta.FileField) and 'enctype="multipart/form-data" ' or '' 640 641 admin_fieldsets = [AdminFieldSet(f, o, bound_field_sets(o, context, 'form.')) for f, o in admin_field_objs] 642 inline_related_objects = opts.get_inline_related_objects_wrapped() 643 644 ordered_object_names = ' '.join(['object.%s' % o.pk.name for o in ordered_objects]) 645 646 extra_context = { 647 'add': add, 648 'change': change, 649 'admin_field_objs' : admin_field_objs, 650 'ordered_objects' : ordered_objects, 651 'auto_populated_fields' : auto_populated_fields, 652 'javascript_imports' : javascript_imports, 653 'coltype' : coltype, 654 'has_absolute_url': has_absolute_url, 655 'form_enc_attrib': form_enc_attrib, 656 'form_url' : form_url, 657 'admin_fieldsets' : admin_fieldsets, 658 'inline_related_objects': inline_related_objects, 659 'ordered_object_names' : ordered_object_names, 660 'content_type_id' : opts.get_content_type_id(), 661 'save_on_top' : opts.admin.save_on_top, 662 'verbose_name_plural': opts.verbose_name_plural, 663 'save_as': opts.admin.save_as, 664 'app_label': app_label, 665 'object_name': opts.object_name, 666 'has_delete_permission' : context['perms'][app_label][opts.get_delete_permission()] 667 } 668 669 context.update(extra_context) 670 671 672 def add_stage_new(request, app_label, module_name, show_delete=False, form_url='', post_url='../', post_url_continue='../%s/', object_id_override=None): 673 mod, opts = _get_mod_opts(app_label, module_name) 674 if not request.user.has_perm(app_label + '.' + opts.get_add_permission()): 675 raise PermissionDenied 676 manipulator = mod.AddManipulator() 677 if request.POST: 678 new_data = request.POST.copy() 679 if opts.has_field_type(meta.FileField): 680 new_data.update(request.FILES) 681 errors = manipulator.get_validation_errors(new_data) 682 if not errors and not request.POST.has_key("_preview"): 683 for f in opts.many_to_many: 684 if f.rel.raw_id_admin: 685 new_data.setlist(f.name, new_data[f.name].split(",")) 686 manipulator.do_html2python(new_data) 687 new_object = manipulator.save(new_data) 688 pk_value = getattr(new_object, opts.pk.column) 689 log.log_action(request.user.id, opts.get_content_type_id(), pk_value, repr(new_object), log.ADDITION) 690 msg = 'The %s "%s" was added successfully.' % (opts.verbose_name, new_object) 691 # Here, we distinguish between different save types by checking for 692 # the presence of keys in request.POST. 693 if request.POST.has_key("_continue"): 694 request.user.add_message("%s You may edit it again below." % msg) 695 if request.POST.has_key("_popup"): 696 post_url_continue += "?_popup=1" 697 return HttpResponseRedirect(post_url_continue % pk_value) 698 if request.POST.has_key("_popup"): 699 return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %s, "%s");</script>' % \ 700 (pk_value, repr(new_object).replace('"', '\\"'))) 701 elif request.POST.has_key("_addanother"): 702 request.user.add_message("%s You may add another %s below." % (msg, opts.verbose_name)) 703 return HttpResponseRedirect(request.path) 704 else: 705 request.user.add_message(msg) 706 return HttpResponseRedirect(post_url) 707 if request.POST.has_key("_preview"): 708 manipulator.do_html2python(new_data) 709 else: 710 # Add default data. 711 new_data = manipulator.flatten_data() 712 713 # Override the defaults with request.GET, if it exists. 714 new_data.update(request.GET) 715 errors = {} 716 717 # Populate the FormWrapper. 718 form = formfields.FormWrapper(manipulator, new_data, errors) 719 720 c = Context(request, { 721 'title': 'Add %s' % opts.verbose_name, 722 "form": form, 723 "is_popup": request.REQUEST.has_key("_popup"), 724 }) 725 if object_id_override is not None: 726 c['object_id'] = object_id_override 727 728 729 fill_extra_context(opts, app_label, c, change=True) 730 731 t = template_loader.get_template("admin_change_form"); 732 733 return HttpResponse(t.render(c)) 734 735 736 737 def change_stage_new(request, app_label, module_name, object_id): 738 mod, opts = _get_mod_opts(app_label, module_name) 739 if not request.user.has_perm(app_label + '.' + opts.get_change_permission()): 740 raise PermissionDenied 741 if request.POST and request.POST.has_key("_saveasnew"): 742 return add_stage_new(request, app_label, module_name, form_url='../add/') 743 try: 744 manipulator = mod.ChangeManipulator(object_id) 745 except ObjectDoesNotExist: 746 raise Http404 747 748 inline_related_objects = opts.get_inline_related_objects() 749 if request.POST: 750 new_data = request.POST.copy() 751 if opts.has_field_type(meta.FileField): 752 new_data.update(request.FILES) 753 754 errors = manipulator.get_validation_errors(new_data) 755 if not errors and not request.POST.has_key("_preview"): 756 for f in opts.many_to_many: 757 if f.rel.raw_id_admin: 758 new_data.setlist(f.name, new_data[f.name].split(",")) 759 manipulator.do_html2python(new_data) 760 new_object = manipulator.save(new_data) 761 pk_value = getattr(new_object, opts.pk.column) 762 763 # Construct the change message. 764 change_message = [] 765 if manipulator.fields_added: 766 change_message.append('Added %s.' % get_text_list(manipulator.fields_added, 'and')) 767 if manipulator.fields_changed: 768 change_message.append('Changed %s.' % get_text_list(manipulator.fields_changed, 'and')) 769 if manipulator.fields_deleted: 770 change_message.append('Deleted %s.' % get_text_list(manipulator.fields_deleted, 'and')) 771 change_message = ' '.join(change_message) 772 if not change_message: 773 change_message = 'No fields changed.' 774 775 log.log_action(request.user.id, opts.get_content_type_id(), pk_value, repr(new_object), log.CHANGE, change_message) 776 msg = 'The %s "%s" was changed successfully.' % (opts.verbose_name, new_object) 777 if request.POST.has_key("_continue"): 778 request.user.add_message("%s You may edit it again below." % msg) 779 if request.REQUEST.has_key('_popup'): 780 return HttpResponseRedirect(request.path + "?_popup=1") 781 else: 782 return HttpResponseRedirect(request.path) 783 elif request.POST.has_key("_saveasnew"): 784 request.user.add_message('The %s "%s" was added successfully. You may edit it again below.' % (opts.verbose_name, new_object)) 785 return HttpResponseRedirect("../%s/" % pk_value) 786 elif request.POST.has_key("_addanother"): 787 request.user.add_message("%s You may add another %s below." % (msg, opts.verbose_name)) 788 return HttpResponseRedirect("../add/") 789 else: 790 request.user.add_message(msg) 791 return HttpResponseRedirect("../") 792 if request.POST.has_key("_preview"): 793 manipulator.do_html2python(new_data) 794 else: 795 # Populate new_data with a "flattened" version of the current data. 796 new_data = manipulator.flatten_data() 797 798 799 # If the object has ordered objects on its admin page, get the existing 800 # order and flatten it into a comma-separated list of IDs. 801 id_order_list = [] 802 for rel_obj in opts.get_ordered_objects(): 803 id_order_list.extend(getattr(obj, 'get_%s_order' % rel_obj.object_name.lower())()) 804 if id_order_list: 805 new_data['order_'] = ','.join(map(str, id_order_list)) 806 errors = {} 807 808 # Populate the FormWrapper. 809 form = formfields.FormWrapper(manipulator, new_data, errors, edit_inline = True) 810 form.original = manipulator.original_object 811 form.order_objects = [] 812 813 for rel_opts, rel_field in inline_related_objects: 814 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: 815 form.order_objects.extend(orig_list) 816 817 c = Context(request, { 818 'title': 'Change %s' % opts.verbose_name, 819 'form': form, 820 'object_id': object_id, 821 'original': manipulator.original_object, 822 'is_popup' : request.REQUEST.has_key('_popup') 823 }) 824 825 fill_extra_context(opts, app_label, c, change=True) 826 827 #t = template_loader.get_template_from_string(raw_template) 828 t = template_loader.get_template("admin_change_form"); 829 return HttpResponse(t.render(c), ) 830 831 533 832 def _get_template(opts, app_label, add=False, change=False, show_delete=False, form_url=''): 534 833 admin_field_objs = opts.admin.get_field_objs(opts) 535 834 ordered_objects = opts.get_ordered_objects()[:] … … 802 1101 # Add default data. 803 1102 for f in opts.fields: 804 1103 if f.has_default(): 805 new_data.update( _get_flattened_data(f, f.get_default()))1104 new_data.update( f.flatten_data() ) 806 1105 # In required many-to-one fields with only one available choice, 807 1106 # select that one available choice. Note: We have to check that 808 1107 # the length of choices is *2*, not 1, because SelectFields always … … 837 1136 if f.editable and f != rel_field and not isinstance(f, meta.AutoField): 838 1137 for field_name in f.get_manipulator_field_names(''): 839 1138 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, [])) 1139 field = manipulator[full_field_name] 1140 data = field.extract_data(new_data) 1141 collection[field_name] = formfields.FormFieldWrapper(field, data, errors.get(full_field_name, [])) 841 1142 wrapper.append(formfields.FormFieldCollection(collection)) 842 1143 setattr(form, rel_opts.module_name, wrapper) 843 1144 … … 849 1150 if object_id_override is not None: 850 1151 c['object_id'] = object_id_override 851 1152 raw_template = _get_template(opts, app_label, add=True, show_delete=show_delete, form_url=form_url) 852 # return HttpResponse(raw_template, mimetype='text/plain')853 1153 t = template_loader.get_template_from_string(raw_template) 854 1154 return HttpResponse(t.render(c)) 855 1155 … … 915 1215 new_data = {} 916 1216 obj = manipulator.original_object 917 1217 for f in opts.fields: 918 new_data.update( _get_flattened_data(f, getattr(obj, f.column)))1218 new_data.update(f.flatten_data(obj)) 919 1219 for f in opts.many_to_many: 920 1220 get_list_func = getattr(obj, 'get_%s_list' % f.rel.singular) 921 1221 if f.rel.raw_id_admin: … … 927 1227 for i, rel_instance in enumerate(getattr(obj, 'get_%s_list' % opts.get_rel_object_method_name(rel_obj, rel_field))()): 928 1228 for f in rel_obj.fields: 929 1229 if f.editable and f != rel_field: 930 for k, v in _get_flattened_data(f, getattr(rel_instance, f.column)).items():1230 for k, v in f.flatten_data(rel_instance).items(): 931 1231 new_data['%s.%d.%s' % (var_name, i, k)] = v 932 1232 for f in rel_obj.many_to_many: 933 1233 new_data['%s.%d.%s' % (var_name, i, f.column)] = [j.id for j in getattr(rel_instance, 'get_%s_list' % f.rel.singular)()] … … 960 1260 if f.editable and f != rel_field: 961 1261 for field_name in f.get_manipulator_field_names(''): 962 1262 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, [])) 1263 field = manipulator[full_field_name] 1264 data = field.extract_data(new_data) 1265 collection[field_name] = formfields.FormFieldWrapper(field, data, errors.get(full_field_name, [])) 964 1266 wrapper.append(formfields.FormFieldCollection(collection)) 965 1267 setattr(form, rel_opts.module_name, wrapper) 966 1268 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: -
tests/runtests.py
100 100 self.output(1, "Creating test database") 101 101 try: 102 102 cursor.execute("CREATE DATABASE %s" % TEST_DATABASE_NAME) 103 except: 103 except Exception, e: 104 self.output(0, "There was an error creating the test database:%s " % str(e)) 104 105 confirm = raw_input("The test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME) 105 106 if confirm == 'yes': 106 107 cursor.execute("DROP DATABASE %s" % TEST_DATABASE_NAME)