diff --git a/django/forms/models.py b/django/forms/models.py
index a14a09f..d2cdcc2 100644
a
|
b
|
from django.utils.datastructures import SortedDict
|
9 | 9 | from django.utils.text import get_text_list, capfirst |
10 | 10 | from django.utils.translation import ugettext_lazy as _, ugettext |
11 | 11 | |
12 | | from django.core.exceptions import ValidationError, NON_FIELD_ERRORS |
| 12 | from django.core.exceptions import ValidationError, NON_FIELD_ERRORS, \ |
| 13 | FieldError |
13 | 14 | from django.core.validators import EMPTY_VALUES |
14 | 15 | from util import ErrorList |
15 | 16 | from forms import BaseForm, get_declared_fields |
… |
… |
class ModelFormMetaclass(type):
|
218 | 219 | # If a model is defined, extract form fields from it. |
219 | 220 | fields = fields_for_model(opts.model, opts.fields, |
220 | 221 | opts.exclude, opts.widgets, formfield_callback) |
| 222 | # make sure opts.fields doesn't specify an invalid field |
| 223 | none_model_fields = [k for k, v in fields.iteritems() if not v] |
| 224 | missing_fields = set(none_model_fields) - \ |
| 225 | set(declared_fields.keys()) |
| 226 | if missing_fields: |
| 227 | message = 'Unknown field(s) (%s) specified for %s' |
| 228 | message = message % (', '.join(missing_fields), |
| 229 | opts.model.__name__) |
| 230 | raise FieldError(message) |
221 | 231 | # Override default model fields with any custom declared ones |
222 | 232 | # (plus, include all the other declared fields). |
223 | 233 | fields.update(declared_fields) |
diff --git a/tests/regressiontests/model_forms_regress/tests.py b/tests/regressiontests/model_forms_regress/tests.py
index 5bee73c..7399a5f 100644
a
|
b
|
from django import forms
|
5 | 5 | from django.forms.models import modelform_factory, ModelChoiceField |
6 | 6 | from django.conf import settings |
7 | 7 | from django.test import TestCase |
| 8 | from django.core.exceptions import FieldError |
8 | 9 | |
9 | 10 | from models import Person, RealPerson, Triple, FilePathModel, Article, \ |
10 | 11 | Publication, CustomFF, Author, Author1, Homepage |
… |
… |
class URLFieldTests(TestCase):
|
250 | 251 | form.is_valid() |
251 | 252 | # self.assertTrue(form.is_valid()) |
252 | 253 | # self.assertEquals(form.cleaned_data['url'], 'http://example.com/test') |
| 254 | |
| 255 | |
| 256 | class InvalidFieldAndFactory(TestCase): |
| 257 | """ Tests for #11905 """ |
| 258 | |
| 259 | def test_extra_field_model_form(self): |
| 260 | try: |
| 261 | class ExtraPersonForm(forms.ModelForm): |
| 262 | """ ModelForm with an extra field """ |
| 263 | |
| 264 | age = forms.IntegerField() |
| 265 | |
| 266 | class Meta: |
| 267 | model = Person |
| 268 | fields = ('name', 'no-field') |
| 269 | except FieldError: |
| 270 | pass |
| 271 | else: |
| 272 | self.fail('Invalid "no-field" field not caught') |
| 273 | |
| 274 | def test_extra_declared_field_model_form(self): |
| 275 | try: |
| 276 | class ExtraPersonForm(forms.ModelForm): |
| 277 | """ ModelForm with an extra field """ |
| 278 | |
| 279 | age = forms.IntegerField() |
| 280 | |
| 281 | class Meta: |
| 282 | model = Person |
| 283 | fields = ('name', 'age') |
| 284 | except FieldError: |
| 285 | self.fail('Declarative field raised FieldError incorrectly') |
| 286 | |
| 287 | def test_extra_field_modelform_factory(self): |
| 288 | self.assertRaises(FieldError, modelform_factory, |
| 289 | Person, fields=['no-field', 'name']) |