diff --git a/django/contrib/admin/templates/admin/edit_inline_stacked.html b/django/contrib/admin/templates/admin/edit_inline_stacked.html
index 4a9f6ce17c..ca9e7095d1 100644
--- a/django/contrib/admin/templates/admin/edit_inline_stacked.html
+++ b/django/contrib/admin/templates/admin/edit_inline_stacked.html
@@ -1,7 +1,7 @@
- {% for fcw in form_field_collection_wrapper_list %}
- {{relation.opts.verbose_name|capfirst }} #{{ forloop.counter }}
- {% if fcw.show_url %}{% if fcw.obj.original %}
+ {% for fcw in bound_related_object.form_field_collection_wrappers %}
+ {{ bound_related_object.relation.opts.verbose_name|capfirst }} #{{ forloop.counter }}
+ {% if bound_related_object.show_url %}{% if fcw.obj.original %}
View on site
{% endif %}{% endif %}
{% for bound_field in fcw.bound_fields %}
@@ -12,5 +12,4 @@
{% endif %}
{% endfor %}
{%endfor%}
-
-
+
\ No newline at end of file
diff --git a/django/contrib/admin/templates/admin/edit_inline_tabular.html b/django/contrib/admin/templates/admin/edit_inline_tabular.html
index a7f25cbcbe..ddfe6f0ff2 100644
--- a/django/contrib/admin/templates/admin/edit_inline_tabular.html
+++ b/django/contrib/admin/templates/admin/edit_inline_tabular.html
@@ -1,12 +1,12 @@
- {{relation.opts.verbose_name_plural|capfirst}}
+ {{bound_related_object.relation.opts.verbose_name_plural|capfirst}}
- {% for fw in field_wrapper_list %}
+ {% for fw in bound_related_object.field_wrapper_list %}
{% if fw.needs_header %}
{{fw.field.verbose_name|capfirst}}
{% endif %}
{% endfor %}
- {% for fcw in form_field_collection_wrapper_list %}
+ {% for fcw in bound_related_object.form_field_collection_wrappers %}
{% if change %}{% if original_row_needed %}
{% if fcw.obj.original %}
@@ -26,14 +26,14 @@
{% endif %}
{% endfor %}
- {% if fcw.show_url %}
+ {% if bound_related_object.show_url %}
{% if fcw.obj.original %}View on site {% endif %}
{% endif %}
{% endfor %}
- {% for fcw in form_field_collection_wrapper_list %}
+ {% for fcw in bound_related_object.form_field_collection_wrapper_list %}
{% for bound_field in fcw.bound_fields %}
{% if bound_field.not_in_table %}
{% field_widget bound_field %}
diff --git a/django/contrib/admin/templatetags/admin_modify.py b/django/contrib/admin/templatetags/admin_modify.py
index 38b5f2c8fa..aed13c22c9 100644
--- a/django/contrib/admin/templatetags/admin_modify.py
+++ b/django/contrib/admin/templatetags/admin_modify.py
@@ -4,11 +4,11 @@ from django.conf.settings import ADMIN_MEDIA_PREFIX
from django.utils.text import capfirst
from django.utils.html import escape
from django.utils.functional import curry
-
from django.core.template.decorators import simple_tag, inclusion_tag
-
from django.contrib.admin.views.main import AdminBoundField
from django.core.meta.fields import BoundField, Field
+from django.core.meta import BoundRelatedObject, TABULAR, STACKED
+
import re
word_re = re.compile('[A-Z][a-z]+')
@@ -122,14 +122,41 @@ class FieldWrapper(object):
return isinstance(self.field.rel, (meta.ManyToOne, meta.ManyToMany)) \
and self.field.rel.raw_id_admin
+
class FormFieldCollectionWrapper(object):
def __init__(self, field_mapping, fields):
self.field_mapping = field_mapping
self.fields = fields
- self.bound_fields = [ AdminBoundField(field, self.field_mapping, field_mapping['original']) for field in self.fields ]
+ self.bound_fields = [AdminBoundField(field, self.field_mapping, field_mapping['original']) for field in self.fields ]
+
+class TabularBoundRelatedObject(BoundRelatedObject):
+ def __init__(self, related_object, field_mapping, original):
+ super(TabularBoundRelatedObject, self).__init__(related_object, field_mapping, original)
+ self.field_wrapper_list = self.relation.editable_fields(FieldWrapper)
+ fields = self.relation.editable_fields()
+ self.form_field_collection_wrappers = [FormFieldCollectionWrapper(field_mapping ,fields)
+ for field_mapping in self.field_mappings]
+ self.original_row_needed = max([fw.use_raw_id_admin() for fw in self.field_wrapper_list])
+ self.show_url = original and hasattr(self.relation.opts, 'get_absolute_url')
- def showurl(self):
- return False
+ def template_name(self):
+ return "admin/edit_inline_tabular"
+
+class StackedBoundRelatedObject(BoundRelatedObject):
+ def __init__(self, related_object, field_mapping, original):
+ super(StackedBoundRelatedObject, self).__init__(related_object, field_mapping, original)
+ fields = self.relation.editable_fields()
+ self.form_field_collection_wrappers = [FormFieldCollectionWrapper(field_mapping ,fields)
+ for field_mapping in self.field_mappings]
+ self.show_url = original and hasattr(self.relation.opts, 'get_absolute_url')
+
+ def template_name(self):
+ return "admin/edit_inline_stacked"
+
+bound_related_object_overrides = {
+ TABULAR : TabularBoundRelatedObject,
+ STACKED : StackedBoundRelatedObject
+}
class EditInlineNode(template.Node):
def __init__(self, rel_var):
@@ -137,34 +164,24 @@ class EditInlineNode(template.Node):
def render(self, context):
relation = template.resolve_variable(self.rel_var, context)
- add, change = context['add'], context['change']
-
+
context.push()
- self.fill_context(relation, add, change, context)
+ klass = relation.field.rel.edit_inline
+ bound_related_object_class = bound_related_object_overrides.get(klass, klass)
- t = template_loader.get_template(relation.field.rel.edit_inline)
+ original = context.get('original', None)
+
+ bound_related_object = relation.bind(context['form'], original, bound_related_object_class)
+ context['bound_related_object'] = bound_related_object
+
+ t = template_loader.get_template( bound_related_object.template_name() )
output = t.render(context)
context.pop()
return output
- def fill_context(self, relation, add, change, context):
- field_wrapper_list = relation.editable_fields(FieldWrapper)
-
- var_name = relation.opts.object_name.lower()
-
- form = template.resolve_variable('form', context)
- form_field_collections = form[relation.opts.module_name]
- fields = relation.editable_fields()
- form_field_collection_wrapper_list = [FormFieldCollectionWrapper(field_mapping ,fields) for field_mapping in form_field_collections]
-
- context['field_wrapper_list'] = field_wrapper_list
- context['form_field_collection_wrapper_list'] = form_field_collection_wrapper_list
- context['num_headers'] = len(field_wrapper_list)
- context['original_row_needed'] = max([fw.use_raw_id_admin() for fw in field_wrapper_list])
-
#@simple_tag
def output_all(form_fields):
@@ -201,7 +218,7 @@ def do_one_arg_tag(node_factory, parser,token):
tokens = token.contents.split()
if len(tokens) != 2:
raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0])
- return node_factory(tokens[1])
+ return node_factory(tokens[1])
one_arg_tag_nodes = [
diff --git a/django/core/meta/__init__.py b/django/core/meta/__init__.py
index d843ce7862..5cf823140c 100644
--- a/django/core/meta/__init__.py
+++ b/django/core/meta/__init__.py
@@ -146,7 +146,17 @@ class FieldDoesNotExist(Exception):
class BadKeywordArguments(Exception):
pass
-
+class BoundRelatedObject(object):
+ def __init__(self,related_object, field_mapping, original):
+ self.relation = related_object
+ self.field_mappings = field_mapping[related_object.opts.module_name]
+
+ def template_name(self):
+ raise NotImplementedException
+
+ def __repr__(self):
+ return repr(self.__dict__)
+
class RelatedObject(object):
def __init__(self,parent_opts, opts, field):
self.parent_opts = parent_opts
@@ -249,9 +259,9 @@ class RelatedObject(object):
f.get_manipulator_fields(self.opts, manipulator, change, name_prefix=prefix, rel=True))
return fields
-
-class BoundRelatedObject(object):
- pass
+
+ def bind(self, field_mapping, original, bound_related_object_class=BoundRelatedObject):
+ return bound_related_object_class(self, field_mapping, original)
class Options:
def __init__(self, module_name='', verbose_name='', verbose_name_plural='', db_table='',
@@ -469,7 +479,7 @@ class Options:
self._ordered_objects = objects
return self._ordered_objects
- def has_field_type(self, field_type, follow):
+ def has_field_type(self, field_type, follow = None):
"""
Returns True if this object's admin form has at least one of the given
field_type (e.g. FileField).
@@ -1754,12 +1764,15 @@ def manipulator_flatten_data(opts, klass, add, change, self):
def manipulator_validator_unique_together(field_name_list, opts, self, field_data, all_data):
from django.utils.text import get_text_list
+
field_list = [opts.get_field(field_name) for field_name in field_name_list]
if isinstance(field_list[0].rel, ManyToOne):
kwargs = {'%s__%s__iexact' % (field_name_list[0], field_list[0].rel.field_name): field_data}
else:
kwargs = {'%s__iexact' % field_name_list[0]: field_data}
for f in field_list[1:]:
+ # This is really not going to work for fields that have different form fields, eg DateTime
+ # This validation needs to occur after html2python to be effective.
field_val = all_data.get(f.column, None)
if field_val is None:
# This will be caught by another validator, assuming the field
diff --git a/django/core/meta/fields.py b/django/core/meta/fields.py
index 8e82d66b23..a1a33ec4b7 100644
--- a/django/core/meta/fields.py
+++ b/django/core/meta/fields.py
@@ -16,7 +16,7 @@ BLANK_CHOICE_DASH = [("", "---------")]
BLANK_CHOICE_NONE = [("", "None")]
# Values for Relation.edit_inline.
-TABULAR, STACKED = "admin/edit_inline_tabular", "admin/edit_inline_stacked"
+TABULAR, STACKED = 1, 2
RECURSIVE_RELATIONSHIP_CONSTANT = 'self'
diff --git a/django/core/template/__init__.py b/django/core/template/__init__.py
index 611126abd3..3290b5d940 100644
--- a/django/core/template/__init__.py
+++ b/django/core/template/__init__.py
@@ -195,6 +195,12 @@ class Context:
if dict.has_key(key):
return True
return False
+
+ def get(self, key, otherwise):
+ for dict in self.dicts:
+ if dict.has_key(key):
+ return dict[key]
+ return otherwise
def update(self, other_dict):
"Like dict.update(). Pushes an entire dictionary's keys and values onto the context."
diff --git a/django/core/template/loaders/app_directories.py b/django/core/template/loaders/app_directories.py
index a698e94971..31cdfd5993 100644
--- a/django/core/template/loaders/app_directories.py
+++ b/django/core/template/loaders/app_directories.py
@@ -7,17 +7,13 @@ import os
# At compile time, cache the directories to search.
app_template_dirs = []
for app in INSTALLED_APPS:
- 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
+ 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)
+
# It won't change, so convert it to a tuple to save memory.
app_template_dirs = tuple(app_template_dirs)
diff --git a/tests/runtests.py b/tests/runtests.py
index fd2d7b43ef..9aa96f20fc 100755
--- a/tests/runtests.py
+++ b/tests/runtests.py
@@ -100,7 +100,6 @@ 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)