mirror of https://github.com/django/django.git
[1.11.x] Fixed #27915 -- Allowed Meta.indexes to be defined in abstract models.
Thanks Markus Holtermann for review.
Backport of 3d19d1428a
from master
This commit is contained in:
parent
5310106ee3
commit
e5880516f9
|
@ -460,6 +460,11 @@ class ModelState(object):
|
||||||
elif name == "index_together":
|
elif name == "index_together":
|
||||||
it = model._meta.original_attrs["index_together"]
|
it = model._meta.original_attrs["index_together"]
|
||||||
options[name] = set(normalize_together(it))
|
options[name] = set(normalize_together(it))
|
||||||
|
elif name == "indexes":
|
||||||
|
indexes = [idx.clone() for idx in model._meta.indexes]
|
||||||
|
for index in indexes:
|
||||||
|
index.set_name_with_model(model)
|
||||||
|
options['indexes'] = indexes
|
||||||
else:
|
else:
|
||||||
options[name] = model._meta.original_attrs[name]
|
options[name] = model._meta.original_attrs[name]
|
||||||
# Force-convert all options to text_type (#23226)
|
# Force-convert all options to text_type (#23226)
|
||||||
|
|
|
@ -303,12 +303,14 @@ class ModelBase(type):
|
||||||
else:
|
else:
|
||||||
new_class.add_to_class(field.name, copy.deepcopy(field))
|
new_class.add_to_class(field.name, copy.deepcopy(field))
|
||||||
|
|
||||||
# Set the name of _meta.indexes. This can't be done in
|
if base_meta and base_meta.abstract and not abstract:
|
||||||
# Options.contribute_to_class() because fields haven't been added to
|
new_class._meta.indexes = [copy.deepcopy(idx) for idx in new_class._meta.indexes]
|
||||||
# the model at that point.
|
# Set the name of _meta.indexes. This can't be done in
|
||||||
for index in new_class._meta.indexes:
|
# Options.contribute_to_class() because fields haven't been added
|
||||||
if not index.name:
|
# to the model at that point.
|
||||||
index.set_name_with_model(new_class)
|
for index in new_class._meta.indexes:
|
||||||
|
if not index.name:
|
||||||
|
index.set_name_with_model(new_class)
|
||||||
|
|
||||||
if abstract:
|
if abstract:
|
||||||
# Abstract base models can't be instantiated and don't appear in
|
# Abstract base models can't be instantiated and don't appear in
|
||||||
|
|
|
@ -77,6 +77,11 @@ class Index(object):
|
||||||
path = path.replace('django.db.models.indexes', 'django.db.models')
|
path = path.replace('django.db.models.indexes', 'django.db.models')
|
||||||
return (path, (), {'fields': self.fields, 'name': self.name})
|
return (path, (), {'fields': self.fields, 'name': self.name})
|
||||||
|
|
||||||
|
def clone(self):
|
||||||
|
"""Create a copy of this Index."""
|
||||||
|
path, args, kwargs = self.deconstruct()
|
||||||
|
return self.__class__(*args, **kwargs)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _hash_generator(*args):
|
def _hash_generator(*args):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1044,6 +1044,33 @@ class ModelStateTests(SimpleTestCase):
|
||||||
state = ModelState.from_model(PrivateFieldModel)
|
state = ModelState.from_model(PrivateFieldModel)
|
||||||
self.assertNotIn('order_with_respect_to', state.options)
|
self.assertNotIn('order_with_respect_to', state.options)
|
||||||
|
|
||||||
|
@isolate_apps('migrations')
|
||||||
|
def test_abstract_model_children_inherit_indexes(self):
|
||||||
|
class Abstract(models.Model):
|
||||||
|
name = models.CharField(max_length=50)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
app_label = 'migrations'
|
||||||
|
abstract = True
|
||||||
|
indexes = [models.indexes.Index(fields=['name'])]
|
||||||
|
|
||||||
|
class Child1(Abstract):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Child2(Abstract):
|
||||||
|
pass
|
||||||
|
|
||||||
|
child1_state = ModelState.from_model(Child1)
|
||||||
|
child2_state = ModelState.from_model(Child2)
|
||||||
|
index_names = [index.name for index in child1_state.options['indexes']]
|
||||||
|
self.assertEqual(index_names, ['migrations__name_b0afd7_idx'])
|
||||||
|
index_names = [index.name for index in child2_state.options['indexes']]
|
||||||
|
self.assertEqual(index_names, ['migrations__name_016466_idx'])
|
||||||
|
|
||||||
|
# Modifying the state doesn't modify the index on the model.
|
||||||
|
child1_state.options['indexes'][0].name = 'bar'
|
||||||
|
self.assertEqual(Child1._meta.indexes[0].name, 'migrations__name_b0afd7_idx')
|
||||||
|
|
||||||
|
|
||||||
class RelatedModelsTests(SimpleTestCase):
|
class RelatedModelsTests(SimpleTestCase):
|
||||||
|
|
||||||
|
|
|
@ -5,3 +5,19 @@ class Book(models.Model):
|
||||||
title = models.CharField(max_length=50)
|
title = models.CharField(max_length=50)
|
||||||
author = models.CharField(max_length=50)
|
author = models.CharField(max_length=50)
|
||||||
pages = models.IntegerField(db_column='page_count')
|
pages = models.IntegerField(db_column='page_count')
|
||||||
|
|
||||||
|
|
||||||
|
class AbstractModel(models.Model):
|
||||||
|
name = models.CharField(max_length=50)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
indexes = [models.indexes.Index(fields=['name'])]
|
||||||
|
|
||||||
|
|
||||||
|
class ChildModel1(AbstractModel):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ChildModel2(AbstractModel):
|
||||||
|
pass
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.test import SimpleTestCase
|
from django.test import SimpleTestCase
|
||||||
|
|
||||||
from .models import Book
|
from .models import Book, ChildModel1, ChildModel2
|
||||||
|
|
||||||
|
|
||||||
class IndexesTests(SimpleTestCase):
|
class IndexesTests(SimpleTestCase):
|
||||||
|
@ -76,3 +76,15 @@ class IndexesTests(SimpleTestCase):
|
||||||
self.assertEqual(path, 'django.db.models.Index')
|
self.assertEqual(path, 'django.db.models.Index')
|
||||||
self.assertEqual(args, ())
|
self.assertEqual(args, ())
|
||||||
self.assertEqual(kwargs, {'fields': ['title'], 'name': 'model_index_title_196f42_idx'})
|
self.assertEqual(kwargs, {'fields': ['title'], 'name': 'model_index_title_196f42_idx'})
|
||||||
|
|
||||||
|
def test_clone(self):
|
||||||
|
index = models.Index(fields=['title'])
|
||||||
|
new_index = index.clone()
|
||||||
|
self.assertIsNot(index, new_index)
|
||||||
|
self.assertEqual(index.fields, new_index.fields)
|
||||||
|
|
||||||
|
def test_abstract_children(self):
|
||||||
|
index_names = [index.name for index in ChildModel1._meta.indexes]
|
||||||
|
self.assertEqual(index_names, ['model_index_name_440998_idx'])
|
||||||
|
index_names = [index.name for index in ChildModel2._meta.indexes]
|
||||||
|
self.assertEqual(index_names, ['model_index_name_b6c374_idx'])
|
||||||
|
|
Loading…
Reference in New Issue