Fixed #30183 -- Added introspection of inline SQLite constraints.

This commit is contained in:
Paveł Tyślacki 2019-02-28 00:47:29 +03:00 committed by Tim Graham
parent 406de977ea
commit 782d85b6df
5 changed files with 332 additions and 51 deletions

View file

@ -58,3 +58,21 @@ class ArticleReporter(models.Model):
class Meta:
managed = False
class Comment(models.Model):
ref = models.UUIDField(unique=True)
article = models.ForeignKey(Article, models.CASCADE, db_index=True)
email = models.EmailField()
pub_date = models.DateTimeField()
up_votes = models.PositiveIntegerField()
body = models.TextField()
class Meta:
constraints = [
models.CheckConstraint(name='up_votes_gte_0_check', check=models.Q(up_votes__gte=0)),
models.UniqueConstraint(fields=['article', 'email', 'pub_date'], name='article_email_pub_date_uniq'),
]
indexes = [
models.Index(fields=['email', 'pub_date'], name='email_pub_date_idx'),
]

View file

@ -5,7 +5,7 @@ from django.db.models import Index
from django.db.utils import DatabaseError
from django.test import TransactionTestCase, skipUnlessDBFeature
from .models import Article, ArticleReporter, City, District, Reporter
from .models import Article, ArticleReporter, City, Comment, District, Reporter
class IntrospectionTests(TransactionTestCase):
@ -211,3 +211,60 @@ class IntrospectionTests(TransactionTestCase):
self.assertEqual(val['orders'], ['ASC'] * len(val['columns']))
indexes_verified += 1
self.assertEqual(indexes_verified, 4)
def test_get_constraints(self):
def assertDetails(details, cols, primary_key=False, unique=False, index=False, check=False, foreign_key=None):
# Different backends have different values for same constraints:
# PRIMARY KEY UNIQUE CONSTRAINT UNIQUE INDEX
# MySQL pk=1 uniq=1 idx=1 pk=0 uniq=1 idx=1 pk=0 uniq=1 idx=1
# PostgreSQL pk=1 uniq=1 idx=0 pk=0 uniq=1 idx=0 pk=0 uniq=1 idx=1
# SQLite pk=1 uniq=0 idx=0 pk=0 uniq=1 idx=0 pk=0 uniq=1 idx=1
if details['primary_key']:
details['unique'] = True
if details['unique']:
details['index'] = False
self.assertEqual(details['columns'], cols)
self.assertEqual(details['primary_key'], primary_key)
self.assertEqual(details['unique'], unique)
self.assertEqual(details['index'], index)
self.assertEqual(details['check'], check)
self.assertEqual(details['foreign_key'], foreign_key)
with connection.cursor() as cursor:
constraints = connection.introspection.get_constraints(cursor, Comment._meta.db_table)
# Test custom constraints
custom_constraints = {
'article_email_pub_date_uniq',
'email_pub_date_idx',
}
if connection.features.supports_column_check_constraints:
custom_constraints.add('up_votes_gte_0_check')
assertDetails(constraints['up_votes_gte_0_check'], ['up_votes'], check=True)
assertDetails(constraints['article_email_pub_date_uniq'], ['article_id', 'email', 'pub_date'], unique=True)
assertDetails(constraints['email_pub_date_idx'], ['email', 'pub_date'], index=True)
# Test field constraints
field_constraints = set()
for name, details in constraints.items():
if name in custom_constraints:
continue
elif details['columns'] == ['up_votes'] and details['check']:
assertDetails(details, ['up_votes'], check=True)
field_constraints.add(name)
elif details['columns'] == ['ref'] and details['unique']:
assertDetails(details, ['ref'], unique=True)
field_constraints.add(name)
elif details['columns'] == ['article_id'] and details['index']:
assertDetails(details, ['article_id'], index=True)
field_constraints.add(name)
elif details['columns'] == ['id'] and details['primary_key']:
assertDetails(details, ['id'], primary_key=True, unique=True)
field_constraints.add(name)
elif details['columns'] == ['article_id'] and details['foreign_key']:
assertDetails(details, ['article_id'], foreign_key=('introspection_article', 'id'))
field_constraints.add(name)
elif details['check']:
# Some databases (e.g. Oracle) include additional check
# constraints.
field_constraints.add(name)
# All constraints are accounted for.
self.assertEqual(constraints.keys() ^ (custom_constraints | field_constraints), set())