1
0
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:
Robert Wittams 2005-10-20 19:07:15 +00:00
parent 5d74e282a4
commit bd47a97997
11 changed files with 144 additions and 174 deletions

View File

@ -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

View File

@ -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 %}

View File

@ -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():

View File

@ -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()

View File

@ -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)

View File

@ -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']}),

View File

@ -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

View File

@ -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):

View File

@ -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)

View File

@ -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():

View File

@ -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)