I'm reporting this to the developers list as I feel this shows a shortfall in (to me) expected behavior. I'm not sure this is exactly a bug or simply a use case the unique validation wasn't designed for.
Basically, sometimes I want to create model formsets that use a limited number of model fields. These model fields may have a unique constraint using unique_together. The other field (or fields) of unique together may not be included in the formset. Upon validating the form, unique_together fields are only checked if all fields are contained in the form. This means, my unique fields will not be validated automatically. To achieve the validation I usually have to copy parts of Django form validation, missing out on DRY. I think one solution would be for model formsets to have a "static" or "constant" fields argument. This could be a single value per field that all forms in the formset would share for a particular set of fields. These fields would not be a part of the rendered form, but could be used for validating the forms and creating new models instances. Thoughts? An example where I might do this: suppose I have a "container" model. This model has many "item" models created through a FK relationship. Perhaps a field is unique together with the container. This example could apply to any container/item relationship. I might create a formset for all items of just one container for a bulk (unique) rename. I have created a simple small example that illustrates my point: models.py ---- class Container(models.Model): pass class Item(models.Model): container = models.ForeignKey(Container) name = models.CharField(max_length=100) class Meta: unique_together = ('container', 'name') ItemFormSet = modelformset_factory(model=Item, fields=['name']) ---- tests.py ---- class ItemFormSetTestCase(TestCase): def test_unique_item_name(self): container = Container() container.save() item1 = Item(container=container, name='item1') item1.save() item2 = Item(container=container, name='item2') item2.save() data = { 'form-TOTAL_FORMS': 2, 'form-INITIAL_FORMS': 2, 'form-MAX_NUM_FORMS': 2, 'form-0-id': str(item1.pk), 'form-0-name': 'newname', 'form-1-id': str(item2.pk), 'form-1-name': 'newname', } formset = ItemFormSet( data, queryset=Item.objects.filter(container=container)) self.assertFalse(formset.is_valid()) --- This test fails because the uniqueness of name is not actually validated. If I were to go ahead an save this "valid" form, I receive the following error: --- Traceback (most recent call last): File "/home/jon/djtest/djtest/myapp/tests.py", line 27, in test_unique_item_name formset.save() File "/home/jon/djtest/venv/lib/python2.7/site-packages/django/forms/models.py", line 636, in save return self.save_existing_objects(commit) + self.save_new_objects(commit) File "/home/jon/djtest/venv/lib/python2.7/site-packages/django/forms/models.py", line 753, in save_existing_objects saved_instances.append(self.save_existing(form, obj, commit=commit)) File "/home/jon/djtest/venv/lib/python2.7/site-packages/django/forms/models.py", line 623, in save_existing return form.save(commit=commit) File "/home/jon/djtest/venv/lib/python2.7/site-packages/django/forms/models.py", line 457, in save construct=False) File "/home/jon/djtest/venv/lib/python2.7/site-packages/django/forms/models.py", line 103, in save_instance instance.save() File "/home/jon/djtest/venv/lib/python2.7/site-packages/django/db/models/base.py", line 590, in save force_update=force_update, update_fields=update_fields) File "/home/jon/djtest/venv/lib/python2.7/site-packages/django/db/models/base.py", line 618, in save_base updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields) File "/home/jon/djtest/venv/lib/python2.7/site-packages/django/db/models/base.py", line 680, in _save_table forced_update) File "/home/jon/djtest/venv/lib/python2.7/site-packages/django/db/models/base.py", line 724, in _do_update return filtered._update(values) > 0 File "/home/jon/djtest/venv/lib/python2.7/site-packages/django/db/models/query.py", line 598, in _update return query.get_compiler(self.db).execute_sql(CURSOR) File "/home/jon/djtest/venv/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 1003, in execute_sql cursor = super(SQLUpdateCompiler, self).execute_sql(result_type) File "/home/jon/djtest/venv/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 785, in execute_sql cursor.execute(sql, params) File "/home/jon/djtest/venv/lib/python2.7/site-packages/django/db/backends/utils.py", line 65, in execute return self.cursor.execute(sql, params) File "/home/jon/djtest/venv/lib/python2.7/site-packages/django/db/utils.py", line 94, in __exit__ six.reraise(dj_exc_type, dj_exc_value, traceback) File "/home/jon/djtest/venv/lib/python2.7/site-packages/django/db/backends/utils.py", line 65, in execute return self.cursor.execute(sql, params) File "/home/jon/djtest/venv/lib/python2.7/site-packages/django/db/backends/sqlite3/base.py", line 485, in execute return Database.Cursor.execute(self, query, params) IntegrityError: UNIQUE constraint failed: myapp_item.container_id, myapp_item.name --- -- You received this message because you are subscribed to the Google Groups "Django developers" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscr...@googlegroups.com. To post to this group, send email to django-developers@googlegroups.com. Visit this group at http://groups.google.com/group/django-developers. To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/CADhq2b585%2Bzfm2XKkYYP6Ji%2B2A7BMHWRywHQ9nyOHOA53MabnA%40mail.gmail.com. For more options, visit https://groups.google.com/d/optout.