diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index dc455dcc8c..b8d05671b1 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -97,6 +97,7 @@ class Field(object): self.help_text = help_text self.db_column = db_column self.db_tablespace = db_tablespace or settings.DEFAULT_INDEX_TABLESPACE + self.auto_created = auto_created # Set db_index to True if the field has a relationship and doesn't explicitly set db_index. self.db_index = db_index diff --git a/django/forms/models.py b/django/forms/models.py index d2e4f574ad..677556d91b 100644 --- a/django/forms/models.py +++ b/django/forms/models.py @@ -96,7 +96,7 @@ def model_to_dict(instance, fields=None, exclude=None): the ``fields`` argument. """ # avoid a circular import - from django.db.models.fields.related import ManyToManyField + from django.db.models.fields.related import ManyToManyField, OneToOneField opts = instance._meta data = {} for f in opts.fields + opts.many_to_many: @@ -115,6 +115,8 @@ def model_to_dict(instance, fields=None, exclude=None): else: # MultipleChoiceWidget needs a list of pks, not object instances. data[f.name] = [obj.pk for obj in f.value_from_object(instance)] + elif isinstance(f, OneToOneField): + data[f.attname] = f.value_from_object(instance) else: data[f.name] = f.value_from_object(instance) return data @@ -317,7 +319,7 @@ class BaseModelFormSet(BaseFormSet): def add_fields(self, form, index): """Add a hidden field for the object's primary key.""" - if self.model._meta.has_auto_field: + if self.model._meta.pk.auto_created: self._pk_field_name = self.model._meta.pk.attname form.fields[self._pk_field_name] = IntegerField(required=False, widget=HiddenInput) super(BaseModelFormSet, self).add_fields(form, index) diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py index da45f23f74..a2c522a1d9 100644 --- a/tests/modeltests/model_forms/models.py +++ b/tests/modeltests/model_forms/models.py @@ -13,6 +13,12 @@ import tempfile from django.db import models from django.core.files.storage import FileSystemStorage +# Python 2.3 doesn't have sorted() +try: + sorted +except NameError: + from django.utils.itercompat import sorted + temp_storage = FileSystemStorage(tempfile.gettempdir()) ARTICLE_STATUS = ( @@ -60,6 +66,9 @@ class ImprovedArticle(models.Model): class ImprovedArticleWithParentLink(models.Model): article = models.OneToOneField(Article, parent_link=True) +class BetterWriter(Writer): + pass + class PhoneNumber(models.Model): phone = models.PhoneNumberField() description = models.CharField(max_length=20) @@ -91,7 +100,7 @@ class ImageFile(models.Model): __test__ = {'API_TESTS': """ >>> from django import forms ->>> from django.forms.models import ModelForm +>>> from django.forms.models import ModelForm, model_to_dict >>> from django.core.files.uploadedfile import SimpleUploadedFile The bare bones, absolutely nothing custom, basic case. @@ -793,6 +802,11 @@ ValidationError: [u'Select a valid choice. 4 is not one of the available choices >>> ImprovedArticleWithParentLinkForm.base_fields.keys() [] +>>> bw = BetterWriter(name=u'Joe Better') +>>> bw.save() +>>> sorted(model_to_dict(bw).keys()) +['id', 'name', 'writer_ptr_id'] + # PhoneNumberField ############################################################ >>> class PhoneNumberForm(ModelForm): diff --git a/tests/modeltests/model_formsets/models.py b/tests/modeltests/model_formsets/models.py index 5b66d1560b..a5738ab1ac 100644 --- a/tests/modeltests/model_formsets/models.py +++ b/tests/modeltests/model_formsets/models.py @@ -14,6 +14,9 @@ class Author(models.Model): def __unicode__(self): return self.name +class BetterAuthor(Author): + write_speed = models.IntegerField() + class Book(models.Model): author = models.ForeignKey(Author) title = models.CharField(max_length=100) @@ -229,6 +232,53 @@ used. >>> [sorted(x.items()) for x in formset.initial] [[('id', 1), ('name', u'Charles Baudelaire')], [('id', 3), ('name', u'Paul Verlaine')], [('id', 2), ('name', u'Walt Whitman')]] +# Model inheritance in model formsets ######################################## + +>>> BetterAuthorFormSet = modelformset_factory(BetterAuthor) +>>> formset = BetterAuthorFormSet() +>>> for form in formset.forms: +... print form.as_p() +
+
+ +>>> data = { +... 'form-TOTAL_FORMS': '1', # the number of forms rendered +... 'form-INITIAL_FORMS': '0', # the number of forms with initial data +... 'form-0-author_ptr_id': '', +... 'form-0-name': 'Ernest Hemingway', +... 'form-0-write_speed': '10', +... } + +>>> formset = BetterAuthorFormSet(data) +>>> formset.is_valid() +True +>>> formset.save() +[
+
+
+
+ +>>> data = { +... 'form-TOTAL_FORMS': '2', # the number of forms rendered +... 'form-INITIAL_FORMS': '1', # the number of forms with initial data +... 'form-0-author_ptr_id': '4', +... 'form-0-name': 'Ernest Hemingway', +... 'form-0-write_speed': '10', +... 'form-1-author_ptr_id': '', +... 'form-1-name': '', +... 'form-1-write_speed': '', +... } + +>>> formset = BetterAuthorFormSet(data) +>>> formset.is_valid() +True +>>> formset.save() +[] # Inline Formsets ############################################################