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":
|
||||
it = model._meta.original_attrs["index_together"]
|
||||
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:
|
||||
options[name] = model._meta.original_attrs[name]
|
||||
# Force-convert all options to text_type (#23226)
|
||||
|
|
|
@ -303,12 +303,14 @@ class ModelBase(type):
|
|||
else:
|
||||
new_class.add_to_class(field.name, copy.deepcopy(field))
|
||||
|
||||
# Set the name of _meta.indexes. This can't be done in
|
||||
# Options.contribute_to_class() because fields haven't been added to
|
||||
# the model at that point.
|
||||
for index in new_class._meta.indexes:
|
||||
if not index.name:
|
||||
index.set_name_with_model(new_class)
|
||||
if base_meta and base_meta.abstract and not abstract:
|
||||
new_class._meta.indexes = [copy.deepcopy(idx) for idx in new_class._meta.indexes]
|
||||
# Set the name of _meta.indexes. This can't be done in
|
||||
# Options.contribute_to_class() because fields haven't been added
|
||||
# to the model at that point.
|
||||
for index in new_class._meta.indexes:
|
||||
if not index.name:
|
||||
index.set_name_with_model(new_class)
|
||||
|
||||
if abstract:
|
||||
# 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')
|
||||
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
|
||||
def _hash_generator(*args):
|
||||
"""
|
||||
|
|
|
@ -1044,6 +1044,33 @@ class ModelStateTests(SimpleTestCase):
|
|||
state = ModelState.from_model(PrivateFieldModel)
|
||||
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):
|
||||
|
||||
|
|
|
@ -5,3 +5,19 @@ class Book(models.Model):
|
|||
title = models.CharField(max_length=50)
|
||||
author = models.CharField(max_length=50)
|
||||
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.test import SimpleTestCase
|
||||
|
||||
from .models import Book
|
||||
from .models import Book, ChildModel1, ChildModel2
|
||||
|
||||
|
||||
class IndexesTests(SimpleTestCase):
|
||||
|
@ -76,3 +76,15 @@ class IndexesTests(SimpleTestCase):
|
|||
self.assertEqual(path, 'django.db.models.Index')
|
||||
self.assertEqual(args, ())
|
||||
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