mirror of
https://github.com/django/django.git
synced 2025-11-07 07:15:35 +00:00
Fixed #12881: Corrected handling of inherited unique constraints. Thanks for report fgaudin.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@12797 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
32
tests/modeltests/model_forms/mforms.py
Executable file
32
tests/modeltests/model_forms/mforms.py
Executable file
@@ -0,0 +1,32 @@
|
||||
from django.forms import ModelForm
|
||||
|
||||
from models import Product, Price, Book, DerivedBook, ExplicitPK, Post, DerivedPost
|
||||
|
||||
class ProductForm(ModelForm):
|
||||
class Meta:
|
||||
model = Product
|
||||
|
||||
class PriceForm(ModelForm):
|
||||
class Meta:
|
||||
model = Price
|
||||
|
||||
class BookForm(ModelForm):
|
||||
class Meta:
|
||||
model = Book
|
||||
|
||||
class DerivedBookForm(ModelForm):
|
||||
class Meta:
|
||||
model = DerivedBook
|
||||
|
||||
class ExplicitPKForm(ModelForm):
|
||||
class Meta:
|
||||
model = ExplicitPK
|
||||
fields = ('key', 'desc',)
|
||||
|
||||
class PostForm(ModelForm):
|
||||
class Meta:
|
||||
model = Post
|
||||
|
||||
class DerivedPostForm(ModelForm):
|
||||
class Meta:
|
||||
model = DerivedPost
|
||||
@@ -101,7 +101,7 @@ try:
|
||||
from PIL import Image, _imaging
|
||||
except ImportError:
|
||||
import Image, _imaging
|
||||
|
||||
|
||||
test_images = True
|
||||
|
||||
class ImageFile(models.Model):
|
||||
@@ -181,6 +181,18 @@ class Book(models.Model):
|
||||
class Meta:
|
||||
unique_together = ('title', 'author')
|
||||
|
||||
class BookXtra(models.Model):
|
||||
isbn = models.CharField(max_length=16, unique=True)
|
||||
suffix1 = models.IntegerField(blank=True, default=0)
|
||||
suffix2 = models.IntegerField(blank=True, default=0)
|
||||
|
||||
class Meta:
|
||||
unique_together = (('suffix1', 'suffix2'))
|
||||
abstract = True
|
||||
|
||||
class DerivedBook(Book, BookXtra):
|
||||
pass
|
||||
|
||||
class ExplicitPK(models.Model):
|
||||
key = models.CharField(max_length=20, primary_key=True)
|
||||
desc = models.CharField(max_length=20, blank=True, unique=True)
|
||||
@@ -199,6 +211,9 @@ class Post(models.Model):
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class DerivedPost(Post):
|
||||
pass
|
||||
|
||||
class BigInt(models.Model):
|
||||
biggie = models.BigIntegerField()
|
||||
|
||||
@@ -1424,41 +1439,6 @@ True
|
||||
>>> f.cleaned_data
|
||||
{'field': u'1'}
|
||||
|
||||
# unique/unique_together validation
|
||||
|
||||
>>> class ProductForm(ModelForm):
|
||||
... class Meta:
|
||||
... model = Product
|
||||
>>> form = ProductForm({'slug': 'teddy-bear-blue'})
|
||||
>>> form.is_valid()
|
||||
True
|
||||
>>> obj = form.save()
|
||||
>>> obj
|
||||
<Product: teddy-bear-blue>
|
||||
>>> form = ProductForm({'slug': 'teddy-bear-blue'})
|
||||
>>> form.is_valid()
|
||||
False
|
||||
>>> form._errors
|
||||
{'slug': [u'Product with this Slug already exists.']}
|
||||
>>> form = ProductForm({'slug': 'teddy-bear-blue'}, instance=obj)
|
||||
>>> form.is_valid()
|
||||
True
|
||||
|
||||
# ModelForm test of unique_together constraint
|
||||
>>> class PriceForm(ModelForm):
|
||||
... class Meta:
|
||||
... model = Price
|
||||
>>> form = PriceForm({'price': '6.00', 'quantity': '1'})
|
||||
>>> form.is_valid()
|
||||
True
|
||||
>>> form.save()
|
||||
<Price: 1 for 6.00>
|
||||
>>> form = PriceForm({'price': '6.00', 'quantity': '1'})
|
||||
>>> form.is_valid()
|
||||
False
|
||||
>>> form._errors
|
||||
{'__all__': [u'Price with this Price and Quantity already exists.']}
|
||||
|
||||
This Price instance generated by this form is not valid because the quantity
|
||||
field is required, but the form is valid because the field is excluded from
|
||||
the form. This is for backwards compatibility.
|
||||
@@ -1495,51 +1475,6 @@ True
|
||||
>>> form.instance.pk is None
|
||||
True
|
||||
|
||||
# Unique & unique together with null values
|
||||
>>> class BookForm(ModelForm):
|
||||
... class Meta:
|
||||
... model = Book
|
||||
>>> w = Writer.objects.get(name='Mike Royko')
|
||||
>>> form = BookForm({'title': 'I May Be Wrong But I Doubt It', 'author' : w.pk})
|
||||
>>> form.is_valid()
|
||||
True
|
||||
>>> form.save()
|
||||
<Book: Book object>
|
||||
>>> form = BookForm({'title': 'I May Be Wrong But I Doubt It', 'author' : w.pk})
|
||||
>>> form.is_valid()
|
||||
False
|
||||
>>> form._errors
|
||||
{'__all__': [u'Book with this Title and Author already exists.']}
|
||||
>>> form = BookForm({'title': 'I May Be Wrong But I Doubt It'})
|
||||
>>> form.is_valid()
|
||||
True
|
||||
>>> form.save()
|
||||
<Book: Book object>
|
||||
>>> form = BookForm({'title': 'I May Be Wrong But I Doubt It'})
|
||||
>>> form.is_valid()
|
||||
True
|
||||
|
||||
# Test for primary_key being in the form and failing validation.
|
||||
>>> class ExplicitPKForm(ModelForm):
|
||||
... class Meta:
|
||||
... model = ExplicitPK
|
||||
... fields = ('key', 'desc',)
|
||||
>>> form = ExplicitPKForm({'key': u'', 'desc': u'' })
|
||||
>>> form.is_valid()
|
||||
False
|
||||
|
||||
# Ensure keys and blank character strings are tested for uniqueness.
|
||||
>>> form = ExplicitPKForm({'key': u'key1', 'desc': u''})
|
||||
>>> form.is_valid()
|
||||
True
|
||||
>>> form.save()
|
||||
<ExplicitPK: key1>
|
||||
>>> form = ExplicitPKForm({'key': u'key1', 'desc': u''})
|
||||
>>> form.is_valid()
|
||||
False
|
||||
>>> sorted(form.errors.items())
|
||||
[('__all__', [u'Explicit pk with this Key and Desc already exists.']), ('desc', [u'Explicit pk with this Desc already exists.']), ('key', [u'Explicit pk with this Key already exists.'])]
|
||||
|
||||
# Choices on CharField and IntegerField
|
||||
>>> class ArticleForm(ModelForm):
|
||||
... class Meta:
|
||||
@@ -1605,38 +1540,6 @@ ValidationError: [u'Select a valid choice. z is not one of the available choices
|
||||
<tr><th><label for="id_description">Description:</label></th><td><input type="text" name="description" id="id_description" /></td></tr>
|
||||
<tr><th><label for="id_url">The URL:</label></th><td><input id="id_url" type="text" name="url" maxlength="40" /></td></tr>
|
||||
|
||||
### Validation on unique_for_date
|
||||
|
||||
>>> p = Post.objects.create(title="Django 1.0 is released", slug="Django 1.0", subtitle="Finally", posted=datetime.date(2008, 9, 3))
|
||||
>>> class PostForm(ModelForm):
|
||||
... class Meta:
|
||||
... model = Post
|
||||
|
||||
>>> f = PostForm({'title': "Django 1.0 is released", 'posted': '2008-09-03'})
|
||||
>>> f.is_valid()
|
||||
False
|
||||
>>> f.errors
|
||||
{'title': [u'Title must be unique for Posted date.']}
|
||||
>>> f = PostForm({'title': "Work on Django 1.1 begins", 'posted': '2008-09-03'})
|
||||
>>> f.is_valid()
|
||||
True
|
||||
>>> f = PostForm({'title': "Django 1.0 is released", 'posted': '2008-09-04'})
|
||||
>>> f.is_valid()
|
||||
True
|
||||
>>> f = PostForm({'slug': "Django 1.0", 'posted': '2008-01-01'})
|
||||
>>> f.is_valid()
|
||||
False
|
||||
>>> f.errors
|
||||
{'slug': [u'Slug must be unique for Posted year.']}
|
||||
>>> f = PostForm({'subtitle': "Finally", 'posted': '2008-09-30'})
|
||||
>>> f.is_valid()
|
||||
False
|
||||
>>> f.errors
|
||||
{'subtitle': [u'Subtitle must be unique for Posted month.']}
|
||||
>>> f = PostForm({'subtitle': "Finally", "title": "Django 1.0 is released", "slug": "Django 1.0", 'posted': '2008-09-03'}, instance=p)
|
||||
>>> f.is_valid()
|
||||
True
|
||||
|
||||
# Clean up
|
||||
>>> import shutil
|
||||
>>> shutil.rmtree(temp_storage_dir)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import datetime
|
||||
from django.test import TestCase
|
||||
from django import forms
|
||||
from models import Category
|
||||
from models import Category, Writer, Book, DerivedBook, Post
|
||||
from mforms import ProductForm, PriceForm, BookForm, DerivedBookForm, ExplicitPKForm, PostForm, DerivedPostForm
|
||||
|
||||
|
||||
class IncompleteCategoryFormWithFields(forms.ModelForm):
|
||||
@@ -35,3 +37,140 @@ class ValidationTest(TestCase):
|
||||
form = IncompleteCategoryFormWithExclude(data={'name': 'some name', 'slug': 'some-slug'})
|
||||
assert form.is_valid()
|
||||
|
||||
# unique/unique_together validation
|
||||
class UniqueTest(TestCase):
|
||||
def setUp(self):
|
||||
self.writer = Writer.objects.create(name='Mike Royko')
|
||||
|
||||
def test_simple_unique(self):
|
||||
form = ProductForm({'slug': 'teddy-bear-blue'})
|
||||
self.assertTrue(form.is_valid())
|
||||
obj = form.save()
|
||||
form = ProductForm({'slug': 'teddy-bear-blue'})
|
||||
self.assertEqual(len(form.errors), 1)
|
||||
self.assertEqual(form.errors['slug'], [u'Product with this Slug already exists.'])
|
||||
form = ProductForm({'slug': 'teddy-bear-blue'}, instance=obj)
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
def test_unique_together(self):
|
||||
"""ModelForm test of unique_together constraint"""
|
||||
form = PriceForm({'price': '6.00', 'quantity': '1'})
|
||||
self.assertTrue(form.is_valid())
|
||||
form.save()
|
||||
form = PriceForm({'price': '6.00', 'quantity': '1'})
|
||||
self.assertFalse(form.is_valid())
|
||||
self.assertEqual(len(form.errors), 1)
|
||||
self.assertEqual(form.errors['__all__'], [u'Price with this Price and Quantity already exists.'])
|
||||
|
||||
def test_unique_null(self):
|
||||
title = 'I May Be Wrong But I Doubt It'
|
||||
form = BookForm({'title': title, 'author': self.writer.pk})
|
||||
self.assertTrue(form.is_valid())
|
||||
form.save()
|
||||
form = BookForm({'title': title, 'author': self.writer.pk})
|
||||
self.assertFalse(form.is_valid())
|
||||
self.assertEqual(len(form.errors), 1)
|
||||
self.assertEqual(form.errors['__all__'], [u'Book with this Title and Author already exists.'])
|
||||
form = BookForm({'title': title})
|
||||
self.assertTrue(form.is_valid())
|
||||
form.save()
|
||||
form = BookForm({'title': title})
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
def test_inherited_unique(self):
|
||||
title = 'Boss'
|
||||
Book.objects.create(title=title, author=self.writer, special_id=1)
|
||||
form = DerivedBookForm({'title': 'Other', 'author': self.writer.pk, 'special_id': u'1', 'isbn': '12345'})
|
||||
self.assertFalse(form.is_valid())
|
||||
self.assertEqual(len(form.errors), 1)
|
||||
self.assertEqual(form.errors['special_id'], [u'Book with this Special id already exists.'])
|
||||
|
||||
def test_inherited_unique_together(self):
|
||||
title = 'Boss'
|
||||
form = BookForm({'title': title, 'author': self.writer.pk})
|
||||
self.assertTrue(form.is_valid())
|
||||
form.save()
|
||||
form = DerivedBookForm({'title': title, 'author': self.writer.pk, 'isbn': '12345'})
|
||||
self.assertFalse(form.is_valid())
|
||||
self.assertEqual(len(form.errors), 1)
|
||||
self.assertEqual(form.errors['__all__'], [u'Book with this Title and Author already exists.'])
|
||||
|
||||
def test_abstract_inherited_unique(self):
|
||||
title = 'Boss'
|
||||
isbn = '12345'
|
||||
dbook = DerivedBook.objects.create(title=title, author=self.writer, isbn=isbn)
|
||||
form = DerivedBookForm({'title': 'Other', 'author': self.writer.pk, 'isbn': isbn})
|
||||
self.assertFalse(form.is_valid())
|
||||
self.assertEqual(len(form.errors), 1)
|
||||
self.assertEqual(form.errors['isbn'], [u'Derived book with this Isbn already exists.'])
|
||||
|
||||
def test_abstract_inherited_unique_together(self):
|
||||
title = 'Boss'
|
||||
isbn = '12345'
|
||||
dbook = DerivedBook.objects.create(title=title, author=self.writer, isbn=isbn)
|
||||
form = DerivedBookForm({'title': 'Other', 'author': self.writer.pk, 'isbn': '9876', 'suffix1': u'0', 'suffix2': u'0'})
|
||||
self.assertFalse(form.is_valid())
|
||||
self.assertEqual(len(form.errors), 1)
|
||||
self.assertEqual(form.errors['__all__'], [u'Derived book with this Suffix1 and Suffix2 already exists.'])
|
||||
|
||||
def test_explicitpk_unspecified(self):
|
||||
"""Test for primary_key being in the form and failing validation."""
|
||||
form = ExplicitPKForm({'key': u'', 'desc': u'' })
|
||||
self.assertFalse(form.is_valid())
|
||||
|
||||
def test_explicitpk_unique(self):
|
||||
"""Ensure keys and blank character strings are tested for uniqueness."""
|
||||
form = ExplicitPKForm({'key': u'key1', 'desc': u''})
|
||||
self.assertTrue(form.is_valid())
|
||||
form.save()
|
||||
form = ExplicitPKForm({'key': u'key1', 'desc': u''})
|
||||
self.assertFalse(form.is_valid())
|
||||
self.assertEqual(len(form.errors), 3)
|
||||
self.assertEqual(form.errors['__all__'], [u'Explicit pk with this Key and Desc already exists.'])
|
||||
self.assertEqual(form.errors['desc'], [u'Explicit pk with this Desc already exists.'])
|
||||
self.assertEqual(form.errors['key'], [u'Explicit pk with this Key already exists.'])
|
||||
|
||||
def test_unique_for_date(self):
|
||||
p = Post.objects.create(title="Django 1.0 is released",
|
||||
slug="Django 1.0", subtitle="Finally", posted=datetime.date(2008, 9, 3))
|
||||
form = PostForm({'title': "Django 1.0 is released", 'posted': '2008-09-03'})
|
||||
self.assertFalse(form.is_valid())
|
||||
self.assertEqual(len(form.errors), 1)
|
||||
self.assertEqual(form.errors['title'], [u'Title must be unique for Posted date.'])
|
||||
form = PostForm({'title': "Work on Django 1.1 begins", 'posted': '2008-09-03'})
|
||||
self.assertTrue(form.is_valid())
|
||||
form = PostForm({'title': "Django 1.0 is released", 'posted': '2008-09-04'})
|
||||
self.assertTrue(form.is_valid())
|
||||
form = PostForm({'slug': "Django 1.0", 'posted': '2008-01-01'})
|
||||
self.assertFalse(form.is_valid())
|
||||
self.assertEqual(len(form.errors), 1)
|
||||
self.assertEqual(form.errors['slug'], [u'Slug must be unique for Posted year.'])
|
||||
form = PostForm({'subtitle': "Finally", 'posted': '2008-09-30'})
|
||||
self.assertFalse(form.is_valid())
|
||||
self.assertEqual(form.errors['subtitle'], [u'Subtitle must be unique for Posted month.'])
|
||||
form = PostForm({'subtitle': "Finally", "title": "Django 1.0 is released",
|
||||
"slug": "Django 1.0", 'posted': '2008-09-03'}, instance=p)
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
def test_inherited_unique_for_date(self):
|
||||
p = Post.objects.create(title="Django 1.0 is released",
|
||||
slug="Django 1.0", subtitle="Finally", posted=datetime.date(2008, 9, 3))
|
||||
form = DerivedPostForm({'title': "Django 1.0 is released", 'posted': '2008-09-03'})
|
||||
self.assertFalse(form.is_valid())
|
||||
self.assertEqual(len(form.errors), 1)
|
||||
self.assertEqual(form.errors['title'], [u'Title must be unique for Posted date.'])
|
||||
form = DerivedPostForm({'title': "Work on Django 1.1 begins", 'posted': '2008-09-03'})
|
||||
self.assertTrue(form.is_valid())
|
||||
form = DerivedPostForm({'title': "Django 1.0 is released", 'posted': '2008-09-04'})
|
||||
self.assertTrue(form.is_valid())
|
||||
form = DerivedPostForm({'slug': "Django 1.0", 'posted': '2008-01-01'})
|
||||
self.assertFalse(form.is_valid())
|
||||
self.assertEqual(len(form.errors), 1)
|
||||
self.assertEqual(form.errors['slug'], [u'Slug must be unique for Posted year.'])
|
||||
form = DerivedPostForm({'subtitle': "Finally", 'posted': '2008-09-30'})
|
||||
self.assertFalse(form.is_valid())
|
||||
self.assertEqual(form.errors['subtitle'], [u'Subtitle must be unique for Posted month.'])
|
||||
form = DerivedPostForm({'subtitle': "Finally", "title": "Django 1.0 is released",
|
||||
"slug": "Django 1.0", 'posted': '2008-09-03'}, instance=p)
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
|
||||
@@ -9,26 +9,34 @@ class GetUniqueCheckTests(unittest.TestCase):
|
||||
def test_unique_fields_get_collected(self):
|
||||
m = UniqueFieldsModel()
|
||||
self.assertEqual(
|
||||
([('id',), ('unique_charfield',), ('unique_integerfield',)], []),
|
||||
([(UniqueFieldsModel, ('id',)),
|
||||
(UniqueFieldsModel, ('unique_charfield',)),
|
||||
(UniqueFieldsModel, ('unique_integerfield',))],
|
||||
[]),
|
||||
m._get_unique_checks()
|
||||
)
|
||||
|
||||
def test_unique_together_gets_picked_up_and_converted_to_tuple(self):
|
||||
m = UniqueTogetherModel()
|
||||
self.assertEqual(
|
||||
([('ifield', 'cfield',),('ifield', 'efield'), ('id',), ], []),
|
||||
([(UniqueTogetherModel, ('ifield', 'cfield',)),
|
||||
(UniqueTogetherModel, ('ifield', 'efield')),
|
||||
(UniqueTogetherModel, ('id',)), ],
|
||||
[]),
|
||||
m._get_unique_checks()
|
||||
)
|
||||
|
||||
def test_primary_key_is_considered_unique(self):
|
||||
m = CustomPKModel()
|
||||
self.assertEqual(([('my_pk_field',)], []), m._get_unique_checks())
|
||||
self.assertEqual(([(CustomPKModel, ('my_pk_field',))], []), m._get_unique_checks())
|
||||
|
||||
def test_unique_for_date_gets_picked_up(self):
|
||||
m = UniqueForDateModel()
|
||||
self.assertEqual((
|
||||
[('id',)],
|
||||
[('date', 'count', 'start_date'), ('year', 'count', 'end_date'), ('month', 'order', 'end_date')]
|
||||
[(UniqueForDateModel, ('id',))],
|
||||
[(UniqueForDateModel, 'date', 'count', 'start_date'),
|
||||
(UniqueForDateModel, 'year', 'count', 'end_date'),
|
||||
(UniqueForDateModel, 'month', 'order', 'end_date')]
|
||||
), m._get_unique_checks()
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user