mirror of
https://github.com/django/django.git
synced 2025-07-04 09:49:12 +00:00
Changed how edit_inline works in the admin. Now it is done by a subclass of BoundRelatedObject.
This means anyone using edit_inline="path/to/template" will need to subclass this ( or TabularBoundRelatedObject or StackedBoundRelatedObject). The functionality may be restored if it becomes obvious exactly what information should be available to these templates; before it was kind of random. So you can do class MyBoundRelatedObject(TabularBoundRelatedObject): def template_name(self): return "path/to/template" and then edit_inline=MyBoundRelatedObject to duplicate the previous functionality. git-svn-id: http://code.djangoproject.com/svn/django/branches/new-admin@986 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
bd47a97997
commit
c40fd89b1a
@ -1,7 +1,7 @@
|
||||
<fieldset class="module aligned">
|
||||
{% for fcw in form_field_collection_wrapper_list %}
|
||||
<h2>{{relation.opts.verbose_name|capfirst }} #{{ forloop.counter }}</h2>
|
||||
{% if fcw.show_url %}{% if fcw.obj.original %}
|
||||
{% for fcw in bound_related_object.form_field_collection_wrappers %}
|
||||
<h2>{{ bound_related_object.relation.opts.verbose_name|capfirst }} #{{ forloop.counter }}</h2>
|
||||
{% if bound_related_object.show_url %}{% if fcw.obj.original %}
|
||||
<p><a href="/r/{{ fcw.obj.original.content_type_id }}/{{ fcw.obj.original.id }}/">View on site</a></p>
|
||||
{% endif %}{% endif %}
|
||||
{% for bound_field in fcw.bound_fields %}
|
||||
@ -12,5 +12,4 @@
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{%endfor%}
|
||||
</fieldset>
|
||||
|
||||
</fieldset>
|
@ -1,12 +1,12 @@
|
||||
<fieldset class="module">
|
||||
<h2>{{relation.opts.verbose_name_plural|capfirst}}</h2><table>
|
||||
<h2>{{bound_related_object.relation.opts.verbose_name_plural|capfirst}}</h2><table>
|
||||
<thead><tr>
|
||||
{% for fw in field_wrapper_list %}
|
||||
{% for fw in bound_related_object.field_wrapper_list %}
|
||||
{% if fw.needs_header %}
|
||||
<th{{fw.header_class_attribute}}> {{fw.field.verbose_name|capfirst}} </th>
|
||||
{% 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 @@
|
||||
</td>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if fcw.show_url %}<td>
|
||||
{% if bound_related_object.show_url %}<td>
|
||||
{% if fcw.obj.original %}<a href="/r/{{ fcw.obj.original.content_type_id }}/{{ fcw.obj.original.id }}/">View on site</a>{% endif %}
|
||||
</td>{% endif %}
|
||||
</tr>
|
||||
|
||||
{% endfor %} </table>
|
||||
|
||||
{% 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 %}
|
||||
|
@ -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 = [
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
||||
|
@ -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."
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user