diff --git a/django/bin/validate.py b/django/bin/validate.py index f0c37d01cb..dbd44abbf8 100644 --- a/django/bin/validate.py +++ b/django/bin/validate.py @@ -13,19 +13,28 @@ def validate_class(klass): # Fields. for f in opts.fields: if isinstance(f, meta.ManyToManyField): - assert isinstance(f.rel, meta.ManyToMany), "ManyToManyField %s should have 'rel' set to a ManyToMany instance." % f.name + assert isinstance(f.rel, meta.ManyToMany), \ + "ManyToManyField %s should have 'rel' set to a ManyToMany instance." % f.name # Inline related objects. - for rel_opts, rel_field in opts.get_inline_related_objects(): - assert len([f for f in rel_opts.fields if f.core]) > 0, "At least one field in %s should have core=True, because it's being edited inline by %s." % (rel_opts.object_name, opts.object_name) + for related in opts.get_followed_related_objects(): + assert len([f for f in related.opts.fields if f.core]) > 0, \ + "At least one field in %s should have core=True, because it's being edited inline by %s." % \ + (related.opts.object_name, opts.object_name) # All related objects. related_apps_seen = [] - for rel_opts, rel_field in opts.get_all_related_objects(): - if rel_opts in related_apps_seen: - assert rel_field.rel.related_name is not None, "Relationship in field %s.%s needs to set 'related_name' because more than one %s object is referenced in %s." % (rel_opts.object_name, rel_field.name, opts.object_name, rel_opts.object_name) - related_apps_seen.append(rel_opts) + for related in opts.get_all_related_objects(): + if related.opts in related_apps_seen: + assert related.field.rel.related_name is not None, \ + "Relationship in field %s.%s needs to set 'related_name' because more than one" \ + " %s object is referenced in %s." % \ + (related.opts.object_name, related.field.name, opts.object_name, rel_opts.object_name) + related_apps_seen.append(related.opts) # Etc. if opts.admin is not None: - assert opts.admin.ordering or opts.ordering, "%s needs to set 'ordering' on either its 'admin' or its model, because it has 'admin' set." % opts.object_name + assert opts.admin.ordering or opts.ordering, \ + "%s needs to set 'ordering' on either its 'admin' or its model," \ + "because it has 'admin' set." % \ + opts.object_name if __name__ == "__main__": import sys diff --git a/django/contrib/admin/templates/admin/change_form.html b/django/contrib/admin/templates/admin/change_form.html index 5962819b56..af0da1b485 100644 --- a/django/contrib/admin/templates/admin/change_form.html +++ b/django/contrib/admin/templates/admin/change_form.html @@ -21,13 +21,11 @@ {% endif %}{% endif %}
- {% if is_popup %}{% endif %} {% if save_on_top %}{% submit_row %}{% endif %} {% if form.error_dict %}

Please correct the error{{ form.error_dict.items|pluralize }} below.

{% endif %} {% for bound_field_set in bound_field_sets %} -
- +
{% if bound_field_set.name %}

{{bound_field_set.name }}

{% endif %} {% for bound_field_line in bound_field_set %} {% admin_field_line bound_field_line %} diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index a7d86add8f..c330c67259 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -518,7 +518,7 @@ def _get_submit_row_template(opts, app_label, add, change, show_delete, ordered_ t.append('\n') return t -def get_javascript_imports(opts,auto_populated_fields, ordered_objects, admin_field_objs): +def get_javascript_imports(opts,auto_populated_fields, ordered_objects, field_sets): # Put in any necessary JavaScript imports. js = ['js/core.js', 'js/admin/RelatedObjectLookups.js'] if auto_populated_fields: @@ -530,13 +530,13 @@ def get_javascript_imports(opts,auto_populated_fields, ordered_objects, admin_fi if opts.admin.js: js.extend(opts.admin.js) seen_collapse = False - for _, options in admin_field_objs: - if not seen_collapse and 'collapse' in options.get('classes', ''): + for field_set in field_sets: + if not seen_collapse and 'collapse' in field_set.classes: seen_collapse = True js.append('js/admin/CollapsedFieldsets.js' ) try: - for field_list in options['fields']: - for f in field_list: + for field_line in field_set: + for f in field_line: if f.rel and isinstance(f, meta.ManyToManyField) and f.rel.filter_interface: js.extend(['js/SelectBox.js' , 'js/SelectFilter2.js']) raise StopIteration @@ -608,33 +608,22 @@ class AdminBoundFieldSet(BoundFieldSet): def fill_extra_context(opts, app_label, context, add=False, change=False, show_delete=False, form_url=''): - admin_field_objs = opts.admin.get_field_objs(opts) - ordered_objects = opts.get_ordered_objects()[:] auto_populated_fields = [f for f in opts.fields if f.prepopulate_from] - - javascript_imports = get_javascript_imports(opts, auto_populated_fields, ordered_objects, admin_field_objs); - - if ordered_objects: - coltype = 'colMS' - else: - coltype = 'colM' - + coltype = ordered_objects and 'colMS' or 'colM' + has_absolute_url = hasattr(opts.get_model_module().Klass, 'get_absolute_url') - form_enc_attrib = opts.has_field_type(meta.FileField) and 'enctype="multipart/form-data" ' or '' - form = context['form'] original = context['original'] field_sets = opts.admin.get_field_sets(opts) bound_field_sets = [field_set.bind(form, original, AdminBoundFieldSet) for field_set in field_sets] - - first_form_field = bound_field_sets[0].bound_field_lines[0].bound_fields[0].form_fields[0]; - - inline_related_objects = opts.get_inline_related_objects_wrapped() - + + javascript_imports = get_javascript_imports(opts, auto_populated_fields, ordered_objects, field_sets); + first_form_field = bound_field_sets[0].bound_field_lines[0].bound_fields[0].form_fields[0]; + inline_related_objects = opts.get_followed_related_objects() ordered_object_names = ' '.join(['object.%s' % o.pk.name for o in ordered_objects]) extra_context = { @@ -739,7 +728,6 @@ def change_stage(request, app_label, module_name, object_id): except ObjectDoesNotExist: raise Http404 - inline_related_objects = opts.get_inline_related_objects() if request.POST: new_data = request.POST.copy() if opts.has_field_type(meta.FileField): @@ -806,11 +794,14 @@ def change_stage(request, app_label, module_name, object_id): form.original = manipulator.original_object form.order_objects = [] - for rel_opts, rel_field in inline_related_objects: - 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: - orig_list = getattr(manipulator.original_object, 'get_%s_list' % opts.get_rel_object_method_name(rel_opts, rel_field))() + for related in opts.get_followed_related_objects(): + wrt = related.opts.order_with_respect_to + if wrt and wrt.rel and wrt.rel.to == opts: + func = getattr(manipulator.original_object, 'get_%s_list' % + opts.get_rel_object_method_name(rel_opts, rel_field)) + orig_list = func() form.order_objects.extend(orig_list) - + c = Context(request, { 'title': 'Change %s' % opts.verbose_name, 'form': form, @@ -836,50 +827,50 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current if current_depth > 16: return # Avoid recursing too deep. objects_seen = [] - for rel_opts, rel_field in opts.get_all_related_objects(): - if rel_opts in objects_seen: + for related in opts.get_all_related_objects(): + if related.opts in objects_seen: continue objects_seen.append(rel_opts) - rel_opts_name = opts.get_rel_object_method_name(rel_opts, rel_field) - if isinstance(rel_field.rel, meta.OneToOne): + rel_opts_name = opts.get_rel_object_method_name(related.opts, related.field) + if isinstance(related.field.rel, meta.OneToOne): try: sub_obj = getattr(obj, 'get_%s' % rel_opts_name)() except ObjectDoesNotExist: pass else: if rel_opts.admin: - p = '%s.%s' % (rel_opts.app_label, rel_opts.get_delete_permission()) + p = '%s.%s' % (related.opts.app_label, related.opts.get_delete_permission()) if not user.has_perm(p): - perms_needed.add(rel_opts.verbose_name) + perms_needed.add(related.opts.verbose_name) # We don't care about populating deleted_objects now. continue - if rel_field.rel.edit_inline or not rel_opts.admin: + if related.field.rel.edit_inline or not related.opts.admin: # Don't display link to edit, because it either has no # admin or is edited inline. - nh(deleted_objects, current_depth, ['%s: %r' % (capfirst(rel_opts.verbose_name), sub_obj), []]) + nh(deleted_objects, current_depth, ['%s: %r' % (capfirst(related.opts.verbose_name), sub_obj), []]) else: # Display a link to the admin page. nh(deleted_objects, current_depth, ['%s: %r' % \ - (capfirst(rel_opts.verbose_name), rel_opts.app_label, rel_opts.module_name, - getattr(sub_obj, rel_opts.pk.column), sub_obj), []]) - _get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, rel_opts, current_depth+2) + (capfirst(related.opts.verbose_name), related.opts.app_label, related.opts.module_name, + getattr(sub_obj, related.opts.pk.column), sub_obj), []]) + _get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2) else: has_related_objs = False for sub_obj in getattr(obj, 'get_%s_list' % rel_opts_name)(): has_related_objs = True - if rel_field.rel.edit_inline or not rel_opts.admin: + if related.field.rel.edit_inline or not related.opts.admin: # Don't display link to edit, because it either has no # admin or is edited inline. - nh(deleted_objects, current_depth, ['%s: %s' % (capfirst(rel_opts.verbose_name), strip_tags(repr(sub_obj))), []]) + nh(deleted_objects, current_depth, ['%s: %s' % (capfirst(related.opts.verbose_name), strip_tags(repr(sub_obj))), []]) else: # Display a link to the admin page. nh(deleted_objects, current_depth, ['%s: %s' % \ - (capfirst(rel_opts.verbose_name), rel_opts.app_label, rel_opts.module_name, sub_obj.id, strip_tags(repr(sub_obj))), []]) - _get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, rel_opts, current_depth+2) + (capfirst(related.opts.verbose_name), related.opts.app_label, related.opts.module_name, sub_obj.id, strip_tags(repr(sub_obj))), []]) + _get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2) # If there were related objects, and the user doesn't have # permission to delete them, add the missing perm to perms_needed. - if rel_opts.admin and has_related_objs: - p = '%s.%s' % (rel_opts.app_label, rel_opts.get_delete_permission()) + if related.opts.admin and has_related_objs: + p = '%s.%s' % (related.opts.app_label, related.opts.get_delete_permission()) if not user.has_perm(p): perms_needed.add(rel_opts.verbose_name) for rel_opts, rel_field in opts.get_all_related_many_to_many_objects(): diff --git a/django/core/formfields.py b/django/core/formfields.py index ffc3b29cc2..ee42cc5dd5 100644 --- a/django/core/formfields.py +++ b/django/core/formfields.py @@ -88,12 +88,8 @@ class Manipulator: must happen after validation because html2python functions aren't expected to deal with invalid input. """ - """ - for field in self.fields: - """ - - for field in self.fields: - field.convert_post_data(new_data) + for field in self.fields: + field.convert_post_data(new_data) class FormWrapper: """ @@ -101,12 +97,12 @@ class FormWrapper: This allows dictionary-style lookups of formfields. It also handles feeding prepopulated data and validation error messages to the formfield objects. """ - def __init__(self, manipulator, data, error_dict, edit_inline = False): + def __init__(self, manipulator, data, error_dict, edit_inline = True): self.manipulator, self.data = manipulator, data self.error_dict = error_dict self._inline_collections = None self.edit_inline = edit_inline - + def __repr__(self): return repr(self.__dict__) @@ -246,7 +242,7 @@ class InlineObjectCollection: errors = self.errors.get(full_field_name, []) collection[field_name] = FormFieldWrapper(field, data, errors) wrapper.append(FormFieldCollection(collection)) - self._collections = wrapper + self._collections = wrapper class FormField: """Abstract class representing a form field. @@ -293,7 +289,7 @@ class FormField: data = data_dict.get(self.get_member_name(), None) if data is None: data = '' - return data + return data def convert_post_data(self, new_data): name = self.get_member_name() diff --git a/django/core/management.py b/django/core/management.py index 564697776d..6a3a048dae 100644 --- a/django/core/management.py +++ b/django/core/management.py @@ -301,12 +301,12 @@ def init(): cursor.execute(sql) cursor.execute("INSERT INTO %s (domain, name) VALUES ('mysite.com', 'My Django site')" % core.Site._meta.db_table) except Exception, e: - sys.stderr.write("Error: The database couldn't be initialized.\n%s\n" % e) + sys.stderr.write("Error: The database couldn't be initialized.\n%s\n" % e) try: db.db.rollback() except UnboundLocalError: pass - sys.exit(1) + raise else: db.db.commit() init.args = '' @@ -582,12 +582,12 @@ def get_validation_errors(outfile): e.add(opts, '"ordering" refers to "%s", a field that doesn\'t exist.' % field_name) # Check core=True, if needed. - for rel_opts, rel_field in opts.get_inline_related_objects(): + for related in opts.get_followed_related_objects(): try: - for f in rel_opts.fields: + for f in related.opts.fields: if f.core: raise StopIteration - e.add(rel_opts, "At least one field in %s should have core=True, because it's being edited inline by %s.%s." % (rel_opts.object_name, opts.module_name, opts.object_name)) + e.add(related.opts, "At least one field in %s should have core=True, because it's being edited inline by %s.%s." % (related.opts.object_name, opts.module_name, opts.object_name)) except StopIteration: pass return len(e.errors) diff --git a/django/core/meta/__init__.py b/django/core/meta/__init__.py index 5edbcab114..d843ce7862 100644 --- a/django/core/meta/__init__.py +++ b/django/core/meta/__init__.py @@ -250,6 +250,8 @@ class RelatedObject(object): return fields +class BoundRelatedObject(object): + pass class Options: def __init__(self, module_name='', verbose_name='', verbose_name_plural='', db_table='', @@ -401,7 +403,7 @@ class Options: for klass in mod._MODELS: for f in klass._meta.fields: if f.rel and self == f.rel.to: - rel_objs.append((klass._meta, f)) + rel_objs.append(RelatedObject(self, klass._meta, f)) if self.has_related_links: # Manually add RelatedLink objects, which are a special case. relatedlinks = get_module('relatedlinks', 'relatedlinks') @@ -415,32 +417,23 @@ class Options: 'content_type__package__label__exact': self.app_label, 'content_type__python_module_name__exact': self.module_name, }) - rel_objs.append((relatedlinks.RelatedLink._meta, link_field)) + rel_objs.append(RelatedObject(self, relatedlinks.RelatedLink._meta, link_field)) self._all_related_objects = rel_objs return rel_objs - def get_inline_related_objects(self): - return [(a, b) for a, b in self.get_all_related_objects() if b.rel.edit_inline] - - def get_inline_related_objects_wrapped(self): - return [RelatedObject(self, opts, field) for opts, field in self.get_all_related_objects() if field.rel.edit_inline] - - def get_all_related_objects_wrapped(self): - return [RelatedObject(self, opts, field) for opts, field in self.get_all_related_objects()] - def get_followed_related_objects(self, follow=None): if follow == None: follow = self.get_follow() - return [f for f in self.get_all_related_objects_wrapped() if follow.get(f.name, None) ] + return [f for f in self.get_all_related_objects() if follow.get(f.name, None) ] def get_data_holders(self, follow=None): if follow == None : follow = self.get_follow() - return [f for f in self.fields + self.many_to_many + self.get_all_related_objects_wrapped() if follow.get(f.name, None) ] + return [f for f in self.fields + self.many_to_many + self.get_all_related_objects() if follow.get(f.name, None) ] def get_follow(self, override=None): follow = {} - for f in self.fields + self.many_to_many + self.get_all_related_objects_wrapped(): + for f in self.fields + self.many_to_many + self.get_all_related_objects(): if override and override.has_key(f.name): child_override = override[f.name] else: @@ -476,7 +469,7 @@ class Options: self._ordered_objects = objects return self._ordered_objects - def has_field_type(self, field_type): + def has_field_type(self, field_type, follow): """ Returns True if this object's admin form has at least one of the given field_type (e.g. FileField). @@ -491,8 +484,8 @@ class Options: if isinstance(f, field_type): raise StopIteration # Failing that, check related fields. - for rel_obj, rel_field in self.get_inline_related_objects(): - for f in rel_obj.fields: + for related in self.get_followed_related_objects(follow): + for f in related.opts.fields: if isinstance(f, field_type): raise StopIteration except StopIteration: @@ -853,8 +846,8 @@ class ModelBase(type): old_app._MODELS[i] = new_class # Replace all relationships to the old class with # relationships to the new one. - for rel_opts, rel_field in model._meta.get_all_related_objects(): - rel_field.rel.to = opts + for related in model._meta.get_all_related_objects(): + related.field.rel.to = opts for rel_opts, rel_field in model._meta.get_all_related_many_to_many_objects(): rel_field.rel.to = opts break @@ -954,9 +947,9 @@ def method_delete(opts, self): if hasattr(self, '_pre_delete'): self._pre_delete() cursor = db.db.cursor() - for rel_opts, rel_field in opts.get_all_related_objects(): - rel_opts_name = opts.get_rel_object_method_name(rel_opts, rel_field) - if isinstance(rel_field.rel, OneToOne): + for related in opts.get_all_related_objects(): + rel_opts_name = opts.get_rel_object_method_name(related.opts, related.field) + if isinstance(related.field.rel, OneToOne): try: sub_obj = getattr(self, 'get_%s' % rel_opts_name)() except ObjectDoesNotExist: @@ -1583,7 +1576,7 @@ def manipulator_init(opts, add, change, self, obj_key=None, follow=None): self.fields.extend(f.get_manipulator_fields(opts, self, change)) # Add fields for related objects. - for f in opts.get_all_related_objects_wrapped(): + for f in opts.get_all_related_objects(): if self.follow.get(f.name, False): fol = self.follow[f.name] self.fields.extend(f.get_manipulator_fields(opts, self, change, fol)) @@ -1638,7 +1631,7 @@ def manipulator_save(opts, klass, add, change, self, new_data): expanded_data = DotExpandedDict(new_data.data) # Save many-to-one objects. Example: Add the Choice objects for a Poll. - for related in opts.get_all_related_objects_wrapped(): + for related in opts.get_all_related_objects(): # Create obj_list, which is a DotExpandedDict such as this: # [('0', {'id': ['940'], 'choice': ['This is the first choice']}), # ('1', {'id': ['941'], 'choice': ['This is the second choice']}), diff --git a/django/core/meta/fields.py b/django/core/meta/fields.py index 981b2a5abb..8e82d66b23 100644 --- a/django/core/meta/fields.py +++ b/django/core/meta/fields.py @@ -48,8 +48,27 @@ def manipulator_validator_unique(f, opts, self, field_data, all_data): return raise validators.ValidationError, "%s with this %s already exists." % (capfirst(opts.verbose_name), f.verbose_name) -class Field(object): +class BoundField(object): + def __init__(self, field, field_mapping, original): + self.field = field + self.original = original + self.form_fields = self.resolve_form_fields(field_mapping) + def resolve_form_fields(self, field_mapping): + return [field_mapping[name] for name in self.field.get_manipulator_field_names('')] + + def as_field_list(self): + return [self.field] + + def original_value(self): + if self.original: + return self.original.__dict__[self.field.column] + + def __repr__(self): + return "BoundField:(%s, %s)" %( self.field.name, self.form_fields) + +class Field(object): + # Designates whether empty strings fundamentally are allowed at the # database level. empty_strings_allowed = True @@ -283,7 +302,7 @@ class Field(object): """ Returns a dictionary mapping the field's manipulator field names to its "flattened" string values for the admin view. Obj is the instance to extract the - values from. + values from. """ return { self.get_db_column(): self._get_val_from_obj(obj)} @@ -292,6 +311,9 @@ class Field(object): return override else: return self.editable + + def bind(self, fieldmapping, original, bound_field_class=BoundField): + return bound_field_class(self, fieldmapping, original) class AutoField(Field): empty_strings_allowed = False @@ -658,7 +680,7 @@ class ForeignKey(Field): return int(value) def flatten_data(self, follow, obj = None): - if not obj: + if not obj: # In required many-to-one fields with only one available choice, # select that one available choice. Note: We have to check that # the length of choices is *2*, not 1, because SelectFields always @@ -730,7 +752,6 @@ class ManyToManyField(Field): new_data[self.name] = [choices_list[0][0]] return new_data - class OneToOneField(IntegerField): def __init__(self, to, to_field=None, **kwargs): kwargs['verbose_name'] = kwargs.get('verbose_name', 'ID') @@ -796,28 +817,10 @@ class OneToOne(ManyToOne): self.lookup_overrides = lookup_overrides or {} self.raw_id_admin = raw_id_admin - -class BoundField(object): - def __init__(self, field, field_mapping, original): - self.field = field - self.form_fields = self.resolve_form_fields(field_mapping) - self.original = original - - def resolve_form_fields(self, field_mapping): - return [field_mapping[name] for name in self.field.get_manipulator_field_names('')] - - def as_field_list(self): - return [self.field] - - def original_value(self): - return self.original.__dict__[self.field.name] - - def __repr__(self): - return "BoundField:(%s, %s)" %( self.field.name, self.form_fields) - class BoundFieldLine(object): def __init__(self, field_line, field_mapping, original, bound_field_class=BoundField): - self.bound_fields = [bound_field_class(field, field_mapping, original) for field in field_line] + self.bound_fields = [field.bind(field_mapping, original, bound_field_class) + for field in field_line] def __iter__(self): for bound_field in self.bound_fields: @@ -881,7 +884,6 @@ class FieldSet(object): def __len__(self): return len(self.field_lines) - class Admin: def __init__(self, fields=None, js=None, list_display=None, list_filter=None, date_hierarchy=None, save_as=False, ordering=None, search_fields=None, save_on_top=False): @@ -893,34 +895,6 @@ class Admin: self.save_as, self.ordering = save_as, ordering self.search_fields = search_fields or [] self.save_on_top = save_on_top - - def get_field_objs(self, opts): - """ - Returns self.fields, except with fields as Field objects instead of - field names. If self.fields is None, defaults to putting every - non-AutoField field with editable=True in a single fieldset. - - returns a list of lists of name, dict - the dict has attribs 'fields' and maybe 'classes'. - fields is a list of subclasses of Field. - """ - if self.fields is None: - field_struct = ((None, {'fields': [f.name for f in opts.fields + opts.many_to_many if f.editable and not isinstance(f, AutoField)]}),) - else: - field_struct = self.fields - new_fieldset_list = [] - for fieldset in field_struct: - new_fieldset = [fieldset[0], {}] - new_fieldset[1].update(fieldset[1]) - admin_fields = [] - for field_name_or_list in fieldset[1]['fields']: - if isinstance(field_name_or_list, basestring): - admin_fields.append([opts.get_field(field_name_or_list)]) - else: - admin_fields.append([opts.get_field(field_name) for field_name in field_name_or_list]) - new_fieldset[1]['fields'] = admin_fields - new_fieldset_list.append(new_fieldset) - return new_fieldset_list def get_field_sets(self, opts): if self.fields is None: @@ -930,12 +904,11 @@ class Admin: else: field_struct = self.fields - new_fieldset_list = [] for fieldset in field_struct: name = fieldset[0] fs_options = fieldset[1] - classes = fs_options.get('classes', None) + classes = fs_options.get('classes', () ) line_specs = fs_options['fields'] new_fieldset_list.append(FieldSet(name, classes, opts.get_field, line_specs) ) return new_fieldset_list diff --git a/django/core/template/loader.py b/django/core/template/loader.py index 9de009bcfd..498606b7e8 100644 --- a/django/core/template/loader.py +++ b/django/core/template/loader.py @@ -30,6 +30,7 @@ for path in TEMPLATE_LOADERS: try: mod = __import__(module, globals(), locals(), [attr]) except ImportError, e: + raise e raise ImproperlyConfigured, 'Error importing template source loader %s: "%s"' % (module, e) try: func = getattr(mod, attr) @@ -42,10 +43,10 @@ for path in TEMPLATE_LOADERS: template_source_loaders.append(func) class LoaderOrigin(Origin): - def __init__(self, name, loader, name, dirs): + def __init__(self, display_name, loader, name, dirs): def reload(): return loader(name, dirs)[0] - super(LoaderOrigin, self).__init__(name) + super(LoaderOrigin, self).__init__(display_name) self._reload = reload def reload(self): diff --git a/django/core/template/loaders/app_directories.py b/django/core/template/loaders/app_directories.py index 7319f27fe1..a698e94971 100644 --- a/django/core/template/loaders/app_directories.py +++ b/django/core/template/loaders/app_directories.py @@ -7,13 +7,18 @@ import os # At compile time, cache the directories to search. app_template_dirs = [] for app in INSTALLED_APPS: - i = app.rfind('.') - m, a = app[:i], app[i+1:] - mod = getattr(__import__(m, '', '', [a]), a) - template_dir = os.path.join(os.path.dirname(mod.__file__), 'templates') - if os.path.isdir(template_dir): - app_template_dirs.append(template_dir) - + try: + i = app.rfind('.') + m, a = app[:i], app[i+1:] + mod = getattr(__import__(m, '', '', [a]), a) + template_dir = os.path.join(os.path.dirname(mod.__file__), 'templates') + if os.path.isdir(template_dir): + app_template_dirs.append(template_dir) + except Exception, e: + print "exception loading" + print e + raise e + # It won't change, so convert it to a tuple to save memory. app_template_dirs = tuple(app_template_dirs) diff --git a/django/models/__init__.py b/django/models/__init__.py index 2937223361..c787552b4a 100644 --- a/django/models/__init__.py +++ b/django/models/__init__.py @@ -19,44 +19,47 @@ for mod in modules: # Add "get_thingie", "get_thingie_count" and "get_thingie_list" methods # for all related objects. - for rel_obj, rel_field in klass._meta.get_all_related_objects(): + for related in klass._meta.get_all_related_objects(): # Determine whether this related object is in another app. # If it's in another app, the method names will have the app # label prepended, and the add_BLAH() method will not be # generated. - rel_mod = rel_obj.get_model_module() - rel_obj_name = klass._meta.get_rel_object_method_name(rel_obj, rel_field) - if isinstance(rel_field.rel, meta.OneToOne): + rel_mod = related.opts.get_model_module() + rel_obj_name = klass._meta.get_rel_object_method_name(related.opts, related.field) + if isinstance(related.field.rel, meta.OneToOne): # Add "get_thingie" methods for one-to-one related objects. # EXAMPLE: Place.get_restaurants_restaurant() - func = curry(meta.method_get_related, 'get_object', rel_mod, rel_field) - func.__doc__ = "Returns the associated `%s.%s` object." % (rel_obj.app_label, rel_obj.module_name) + func = curry(meta.method_get_related, 'get_object', rel_mod, related.field) + func.__doc__ = "Returns the associated `%s.%s` object." % (related.opts.app_label, related.opts.module_name) setattr(klass, 'get_%s' % rel_obj_name, func) - elif isinstance(rel_field.rel, meta.ManyToOne): + elif isinstance(related.field.rel, meta.ManyToOne): # Add "get_thingie" methods for many-to-one related objects. # EXAMPLE: Poll.get_choice() - func = curry(meta.method_get_related, 'get_object', rel_mod, rel_field) - func.__doc__ = "Returns the associated `%s.%s` object matching the given criteria." % (rel_obj.app_label, rel_obj.module_name) + func = curry(meta.method_get_related, 'get_object', rel_mod, related.field) + func.__doc__ = "Returns the associated `%s.%s` object matching the given criteria." % \ + (related.opts.app_label, related.opts.module_name) setattr(klass, 'get_%s' % rel_obj_name, func) # Add "get_thingie_count" methods for many-to-one related objects. # EXAMPLE: Poll.get_choice_count() - func = curry(meta.method_get_related, 'get_count', rel_mod, rel_field) - func.__doc__ = "Returns the number of associated `%s.%s` objects." % (rel_obj.app_label, rel_obj.module_name) + func = curry(meta.method_get_related, 'get_count', rel_mod, related.field) + func.__doc__ = "Returns the number of associated `%s.%s` objects." % \ + (related.opts.app_label, related.opts.module_name) setattr(klass, 'get_%s_count' % rel_obj_name, func) # Add "get_thingie_list" methods for many-to-one related objects. # EXAMPLE: Poll.get_choice_list() - func = curry(meta.method_get_related, 'get_list', rel_mod, rel_field) - func.__doc__ = "Returns a list of associated `%s.%s` objects." % (rel_obj.app_label, rel_obj.module_name) + func = curry(meta.method_get_related, 'get_list', rel_mod, related.field) + func.__doc__ = "Returns a list of associated `%s.%s` objects." % \ + (related.opts.app_label, related.opts.module_name) setattr(klass, 'get_%s_list' % rel_obj_name, func) # Add "add_thingie" methods for many-to-one related objects, # but only for related objects that are in the same app. # EXAMPLE: Poll.add_choice() - if rel_obj.app_label == klass._meta.app_label: - func = curry(meta.method_add_related, rel_obj, rel_mod, rel_field) + if related.opts.app_label == klass._meta.app_label: + func = curry(meta.method_add_related, related.opts, rel_mod, related.field) func.alters_data = True setattr(klass, 'add_%s' % rel_obj_name, func) del func - del rel_obj_name, rel_mod, rel_obj, rel_field # clean up + del rel_obj_name, rel_mod, related # clean up # Do the same for all related many-to-many objects. for rel_opts, rel_field in klass._meta.get_all_related_many_to_many_objects(): diff --git a/tests/runtests.py b/tests/runtests.py index 9aa96f20fc..fd2d7b43ef 100755 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -100,6 +100,7 @@ class TestRunner: self.output(1, "Creating test database") try: cursor.execute("CREATE DATABASE %s" % TEST_DATABASE_NAME) + print "created" except Exception, e: self.output(0, "There was an error creating the test database:%s " % str(e)) confirm = raw_input("The test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME)