mirror of
https://github.com/django/django.git
synced 2025-07-04 17:59:13 +00:00
newforms-admin: Fixed #5488. inlines with multiple ForeignKeys to the same parent don't work. Thanks jdetaeye. Also, some whitespace cleanup. Sorry for the mess.
git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@6301 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
b28be9b04d
commit
f68769e1c6
@ -36,7 +36,7 @@ def save_instance(form, instance, fields=None, fail_message='saved', commit=True
|
|||||||
continue
|
continue
|
||||||
if fields and f.name not in fields:
|
if fields and f.name not in fields:
|
||||||
continue
|
continue
|
||||||
f.save_form_data(instance, cleaned_data[f.name])
|
f.save_form_data(instance, cleaned_data[f.name])
|
||||||
# Wrap up the saving of m2m data as a function
|
# Wrap up the saving of m2m data as a function
|
||||||
def save_m2m():
|
def save_m2m():
|
||||||
opts = instance.__class__._meta
|
opts = instance.__class__._meta
|
||||||
@ -51,7 +51,7 @@ def save_instance(form, instance, fields=None, fail_message='saved', commit=True
|
|||||||
instance.save()
|
instance.save()
|
||||||
save_m2m()
|
save_m2m()
|
||||||
else:
|
else:
|
||||||
# We're not committing. Add a method to the form to allow deferred
|
# We're not committing. Add a method to the form to allow deferred
|
||||||
# saving of m2m data
|
# saving of m2m data
|
||||||
form.save_m2m = save_m2m
|
form.save_m2m = save_m2m
|
||||||
return instance
|
return instance
|
||||||
@ -61,7 +61,7 @@ def make_model_save(model, fields, fail_message):
|
|||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
return save_instance(self, model(), fields, fail_message, commit)
|
return save_instance(self, model(), fields, fail_message, commit)
|
||||||
return save
|
return save
|
||||||
|
|
||||||
def make_instance_save(instance, fields, fail_message):
|
def make_instance_save(instance, fields, fail_message):
|
||||||
"Returns the save() method for a Form."
|
"Returns the save() method for a Form."
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
@ -89,7 +89,7 @@ def form_for_model(model, form=BaseForm, fields=None, formfield_callback=lambda
|
|||||||
if formfield:
|
if formfield:
|
||||||
field_list.append((f.name, formfield))
|
field_list.append((f.name, formfield))
|
||||||
base_fields = SortedDictFromList(field_list)
|
base_fields = SortedDictFromList(field_list)
|
||||||
return type(opts.object_name + 'Form', (form,),
|
return type(opts.object_name + 'Form', (form,),
|
||||||
{'base_fields': base_fields, '_model': model, 'save': make_model_save(model, fields, 'created')})
|
{'base_fields': base_fields, '_model': model, 'save': make_model_save(model, fields, 'created')})
|
||||||
|
|
||||||
def form_for_instance(instance, form=BaseForm, fields=None, formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)):
|
def form_for_instance(instance, form=BaseForm, fields=None, formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)):
|
||||||
@ -211,9 +211,9 @@ class ModelMultipleChoiceField(ModelChoiceField):
|
|||||||
|
|
||||||
def initial_data(instance, fields=None):
|
def initial_data(instance, fields=None):
|
||||||
"""
|
"""
|
||||||
Return a dictionary from data in ``instance`` that is suitable for
|
Return a dictionary from data in ``instance`` that is suitable for
|
||||||
use as a ``Form`` constructor's ``initial`` argument.
|
use as a ``Form`` constructor's ``initial`` argument.
|
||||||
|
|
||||||
Provide ``fields`` to specify the names of specific fields to return.
|
Provide ``fields`` to specify the names of specific fields to return.
|
||||||
All field values in the instance will be returned if ``fields`` is not
|
All field values in the instance will be returned if ``fields`` is not
|
||||||
provided.
|
provided.
|
||||||
@ -234,7 +234,7 @@ class BaseModelFormSet(BaseFormSet):
|
|||||||
A ``FormSet`` attatched to a particular model or sequence of model instances.
|
A ``FormSet`` attatched to a particular model or sequence of model instances.
|
||||||
"""
|
"""
|
||||||
model = None
|
model = None
|
||||||
|
|
||||||
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, instances=None):
|
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, instances=None):
|
||||||
self.instances = instances
|
self.instances = instances
|
||||||
kwargs = {'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix}
|
kwargs = {'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix}
|
||||||
@ -308,7 +308,7 @@ class InlineFormset(BaseModelFormSet):
|
|||||||
def inline_formset(parent_model, model, fk_name=None, fields=None, extra=3, orderable=False, deletable=True, formfield_callback=lambda f: f.formfield()):
|
def inline_formset(parent_model, model, fk_name=None, fields=None, extra=3, orderable=False, deletable=True, formfield_callback=lambda f: f.formfield()):
|
||||||
"""
|
"""
|
||||||
Returns an ``InlineFormset`` for the given kwargs.
|
Returns an ``InlineFormset`` for the given kwargs.
|
||||||
|
|
||||||
You must provide ``fk_name`` if ``model`` has more than one ``ForeignKey``
|
You must provide ``fk_name`` if ``model`` has more than one ``ForeignKey``
|
||||||
to ``parent_model``.
|
to ``parent_model``.
|
||||||
"""
|
"""
|
||||||
@ -323,10 +323,18 @@ def inline_formset(parent_model, model, fk_name=None, fields=None, extra=3, orde
|
|||||||
raise Exception("%s has no ForeignKey to %s" % (model, parent_model))
|
raise Exception("%s has no ForeignKey to %s" % (model, parent_model))
|
||||||
else:
|
else:
|
||||||
raise Exception("%s has more than 1 ForeignKey to %s" % (model, parent_model))
|
raise Exception("%s has more than 1 ForeignKey to %s" % (model, parent_model))
|
||||||
|
else:
|
||||||
|
fks_to_parent = [f for f in opts.fields if f.name == fk_name]
|
||||||
|
if len(fks_to_parent) == 1:
|
||||||
|
fk = fks_to_parent[0]
|
||||||
|
if not isinstance(fk, ForeignKey) or fk.rel.to != parent_model:
|
||||||
|
raise Exception("fk_name '%s' is not a ForeignKey to %s" % (fk_name, parent_model))
|
||||||
|
elif len(fks_to_parent) == 0:
|
||||||
|
raise Exception("%s has no field named '%s'" % (model, fk_name))
|
||||||
# let the formset handle object deletion by default
|
# let the formset handle object deletion by default
|
||||||
FormSet = formset_for_model(model, formset=InlineFormset, fields=fields,
|
FormSet = formset_for_model(model, formset=InlineFormset, fields=fields,
|
||||||
formfield_callback=formfield_callback,
|
formfield_callback=formfield_callback,
|
||||||
extra=extra, orderable=orderable,
|
extra=extra, orderable=orderable,
|
||||||
deletable=deletable)
|
deletable=deletable)
|
||||||
# HACK: remove the ForeignKey to the parent from every form
|
# HACK: remove the ForeignKey to the parent from every form
|
||||||
# This should be done a line above before we pass 'fields' to formset_for_model
|
# This should be done a line above before we pass 'fields' to formset_for_model
|
||||||
|
0
tests/regressiontests/inline_formsets/__init__.py
Normal file
0
tests/regressiontests/inline_formsets/__init__.py
Normal file
55
tests/regressiontests/inline_formsets/models.py
Normal file
55
tests/regressiontests/inline_formsets/models.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
class School(models.Model):
|
||||||
|
name = models.CharField(max_length=100)
|
||||||
|
|
||||||
|
class Parent(models.Model):
|
||||||
|
name = models.CharField(max_length=100)
|
||||||
|
|
||||||
|
class Child(models.Model):
|
||||||
|
mother = models.ForeignKey(Parent, related_name='mothers_children')
|
||||||
|
father = models.ForeignKey(Parent, related_name='fathers_children')
|
||||||
|
school = models.ForeignKey(School)
|
||||||
|
name = models.CharField(max_length=100)
|
||||||
|
|
||||||
|
__test__ = {'API_TESTS': """
|
||||||
|
|
||||||
|
>>> from django.newforms.models import inline_formset
|
||||||
|
|
||||||
|
|
||||||
|
Child has two ForeignKeys to Parent, so if we don't specify which one to use
|
||||||
|
for the inline formset, we should get an exception.
|
||||||
|
|
||||||
|
>>> ifs = inline_formset(Parent, Child)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
Exception: <class 'regressiontests.inline_formsets.models.Child'> has more than 1 ForeignKey to <class 'regressiontests.inline_formsets.models.Parent'>
|
||||||
|
|
||||||
|
|
||||||
|
These two should both work without a problem.
|
||||||
|
|
||||||
|
>>> ifs = inline_formset(Parent, Child, fk_name='mother')
|
||||||
|
>>> ifs = inline_formset(Parent, Child, fk_name='father')
|
||||||
|
|
||||||
|
|
||||||
|
If we specify fk_name, but it isn't a ForeignKey from the child model to the
|
||||||
|
parent model, we should get an exception.
|
||||||
|
|
||||||
|
>>> ifs = inline_formset(Parent, Child, fk_name='school')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
Exception: fk_name 'school' is not a ForeignKey to <class 'regressiontests.inline_formsets.models.Parent'>
|
||||||
|
|
||||||
|
|
||||||
|
If the field specified in fk_name is not a ForeignKey, we should get an
|
||||||
|
exception.
|
||||||
|
|
||||||
|
>>> ifs = inline_formset(Parent, Child, fk_name='test')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
Exception: <class 'regressiontests.inline_formsets.models.Child'> has no field named 'test'
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user