mirror of
https://github.com/django/django.git
synced 2025-07-05 10:19:20 +00:00
Rationalised related object methods
git-svn-id: http://code.djangoproject.com/svn/django/branches/new-admin@982 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
5d74e282a4
commit
bd47a97997
@ -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
|
||||
|
@ -21,13 +21,11 @@
|
||||
{% endif %}{% endif %}
|
||||
<form {{ form_enc_attrib }} action='{{ form_url }}' method="post">
|
||||
|
||||
|
||||
{% if is_popup %}<input type="hidden" name="_popup" value="1">{% endif %}
|
||||
{% if save_on_top %}{% submit_row %}{% endif %}
|
||||
{% if form.error_dict %}<p class="errornote">Please correct the error{{ form.error_dict.items|pluralize }} below.</p>{% endif %}
|
||||
{% for bound_field_set in bound_field_sets %}
|
||||
<fieldset class="module aligned {{ bound_field_set.classes }}">
|
||||
|
||||
{% if bound_field_set.name %}<h2>{{bound_field_set.name }}</h2>{% endif %}
|
||||
{% for bound_field_line in bound_field_set %}
|
||||
{% admin_field_line bound_field_line %}
|
||||
|
@ -518,7 +518,7 @@ def _get_submit_row_template(opts, app_label, add, change, show_delete, ordered_
|
||||
t.append('</div>\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,22 +608,12 @@ 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']
|
||||
|
||||
@ -631,10 +621,9 @@ def fill_extra_context(opts, app_label, context, add=False, change=False, show_d
|
||||
bound_field_sets = [field_set.bind(form, original, AdminBoundFieldSet)
|
||||
for field_set in field_sets]
|
||||
|
||||
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_inline_related_objects_wrapped()
|
||||
|
||||
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,9 +794,12 @@ 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, {
|
||||
@ -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: <a href="../../../../%s/%s/%s/">%r</a>' % \
|
||||
(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: <a href="../../../../%s/%s/%s/">%s</a>' % \
|
||||
(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():
|
||||
|
@ -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,7 +97,7 @@ 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
|
||||
@ -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()
|
||||
|
@ -306,7 +306,7 @@ def init():
|
||||
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)
|
||||
|
@ -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']}),
|
||||
|
@ -48,6 +48,25 @@ 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 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
|
||||
@ -293,6 +312,9 @@ class Field(object):
|
||||
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
|
||||
def __init__(self, *args, **kwargs):
|
||||
@ -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):
|
||||
@ -894,34 +896,6 @@ class Admin:
|
||||
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:
|
||||
field_struct = ((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
|
||||
|
@ -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):
|
||||
|
@ -7,12 +7,17 @@ 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)
|
||||
|
@ -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():
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user