Kaydet (Commit) 0ea15f56 authored tarafından Brian Rosner's avatar Brian Rosner

Fixed #8882 -- When a foreign key is among the unique_together fields in an…

Fixed #8882 -- When a foreign key is among the unique_together fields in an inline formset properly handle it.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@9297 bcc190cf-cafb-0310-a4f2-bffc1f526a37
üst fe54f06a
......@@ -109,6 +109,8 @@ class InlineAdminFormSet(object):
def fields(self):
for field_name in flatten_fieldsets(self.fieldsets):
if self.formset.fk.name == field_name:
continue
yield self.formset.form.base_fields[field_name]
def _media(self):
......@@ -130,6 +132,10 @@ class InlineAdminForm(AdminForm):
self.show_url = original and hasattr(original, 'get_absolute_url')
super(InlineAdminForm, self).__init__(form, fieldsets, prepopulated_fields)
def __iter__(self):
for name, options in self.fieldsets:
yield InlineFieldset(self.formset, self.form, name, **options)
def field_count(self):
# tabular.html uses this function for colspan value.
num_of_fields = 1 # always has at least one field
......@@ -142,6 +148,9 @@ class InlineAdminForm(AdminForm):
def pk_field(self):
return AdminField(self.form, self.formset._pk_field.name, False)
def fk_field(self):
return AdminField(self.form, self.formset.fk.name, False)
def deletion_field(self):
from django.forms.formsets import DELETION_FIELD_NAME
......@@ -151,6 +160,17 @@ class InlineAdminForm(AdminForm):
from django.forms.formsets import ORDERING_FIELD_NAME
return AdminField(self.form, ORDERING_FIELD_NAME, False)
class InlineFieldset(Fieldset):
def __init__(self, formset, *args, **kwargs):
self.formset = formset
super(InlineFieldset, self).__init__(*args, **kwargs)
def __iter__(self):
for field in self.fields:
if self.formset.fk.name == field:
continue
yield Fieldline(self.form, field)
class AdminErrorList(forms.util.ErrorList):
"""
Stores all errors for the form/formsets in an add/change stage view.
......
......@@ -18,6 +18,7 @@
{% include "admin/includes/fieldset.html" %}
{% endfor %}
{{ inline_admin_form.pk_field.field }}
{{ inline_admin_form.fk_field.field }}
</div>
{% endfor %}
......
......@@ -26,7 +26,7 @@
{% if inline_admin_form.original %} {{ inline_admin_form.original }}{% endif %}
{% if inline_admin_form.show_url %}<a href="../../../r/{{ inline_admin_form.original.content_type_id }}/{{ inline_admin_form.original.id }}/">{% trans "View on site" %}</a>{% endif %}
</p>{% endif %}
{{ inline_admin_form.pk_field.field }}
{{ inline_admin_form.pk_field.field }} {{ inline_admin_form.fk_field.field }}
{% spaceless %}
{% for fieldset in inline_admin_form %}
{% for line in fieldset %}
......
......@@ -3,7 +3,7 @@ Helper functions for creating Form classes from Django models
and database field objects.
"""
from django.utils.encoding import smart_unicode
from django.utils.encoding import smart_unicode, force_unicode
from django.utils.datastructures import SortedDict
from django.utils.text import get_text_list, capfirst
from django.utils.translation import ugettext_lazy as _
......@@ -468,7 +468,7 @@ class BaseInlineFormSet(BaseModelFormSet):
# creating new instances
form.data[form.add_prefix(self._pk_field.name)] = None
return form
def get_queryset(self):
"""
Returns this FormSet's queryset, but restricted to children of
......@@ -485,7 +485,9 @@ class BaseInlineFormSet(BaseModelFormSet):
def add_fields(self, form, index):
super(BaseInlineFormSet, self).add_fields(form, index)
if self._pk_field == self.fk:
form.fields[self._pk_field.name] = IntegerField(required=False, widget=HiddenInput)
form.fields[self._pk_field.name] = InlineForeignKeyField(self.instance, pk_field=True)
else:
form.fields[self.fk.name] = InlineForeignKeyField(self.instance, label=form.fields[self.fk.name].label)
def _get_foreign_key(parent_model, model, fk_name=None):
"""
......@@ -537,11 +539,6 @@ def inlineformset_factory(parent_model, model, form=ModelForm,
# enforce a max_num=1 when the foreign key to the parent model is unique.
if fk.unique:
max_num = 1
if exclude is not None:
exclude = list(exclude)
exclude.append(fk.name)
else:
exclude = [fk.name]
kwargs = {
'form': form,
'formfield_callback': formfield_callback,
......@@ -560,6 +557,41 @@ def inlineformset_factory(parent_model, model, form=ModelForm,
# Fields #####################################################################
class InlineForeignKeyHiddenInput(HiddenInput):
def _has_changed(self, initial, data):
return False
class InlineForeignKeyField(Field):
"""
A basic integer field that deals with validating the given value to a
given parent instance in an inline.
"""
default_error_messages = {
'invalid_choice': _(u'The inline foreign key did not match the parent instance primary key.'),
}
def __init__(self, parent_instance, *args, **kwargs):
self.parent_instance = parent_instance
self.pk_field = kwargs.pop("pk_field", False)
if self.parent_instance is not None:
kwargs["initial"] = self.parent_instance.pk
kwargs["required"] = False
kwargs["widget"] = InlineForeignKeyHiddenInput
super(InlineForeignKeyField, self).__init__(*args, **kwargs)
def clean(self, value):
if value in EMPTY_VALUES:
if self.pk_field:
return None
# if there is no value act as we did before.
return self.parent_instance
# ensure the we compare the values as equal types.
if force_unicode(value) != force_unicode(self.parent_instance.pk):
raise ValidationError(self.error_messages['invalid_choice'])
if self.pk_field:
return self.parent_instance.pk
return self.parent_instance
class ModelChoiceIterator(object):
def __init__(self, field):
self.field = field
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment