Permalink
Browse files

magic-removal: fixed #1330: edit-inline works again on magic-removal.…

… Note that the API will change *substantailly* before we're done (for example, this reintroduces core fields, which suck) but this at least gives us a place to start with.

Many many thanks for Christopher Lenz, my new hero.


git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@2502 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
1 parent 4e292da commit 738d9af1e8e38b0289b7dfa7c8a5413f5d0e20d1 @jacobian jacobian committed Mar 8, 2006
@@ -12,11 +12,5 @@ <h2>{{ bound_related_object.relation.opts.verbose_name|capfirst }}&nbsp;#{{ forl
{% admin_field_line bound_field %}
{% endif %}
{% endfor %}
- <div class="item actions">
- <button class="deletebutton" name="command" value="{{bound_related_object.relation.var_name}}.{{fcw.index}}.delete">Delete</button>
- </div>
{% endfor %}
- <div class="collection actions">
- <button class="addbutton" name="command" value="{{bound_related_object.relation.var_name}}.add">Add</button>
- </div>
-</fieldset>
+</fieldset>
@@ -1,45 +1,43 @@
{% load admin_modify %}
+<fieldset class="module">
+ <h2>{{ bound_related_object.relation.opts.verbose_name_plural|capfirst }}</h2><table>
+ <thead><tr>
+ {% 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 bound_related_object.form_field_collection_wrappers %}
+ {% if change %}{% if original_row_needed %}
+ {% if fcw.obj.original %}
+ <tr class="row-label {% cycle row1,row2 %}"><td colspan="{{ num_headers }}"><strong>{{ fcw.obj.original }}</strong></tr>
+ {% endif %}
+ {% endif %}{% endif %}
+ {% if fcw.obj.errors %}
+ <tr class="errorlist"><td colspan="{{ num_headers }}">
+ {{ fcw.obj.html_combined_error_list }}
+ </tr>
+ {% endif %}
+ <tr class="{% cycle row1,row2 %}">
+ {% for bound_field in fcw.bound_fields %}
+ {% if not bound_field.hidden %}
+ <td {{ bound_field.cell_class_attribute }}>
+ {% field_widget bound_field %}
+ </td>
+ {% endif %}
+ {% endfor %}
+ {% 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>
-<fieldset class="module editinline">
- <h2>{{ bound_related_object.relation.opts.verbose_name_plural|capfirst }}</h2>
- <table>
- <thead>
- <tr>
- {% 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 %}
- <th>&nbsp;</th>
- </tr>
- </thead>
- <tfoot>
- <tr>
- <td colspan='{{ num_headers }}'>
- <button class="addlink" name="command" value="{{ bound_related_object.relation.var_name }}.add">
- Add another {{ bound_related_object.relation.opts.verbose_name }}
- </button>
- </td>
- </tr>
- </tfoot>
- <tbody>
- {% for fcw in bound_related_object.form_field_collection_wrappers %}
- <tr class="{% cycle row1,row2 %}{% if fcw.obj.errors %} error{% endif %}">
- {% for bound_field in fcw.bound_fields %}
- {% if not bound_field.hidden %}
- <td {{ bound_field.cell_class_attribute }}>
- {{ bound_field.html_error_list }}
- {% field_widget bound_field %}
- </td>
- {% endif %}
- {% endfor %}
- <td class="controls" >
- <button class="inline-deletelink" name="command" value="{{ bound_related_object.relation.var_name }}.{{ fcw.index }}.delete">
- Delete {{ bound_related_object.relation.opts.verbose_name }}
- </button>
- </td>
- </tr>
- {% endfor %}
- </tbody>
- </table>
-</fieldset>
+ {% endfor %} </table>
+
+ {% for fcw in bound_related_object.form_field_collection_wrappers %}
+ {% for bound_field in fcw.bound_fields %}
+ {% if bound_field.hidden %}
+ {% field_widget bound_field %}
+ {% endif %}
+ {% endfor %}
+ {% endfor %}
+</fieldset>
View
@@ -954,6 +954,16 @@ def get_validation_errors(outfile, app=None):
except models.FieldDoesNotExist:
e.add(opts, '"ordering" refers to "%s", a field that doesn\'t exist.' % field_name)
+ # Check core=True, if needed.
+ for related in opts.get_followed_related_objects():
+ try:
+ for f in related.opts.fields:
+ if f.core:
+ raise StopIteration
+ 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
+
# Check unique_together.
for ut in opts.unique_together:
for field_name in ut:
@@ -74,7 +74,7 @@ def __init__(self, verbose_name=None, name=None, primary_key=False,
self.primary_key = primary_key
self.maxlength, self.unique = maxlength, unique
self.blank, self.null = blank, null
- self.rel, self.default = rel, default
+ self.core, self.rel, self.default = core, rel, default
self.editable = editable
self.validator_list = validator_list or []
self.prepopulate_from = prepopulate_from
@@ -88,10 +88,6 @@ def __init__(self, verbose_name=None, name=None, primary_key=False,
# Set db_index to True if the field has a relationship and doesn't explicitly set db_index.
self.db_index = db_index
- self.deprecated_args = []
- if core:
- self.deprecated_args.append('core')
-
# Increase the creation counter, and save our local copy.
self.creation_counter = Field.creation_counter
Field.creation_counter += 1
@@ -219,14 +215,29 @@ def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=
params['validator_list'].append(curry(manipulator_validator_unique, self, opts, manipulator))
# Only add is_required=True if the field cannot be blank. Primary keys
- # are a special case.
- params['is_required'] = not self.blank and not self.primary_key
+ # are a special case, and fields in a related context should set this
+ # as False, because they'll be caught by a separate validator --
+ # RequiredIfOtherFieldGiven.
+ params['is_required'] = not self.blank and not self.primary_key and not rel
# BooleanFields (CheckboxFields) are a special case. They don't take
# is_required or validator_list.
if isinstance(self, BooleanField):
del params['validator_list'], params['is_required']
+ # If this field is in a related context, check whether any other fields
+ # in the related object have core=True. If so, add a validator --
+ # RequiredIfOtherFieldsGiven -- to this FormField.
+ if rel and not self.blank and not isinstance(self, AutoField) and not isinstance(self, FileField):
+ # First, get the core fields, if any.
+ core_field_names = []
+ for f in opts.fields:
+ if f.core and f != self:
+ core_field_names.extend(f.get_manipulator_field_names(name_prefix))
+ # Now, if there are any, add the validator to this FormField.
+ if core_field_names:
+ params['validator_list'].append(validators.RequiredIfOtherFieldsGiven(core_field_names, gettext_lazy("This field is required.")))
+
# Finally, add the field_names.
field_names = self.get_manipulator_field_names(name_prefix)
return [man(field_name=field_names[i], **params) for i, man in enumerate(field_objs)]
@@ -239,9 +250,8 @@ def get_manipulator_new_data(self, new_data, rel=False):
Given the full new_data dictionary (from the manipulator), returns this
field's data.
"""
- #if rel:
- # return new_data.get(self.name, [self.get_default()])[0]
- #else:
+ if rel:
+ return new_data.get(self.name, [self.get_default()])[0]
val = new_data.get(self.name, self.get_default())
if not self.empty_strings_allowed and val == '' and self.null:
val = None
@@ -397,12 +407,12 @@ def get_manipulator_field_names(self, name_prefix):
def get_manipulator_new_data(self, new_data, rel=False):
date_field, time_field = self.get_manipulator_field_names('')
- #if rel:
- # d = new_data.get(date_field, [None])[0]
- # t = new_data.get(time_field, [None])[0]
- #else:
- d = new_data.get(date_field, None)
- t = new_data.get(time_field, None)
+ if rel:
+ d = new_data.get(date_field, [None])[0]
+ t = new_data.get(time_field, [None])[0]
+ else:
+ d = new_data.get(date_field, None)
+ t = new_data.get(time_field, None)
if d is not None and t is not None:
return datetime.datetime.combine(d, t)
return self.get_default()
@@ -492,7 +502,10 @@ def save_file(self, new_data, new_object, original_object, change, rel):
upload_field_name = self.get_manipulator_field_names('')[0]
if new_data.get(upload_field_name, False):
func = getattr(new_object, 'save_%s_file' % self.name)
- func(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"])
+ if rel:
+ func(new_data[upload_field_name][0]["filename"], new_data[upload_field_name][0]["content"])
+ else:
+ func(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"])
def get_directory_name(self):
return os.path.normpath(datetime.datetime.now().strftime(self.upload_to))
@@ -418,6 +418,10 @@ def __init__(self, to, to_field=None, **kwargs):
kwargs['edit_inline'] = kwargs.pop('edit_inline_type')
kwargs['rel'] = ManyToOne(to, to_field,
+ num_in_admin=kwargs.pop('num_in_admin', 3),
+ min_num_in_admin=kwargs.pop('min_num_in_admin', None),
+ max_num_in_admin=kwargs.pop('max_num_in_admin', None),
+ num_extra_on_change=kwargs.pop('num_extra_on_change', 1),
edit_inline=kwargs.pop('edit_inline', False),
related_name=kwargs.pop('related_name', None),
limit_choices_to=kwargs.pop('limit_choices_to', None),
@@ -427,10 +431,6 @@ def __init__(self, to, to_field=None, **kwargs):
self.db_index = True
- for name in ('num_in_admin', 'min_num_in_admin', 'max_num_in_admin', 'num_extra_on_change'):
- if name in kwargs:
- self.deprecated_args.append(name)
-
def get_attname(self):
return '%s_id' % self.name
@@ -501,6 +501,7 @@ def __init__(self, to, to_field=None, **kwargs):
kwargs['edit_inline'] = kwargs.pop('edit_inline_type')
kwargs['rel'] = OneToOne(to, to_field,
+ num_in_admin=kwargs.pop('num_in_admin', 0),
edit_inline=kwargs.pop('edit_inline', False),
related_name=kwargs.pop('related_name', None),
limit_choices_to=kwargs.pop('limit_choices_to', None),
@@ -511,10 +512,6 @@ def __init__(self, to, to_field=None, **kwargs):
self.db_index = True
- for name in ('num_in_admin',):
- if name in kwargs:
- self.deprecated_args.append(name)
-
def get_attname(self):
return '%s_id' % self.name
@@ -534,6 +531,7 @@ class ManyToManyField(RelatedField, Field):
def __init__(self, to, **kwargs):
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
kwargs['rel'] = ManyToMany(to, kwargs.pop('singular', None),
+ num_in_admin=kwargs.pop('num_in_admin', 0),
related_name=kwargs.pop('related_name', None),
filter_interface=kwargs.pop('filter_interface', None),
limit_choices_to=kwargs.pop('limit_choices_to', None),
@@ -542,9 +540,6 @@ def __init__(self, to, **kwargs):
if kwargs["rel"].raw_id_admin:
kwargs.setdefault("validator_list", []).append(self.isValidIDList)
Field.__init__(self, **kwargs)
- for name in ('num_in_admin'):
- if name in kwargs:
- self.deprecated_args.append(name)
if self.rel.raw_id_admin:
msg = gettext_lazy('Separate multiple IDs with commas.')
@@ -641,15 +636,17 @@ def set_attributes_from_rel(self):
pass
class ManyToOne:
- def __init__(self, to, field_name, edit_inline=False,
+ def __init__(self, to, field_name, num_in_admin=3, min_num_in_admin=None,
+ max_num_in_admin=None, num_extra_on_change=1, edit_inline=False,
related_name=None, limit_choices_to=None, lookup_overrides=None, raw_id_admin=False):
try:
to._meta
- except AttributeError:
+ except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
assert isinstance(to, basestring), "'to' must be either a model, a model name or the string %r" % RECURSIVE_RELATIONSHIP_CONSTANT
self.to, self.field_name = to, field_name
- self.edit_inline = edit_inline
- self.related_name = related_name
+ self.num_in_admin, self.edit_inline = num_in_admin, edit_inline
+ self.min_num_in_admin, self.max_num_in_admin = min_num_in_admin, max_num_in_admin
+ self.num_extra_on_change, self.related_name = num_extra_on_change, related_name
self.limit_choices_to = limit_choices_to or {}
self.lookup_overrides = lookup_overrides or {}
self.raw_id_admin = raw_id_admin
@@ -660,22 +657,23 @@ def get_related_field(self):
return self.to._meta.get_field(self.field_name)
class OneToOne(ManyToOne):
- def __init__(self, to, field_name, edit_inline=False,
+ def __init__(self, to, field_name, num_in_admin=0, edit_inline=False,
related_name=None, limit_choices_to=None, lookup_overrides=None,
raw_id_admin=False):
self.to, self.field_name = to, field_name
- self.edit_inline = edit_inline
+ self.num_in_admin, self.edit_inline = num_in_admin, edit_inline
self.related_name = related_name
self.limit_choices_to = limit_choices_to or {}
self.lookup_overrides = lookup_overrides or {}
self.raw_id_admin = raw_id_admin
self.multiple = False
-
+
class ManyToMany:
- def __init__(self, to, singular=None, related_name=None,
+ def __init__(self, to, singular=None, num_in_admin=0, related_name=None,
filter_interface=None, limit_choices_to=None, raw_id_admin=False, symmetrical=True):
self.to = to
self.singular = singular or None
+ self.num_in_admin = num_in_admin
self.related_name = related_name
self.filter_interface = filter_interface
self.limit_choices_to = limit_choices_to or {}
@@ -139,6 +139,9 @@ def save(self, new_data):
if child_follow:
obj_list = expanded_data[related.var_name].items()
+ if not obj_list:
+ continue
+
obj_list.sort(lambda x, y: cmp(int(x[0]), int(y[0])))
# For each related item...
@@ -187,15 +190,8 @@ def save(self, new_data):
if param != None:
params[f.attname] = param
- # Related links are a special case, because we have to
- # manually set the "content_type_id" and "object_id" fields.
- if self.opts.has_related_links and related.opts.module_name == 'relatedlinks':
- contenttypes_mod = get_module('core', 'contenttypes')
- params['content_type_id'] = contenttypes_mod.get_object(package__label__exact=self.opts.app_label, python_module_name__exact=self.opts.module_name).id
- params['object_id'] = new_object.id
-
# Create the related item.
- new_rel_obj = related.opts.get_model_module().Klass(**params)
+ new_rel_obj = related.model(**params)
# If all the core fields were provided (non-empty), save the item.
if all_cores_given:
Oops, something went wrong.

0 comments on commit 738d9af

Please sign in to comment.