mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	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
This commit is contained in:
		| @@ -12,11 +12,5 @@ | |||||||
|             {% admin_field_line bound_field %} |             {% admin_field_line bound_field %} | ||||||
|          {% endif %} |          {% endif %} | ||||||
|       {% endfor %} |       {% endfor %} | ||||||
|       <div class="item actions"> |  | ||||||
|       <button class="deletebutton" name="command" value="{{bound_related_object.relation.var_name}}.{{fcw.index}}.delete">Delete</button> |  | ||||||
|       </div> |  | ||||||
|     {% endfor %} |     {% endfor %} | ||||||
|     <div class="collection actions"> | </fieldset> | ||||||
|     <button class="addbutton" name="command" value="{{bound_related_object.relation.var_name}}.add">Add</button> |  | ||||||
| 	</div> |  | ||||||
| </fieldset> |  | ||||||
|   | |||||||
| @@ -1,45 +1,43 @@ | |||||||
| {% load admin_modify %} | {% 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"> |    {% endfor %} </table> | ||||||
|     <h2>{{ bound_related_object.relation.opts.verbose_name_plural|capfirst }}</h2> |  | ||||||
| 	<table> |    {% for fcw in bound_related_object.form_field_collection_wrappers %} | ||||||
| 		<thead> |       {% for bound_field in fcw.bound_fields %} | ||||||
| 			<tr> |          {% if bound_field.hidden %} | ||||||
| 			    {% for fw in bound_related_object.field_wrapper_list %} |             {% field_widget bound_field %} | ||||||
| 			        {% if fw.needs_header %} |          {% endif %} | ||||||
| 			            <th{{ fw.header_class_attribute }}>{{ fw.field.verbose_name|capfirst }}</th> |       {% endfor %} | ||||||
| 			        {% endif %} |    {% endfor %} | ||||||
| 			    {% endfor %} | </fieldset> | ||||||
| 				<th> </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> |  | ||||||
|   | |||||||
| @@ -954,6 +954,16 @@ def get_validation_errors(outfile, app=None): | |||||||
|                 except models.FieldDoesNotExist: |                 except models.FieldDoesNotExist: | ||||||
|                     e.add(opts, '"ordering" refers to "%s", a field that doesn\'t exist.' % field_name) |                     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. |         # Check unique_together. | ||||||
|         for ut in opts.unique_together: |         for ut in opts.unique_together: | ||||||
|             for field_name in ut: |             for field_name in ut: | ||||||
|   | |||||||
| @@ -74,7 +74,7 @@ class Field(object): | |||||||
|         self.primary_key = primary_key |         self.primary_key = primary_key | ||||||
|         self.maxlength, self.unique = maxlength, unique |         self.maxlength, self.unique = maxlength, unique | ||||||
|         self.blank, self.null = blank, null |         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.editable = editable | ||||||
|         self.validator_list = validator_list or [] |         self.validator_list = validator_list or [] | ||||||
|         self.prepopulate_from = prepopulate_from |         self.prepopulate_from = prepopulate_from | ||||||
| @@ -88,10 +88,6 @@ class Field(object): | |||||||
|         # Set db_index to True if the field has a relationship and doesn't explicitly set db_index. |         # Set db_index to True if the field has a relationship and doesn't explicitly set db_index. | ||||||
|         self.db_index = 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. |         # Increase the creation counter, and save our local copy. | ||||||
|         self.creation_counter = Field.creation_counter |         self.creation_counter = Field.creation_counter | ||||||
|         Field.creation_counter += 1 |         Field.creation_counter += 1 | ||||||
| @@ -219,14 +215,29 @@ class Field(object): | |||||||
|             params['validator_list'].append(curry(manipulator_validator_unique, self, opts, manipulator)) |             params['validator_list'].append(curry(manipulator_validator_unique, self, opts, manipulator)) | ||||||
|  |  | ||||||
|         # Only add is_required=True if the field cannot be blank. Primary keys |         # Only add is_required=True if the field cannot be blank. Primary keys | ||||||
|         # are a special case. |         # are a special case, and fields in a related context should set this | ||||||
|         params['is_required'] = not self.blank and not self.primary_key |         # 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 |         # BooleanFields (CheckboxFields) are a special case. They don't take | ||||||
|         # is_required or validator_list. |         # is_required or validator_list. | ||||||
|         if isinstance(self, BooleanField): |         if isinstance(self, BooleanField): | ||||||
|             del params['validator_list'], params['is_required'] |             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. |         # Finally, add the field_names. | ||||||
|         field_names = self.get_manipulator_field_names(name_prefix) |         field_names = self.get_manipulator_field_names(name_prefix) | ||||||
|         return [man(field_name=field_names[i], **params) for i, man in enumerate(field_objs)] |         return [man(field_name=field_names[i], **params) for i, man in enumerate(field_objs)] | ||||||
| @@ -239,9 +250,8 @@ class Field(object): | |||||||
|         Given the full new_data dictionary (from the manipulator), returns this |         Given the full new_data dictionary (from the manipulator), returns this | ||||||
|         field's data. |         field's data. | ||||||
|         """ |         """ | ||||||
|         #if rel: |         if rel: | ||||||
|         #    return new_data.get(self.name, [self.get_default()])[0] |             return new_data.get(self.name, [self.get_default()])[0] | ||||||
|         #else: |  | ||||||
|         val = new_data.get(self.name, self.get_default()) |         val = new_data.get(self.name, self.get_default()) | ||||||
|         if not self.empty_strings_allowed and val == '' and self.null: |         if not self.empty_strings_allowed and val == '' and self.null: | ||||||
|             val = None |             val = None | ||||||
| @@ -397,12 +407,12 @@ class DateTimeField(DateField): | |||||||
|  |  | ||||||
|     def get_manipulator_new_data(self, new_data, rel=False): |     def get_manipulator_new_data(self, new_data, rel=False): | ||||||
|         date_field, time_field = self.get_manipulator_field_names('') |         date_field, time_field = self.get_manipulator_field_names('') | ||||||
|         #if rel: |         if rel: | ||||||
|         #    d = new_data.get(date_field, [None])[0] |             d = new_data.get(date_field, [None])[0] | ||||||
|         #    t = new_data.get(time_field, [None])[0] |             t = new_data.get(time_field, [None])[0] | ||||||
|         #else: |         else: | ||||||
|         d = new_data.get(date_field, None) |             d = new_data.get(date_field, None) | ||||||
|         t = new_data.get(time_field, None) |             t = new_data.get(time_field, None) | ||||||
|         if d is not None and t is not None: |         if d is not None and t is not None: | ||||||
|             return datetime.datetime.combine(d, t) |             return datetime.datetime.combine(d, t) | ||||||
|         return self.get_default() |         return self.get_default() | ||||||
| @@ -492,7 +502,10 @@ class FileField(Field): | |||||||
|         upload_field_name = self.get_manipulator_field_names('')[0] |         upload_field_name = self.get_manipulator_field_names('')[0] | ||||||
|         if new_data.get(upload_field_name, False): |         if new_data.get(upload_field_name, False): | ||||||
|             func = getattr(new_object, 'save_%s_file' % self.name) |             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): |     def get_directory_name(self): | ||||||
|         return os.path.normpath(datetime.datetime.now().strftime(self.upload_to)) |         return os.path.normpath(datetime.datetime.now().strftime(self.upload_to)) | ||||||
|   | |||||||
| @@ -418,6 +418,10 @@ class ForeignKey(RelatedField, Field): | |||||||
|             kwargs['edit_inline'] = kwargs.pop('edit_inline_type') |             kwargs['edit_inline'] = kwargs.pop('edit_inline_type') | ||||||
|  |  | ||||||
|         kwargs['rel'] = ManyToOne(to, to_field, |         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), |             edit_inline=kwargs.pop('edit_inline', False), | ||||||
|             related_name=kwargs.pop('related_name', None), |             related_name=kwargs.pop('related_name', None), | ||||||
|             limit_choices_to=kwargs.pop('limit_choices_to', None), |             limit_choices_to=kwargs.pop('limit_choices_to', None), | ||||||
| @@ -427,10 +431,6 @@ class ForeignKey(RelatedField, Field): | |||||||
|  |  | ||||||
|         self.db_index = True |         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): |     def get_attname(self): | ||||||
|         return '%s_id' % self.name |         return '%s_id' % self.name | ||||||
|  |  | ||||||
| @@ -501,6 +501,7 @@ class OneToOneField(RelatedField, IntegerField): | |||||||
|             kwargs['edit_inline'] = kwargs.pop('edit_inline_type') |             kwargs['edit_inline'] = kwargs.pop('edit_inline_type') | ||||||
|  |  | ||||||
|         kwargs['rel'] = OneToOne(to, to_field, |         kwargs['rel'] = OneToOne(to, to_field, | ||||||
|  |             num_in_admin=kwargs.pop('num_in_admin', 0), | ||||||
|             edit_inline=kwargs.pop('edit_inline', False), |             edit_inline=kwargs.pop('edit_inline', False), | ||||||
|             related_name=kwargs.pop('related_name', None), |             related_name=kwargs.pop('related_name', None), | ||||||
|             limit_choices_to=kwargs.pop('limit_choices_to', None), |             limit_choices_to=kwargs.pop('limit_choices_to', None), | ||||||
| @@ -511,10 +512,6 @@ class OneToOneField(RelatedField, IntegerField): | |||||||
|  |  | ||||||
|         self.db_index = True |         self.db_index = True | ||||||
|  |  | ||||||
|         for name in ('num_in_admin',): |  | ||||||
|             if name in kwargs: |  | ||||||
|                 self.deprecated_args.append(name) |  | ||||||
|  |  | ||||||
|     def get_attname(self): |     def get_attname(self): | ||||||
|         return '%s_id' % self.name |         return '%s_id' % self.name | ||||||
|  |  | ||||||
| @@ -534,6 +531,7 @@ class ManyToManyField(RelatedField, Field): | |||||||
|     def __init__(self, to, **kwargs): |     def __init__(self, to, **kwargs): | ||||||
|         kwargs['verbose_name'] = kwargs.get('verbose_name', None) |         kwargs['verbose_name'] = kwargs.get('verbose_name', None) | ||||||
|         kwargs['rel'] = ManyToMany(to, kwargs.pop('singular', 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), |             related_name=kwargs.pop('related_name', None), | ||||||
|             filter_interface=kwargs.pop('filter_interface', None), |             filter_interface=kwargs.pop('filter_interface', None), | ||||||
|             limit_choices_to=kwargs.pop('limit_choices_to', None), |             limit_choices_to=kwargs.pop('limit_choices_to', None), | ||||||
| @@ -542,9 +540,6 @@ class ManyToManyField(RelatedField, Field): | |||||||
|         if kwargs["rel"].raw_id_admin: |         if kwargs["rel"].raw_id_admin: | ||||||
|             kwargs.setdefault("validator_list", []).append(self.isValidIDList) |             kwargs.setdefault("validator_list", []).append(self.isValidIDList) | ||||||
|         Field.__init__(self, **kwargs) |         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: |         if self.rel.raw_id_admin: | ||||||
|             msg = gettext_lazy('Separate multiple IDs with commas.') |             msg = gettext_lazy('Separate multiple IDs with commas.') | ||||||
| @@ -641,15 +636,17 @@ class ManyToManyField(RelatedField, Field): | |||||||
|         pass |         pass | ||||||
|  |  | ||||||
| class ManyToOne: | 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): |         related_name=None, limit_choices_to=None, lookup_overrides=None, raw_id_admin=False): | ||||||
|         try: |         try: | ||||||
|             to._meta |             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 |             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.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.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.limit_choices_to = limit_choices_to or {} | ||||||
|         self.lookup_overrides = lookup_overrides or {} |         self.lookup_overrides = lookup_overrides or {} | ||||||
|         self.raw_id_admin = raw_id_admin |         self.raw_id_admin = raw_id_admin | ||||||
| @@ -660,22 +657,23 @@ class ManyToOne: | |||||||
|         return self.to._meta.get_field(self.field_name) |         return self.to._meta.get_field(self.field_name) | ||||||
|  |  | ||||||
| class OneToOne(ManyToOne): | 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, |         related_name=None, limit_choices_to=None, lookup_overrides=None, | ||||||
|         raw_id_admin=False): |         raw_id_admin=False): | ||||||
|         self.to, self.field_name = to, field_name |         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.related_name = related_name | ||||||
|         self.limit_choices_to = limit_choices_to or {} |         self.limit_choices_to = limit_choices_to or {} | ||||||
|         self.lookup_overrides = lookup_overrides or {} |         self.lookup_overrides = lookup_overrides or {} | ||||||
|         self.raw_id_admin = raw_id_admin |         self.raw_id_admin = raw_id_admin | ||||||
|         self.multiple = False |         self.multiple = False | ||||||
|          |  | ||||||
| class ManyToMany: | 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): |         filter_interface=None, limit_choices_to=None, raw_id_admin=False, symmetrical=True): | ||||||
|         self.to = to |         self.to = to | ||||||
|         self.singular = singular or None |         self.singular = singular or None | ||||||
|  |         self.num_in_admin = num_in_admin | ||||||
|         self.related_name = related_name |         self.related_name = related_name | ||||||
|         self.filter_interface = filter_interface |         self.filter_interface = filter_interface | ||||||
|         self.limit_choices_to = limit_choices_to or {} |         self.limit_choices_to = limit_choices_to or {} | ||||||
|   | |||||||
| @@ -139,6 +139,9 @@ class AutomaticManipulator(forms.Manipulator): | |||||||
|  |  | ||||||
|             if child_follow: |             if child_follow: | ||||||
|                 obj_list = expanded_data[related.var_name].items() |                 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]))) |                 obj_list.sort(lambda x, y: cmp(int(x[0]), int(y[0]))) | ||||||
|  |  | ||||||
|                 # For each related item... |                 # For each related item... | ||||||
| @@ -187,15 +190,8 @@ class AutomaticManipulator(forms.Manipulator): | |||||||
|                         if param != None: |                         if param != None: | ||||||
|                             params[f.attname] = param |                             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. |                     # 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 the core fields were provided (non-empty), save the item. | ||||||
|                     if all_cores_given: |                     if all_cores_given: | ||||||
|   | |||||||
| @@ -41,6 +41,35 @@ class RelatedObject(object): | |||||||
|         """ |         """ | ||||||
|         return data # TODO |         return data # TODO | ||||||
|  |  | ||||||
|  |     def get_list(self, parent_instance=None): | ||||||
|  |         "Get the list of this type of object from an instance of the parent class." | ||||||
|  |         if parent_instance is not None: | ||||||
|  |             attr = getattr(parent_instance, self.get_accessor_name()) | ||||||
|  |             if self.field.rel.multiple: | ||||||
|  |                 # For many-to-many relationships, return a list of objects | ||||||
|  |                 # corresponding to the xxx_num_in_admin options of the field | ||||||
|  |                 objects = list(attr.all()) | ||||||
|  |  | ||||||
|  |                 count = len(objects) + self.field.rel.num_extra_on_change | ||||||
|  |                 if self.field.rel.min_num_in_admin: | ||||||
|  |                    count = max(count, self.field.rel.min_num_in_admin) | ||||||
|  |                 if self.field.rel.max_num_in_admin: | ||||||
|  |                    count = min(count, self.field.rel.max_num_in_admin) | ||||||
|  |  | ||||||
|  |                 change = count - len(objects) | ||||||
|  |                 if change > 0: | ||||||
|  |                     return objects + [None for _ in range(change)] | ||||||
|  |                 if change < 0: | ||||||
|  |                     return objects[:change] | ||||||
|  |                 else: # Just right | ||||||
|  |                     return objects | ||||||
|  |             else: | ||||||
|  |                 # A one-to-one relationship, so just return the single related | ||||||
|  |                 # object | ||||||
|  |                 return [attr] | ||||||
|  |         else: | ||||||
|  |             return [None for _ in range(self.field.rel.num_in_admin)] | ||||||
|  |  | ||||||
|     def editable_fields(self): |     def editable_fields(self): | ||||||
|         "Get the fields in this class that should be edited inline." |         "Get the fields in this class that should be edited inline." | ||||||
|         return [f for f in self.opts.fields + self.opts.many_to_many if f.editable and f != self.field] |         return [f for f in self.opts.fields + self.opts.many_to_many if f.editable and f != self.field] | ||||||
| @@ -62,6 +91,30 @@ class RelatedObject(object): | |||||||
|         over[self.field.name] = False |         over[self.field.name] = False | ||||||
|         return self.opts.get_follow(over) |         return self.opts.get_follow(over) | ||||||
|  |  | ||||||
|  |     def get_manipulator_fields(self, opts, manipulator, change, follow): | ||||||
|  |         if self.field.rel.multiple: | ||||||
|  |             if change: | ||||||
|  |                 attr = getattr(manipulator.original_object, self.get_accessor_name()) | ||||||
|  |                 count = attr.count() | ||||||
|  |                 count += self.field.rel.num_extra_on_change | ||||||
|  |                 if self.field.rel.min_num_in_admin: | ||||||
|  |                     count = max(count, self.field.rel.min_num_in_admin) | ||||||
|  |                 if self.field.rel.max_num_in_admin: | ||||||
|  |                     count = min(count, self.field.rel.max_num_in_admin) | ||||||
|  |             else: | ||||||
|  |                 count = self.field.rel.num_in_admin | ||||||
|  |         else: | ||||||
|  |             count = 1 | ||||||
|  |  | ||||||
|  |         fields = [] | ||||||
|  |         for i in range(count): | ||||||
|  |             for f in self.opts.fields + self.opts.many_to_many: | ||||||
|  |                 if follow.get(f.name, False): | ||||||
|  |                     prefix = '%s.%d.' % (self.var_name, i) | ||||||
|  |                     fields.extend(f.get_manipulator_fields(self.opts, manipulator, change, | ||||||
|  |                                                            name_prefix=prefix, rel=True)) | ||||||
|  |         return fields | ||||||
|  |  | ||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
|         return "<RelatedObject: %s related to %s>" % (self.name, self.field.name) |         return "<RelatedObject: %s related to %s>" % (self.name, self.field.name) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -131,10 +131,10 @@ class FormWrapper: | |||||||
|     def fill_inline_collections(self): |     def fill_inline_collections(self): | ||||||
|         if not self._inline_collections: |         if not self._inline_collections: | ||||||
|             ic = [] |             ic = [] | ||||||
|             children = self.manipulator.children.items() |             related_objects = self.manipulator.get_related_objects() | ||||||
|             for rel_obj, child_manips  in children: |             for rel_obj in related_objects: | ||||||
|                 data = rel_obj.extract_data(self.data) |                 data = rel_obj.extract_data(self.data) | ||||||
|                 inline_collection = InlineObjectCollection(self.manipulator, rel_obj, child_manips, data, self.error_dict) |                 inline_collection = InlineObjectCollection(self.manipulator, rel_obj, data, self.error_dict) | ||||||
|                 ic.append(inline_collection) |                 ic.append(inline_collection) | ||||||
|             self._inline_collections = ic |             self._inline_collections = ic | ||||||
|  |  | ||||||
| @@ -213,12 +213,11 @@ class FormFieldCollection(FormFieldWrapper): | |||||||
|  |  | ||||||
| class InlineObjectCollection: | class InlineObjectCollection: | ||||||
|     "An object that acts like a sparse list of form field collections." |     "An object that acts like a sparse list of form field collections." | ||||||
|     def __init__(self, parent_manipulator, rel_obj,child_manips, data, errors): |     def __init__(self, parent_manipulator, rel_obj, data, errors): | ||||||
|         self.parent_manipulator = parent_manipulator |         self.parent_manipulator = parent_manipulator | ||||||
|         self.rel_obj = rel_obj |         self.rel_obj = rel_obj | ||||||
|         self.data = data |         self.data = data | ||||||
|         self.errors = errors |         self.errors = errors | ||||||
|         self.child_manips = child_manips |  | ||||||
|         self._collections = None |         self._collections = None | ||||||
|         self.name = rel_obj.name |         self.name = rel_obj.name | ||||||
|  |  | ||||||
| @@ -240,7 +239,7 @@ class InlineObjectCollection: | |||||||
|  |  | ||||||
|     def __iter__(self): |     def __iter__(self): | ||||||
|         self.fill() |         self.fill() | ||||||
|         return self._collections.values().__iter__() |         return iter(self._collections.values()) | ||||||
|  |  | ||||||
|     def items(self): |     def items(self): | ||||||
|         self.fill() |         self.fill() | ||||||
| @@ -250,22 +249,25 @@ class InlineObjectCollection: | |||||||
|         if self._collections: |         if self._collections: | ||||||
|             return |             return | ||||||
|         else: |         else: | ||||||
|             #var_name = self.rel_obj.opts.object_name.lower() |             var_name = self.rel_obj.opts.object_name.lower() | ||||||
|             cols = {} |             collections = {} | ||||||
|             #orig = hasattr(self.parent_manipulator, 'original_object') and self.parent_manipulator.original_object  or None |             orig = None | ||||||
|             #orig_list = self.rel_obj.get_list(orig) |             if hasattr(self.parent_manipulator, 'original_object'): | ||||||
|  |                 orig = self.parent_manipulator.original_object | ||||||
|  |             orig_list = self.rel_obj.get_list(orig) | ||||||
|  |  | ||||||
|             for i, manip in enumerate(self.child_manips) : |             for i, instance in enumerate(orig_list): | ||||||
|                 if manip and not manip.needs_deletion: |                 collection = {'original': instance} | ||||||
|                     collection = {'original': manip.original_object} |                 for f in self.rel_obj.editable_fields(): | ||||||
|                     for field in manip.fields: |                     for field_name in f.get_manipulator_field_names(''): | ||||||
|                         errors = self.errors.get(field.field_name, []) |                         full_field_name = '%s.%d.%s' % (var_name, i, field_name) | ||||||
|  |                         field = self.parent_manipulator[full_field_name] | ||||||
|                         data = field.extract_data(self.data) |                         data = field.extract_data(self.data) | ||||||
|                         last_part = field.field_name[field.field_name.rindex('.') + 1:] |                         errors = self.errors.get(full_field_name, []) | ||||||
|                         collection[last_part] = FormFieldWrapper(field, data, errors) |                         collection[field_name] = FormFieldWrapper(field, data, errors) | ||||||
|  |                 collections[i] = FormFieldCollection(collection) | ||||||
|  |             self._collections = collections | ||||||
|  |  | ||||||
|                     cols[i] = FormFieldCollection(collection) |  | ||||||
|             self._collections = cols |  | ||||||
|  |  | ||||||
| class FormField: | class FormField: | ||||||
|     """Abstract class representing a form field. |     """Abstract class representing a form field. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user