测试gitnore
This commit is contained in:
@@ -1,40 +1,17 @@
|
||||
from .fields import AddField, AlterField, RemoveField, RenameField
|
||||
from .models import (
|
||||
AddConstraint,
|
||||
AddIndex,
|
||||
AlterIndexTogether,
|
||||
AlterModelManagers,
|
||||
AlterModelOptions,
|
||||
AlterModelTable,
|
||||
AlterOrderWithRespectTo,
|
||||
AlterUniqueTogether,
|
||||
CreateModel,
|
||||
DeleteModel,
|
||||
RemoveConstraint,
|
||||
RemoveIndex,
|
||||
RenameModel,
|
||||
AddConstraint, AddIndex, AlterIndexTogether, AlterModelManagers,
|
||||
AlterModelOptions, AlterModelTable, AlterOrderWithRespectTo,
|
||||
AlterUniqueTogether, CreateModel, DeleteModel, RemoveConstraint,
|
||||
RemoveIndex, RenameModel,
|
||||
)
|
||||
from .special import RunPython, RunSQL, SeparateDatabaseAndState
|
||||
|
||||
__all__ = [
|
||||
"CreateModel",
|
||||
"DeleteModel",
|
||||
"AlterModelTable",
|
||||
"AlterUniqueTogether",
|
||||
"RenameModel",
|
||||
"AlterIndexTogether",
|
||||
"AlterModelOptions",
|
||||
"AddIndex",
|
||||
"RemoveIndex",
|
||||
"AddField",
|
||||
"RemoveField",
|
||||
"AlterField",
|
||||
"RenameField",
|
||||
"AddConstraint",
|
||||
"RemoveConstraint",
|
||||
"SeparateDatabaseAndState",
|
||||
"RunSQL",
|
||||
"RunPython",
|
||||
"AlterOrderWithRespectTo",
|
||||
"AlterModelManagers",
|
||||
'CreateModel', 'DeleteModel', 'AlterModelTable', 'AlterUniqueTogether',
|
||||
'RenameModel', 'AlterIndexTogether', 'AlterModelOptions', 'AddIndex',
|
||||
'RemoveIndex', 'AddField', 'RemoveField', 'AlterField', 'RenameField',
|
||||
'AddConstraint', 'RemoveConstraint',
|
||||
'SeparateDatabaseAndState', 'RunSQL', 'RunPython',
|
||||
'AlterOrderWithRespectTo', 'AlterModelManagers',
|
||||
]
|
||||
|
||||
@@ -56,18 +56,14 @@ class Operation:
|
||||
Take the state from the previous migration, and mutate it
|
||||
so that it matches what this migration would perform.
|
||||
"""
|
||||
raise NotImplementedError(
|
||||
"subclasses of Operation must provide a state_forwards() method"
|
||||
)
|
||||
raise NotImplementedError('subclasses of Operation must provide a state_forwards() method')
|
||||
|
||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||
"""
|
||||
Perform the mutation on the database schema in the normal
|
||||
(forwards) direction.
|
||||
"""
|
||||
raise NotImplementedError(
|
||||
"subclasses of Operation must provide a database_forwards() method"
|
||||
)
|
||||
raise NotImplementedError('subclasses of Operation must provide a database_forwards() method')
|
||||
|
||||
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
||||
"""
|
||||
@@ -75,9 +71,7 @@ class Operation:
|
||||
direction - e.g. if this were CreateModel, it would in fact
|
||||
drop the model's table.
|
||||
"""
|
||||
raise NotImplementedError(
|
||||
"subclasses of Operation must provide a database_backwards() method"
|
||||
)
|
||||
raise NotImplementedError('subclasses of Operation must provide a database_backwards() method')
|
||||
|
||||
def describe(self):
|
||||
"""
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
from django.db.migrations.utils import field_references
|
||||
from django.core.exceptions import FieldDoesNotExist
|
||||
from django.db.models import NOT_PROVIDED
|
||||
from django.utils.functional import cached_property
|
||||
|
||||
from .base import Operation
|
||||
from .utils import field_is_referenced, field_references, get_references
|
||||
|
||||
|
||||
class FieldOperation(Operation):
|
||||
@@ -23,23 +24,16 @@ class FieldOperation(Operation):
|
||||
return self.model_name_lower == operation.model_name_lower
|
||||
|
||||
def is_same_field_operation(self, operation):
|
||||
return (
|
||||
self.is_same_model_operation(operation)
|
||||
and self.name_lower == operation.name_lower
|
||||
)
|
||||
return self.is_same_model_operation(operation) and self.name_lower == operation.name_lower
|
||||
|
||||
def references_model(self, name, app_label):
|
||||
name_lower = name.lower()
|
||||
if name_lower == self.model_name_lower:
|
||||
return True
|
||||
if self.field:
|
||||
return bool(
|
||||
field_references(
|
||||
(app_label, self.model_name_lower),
|
||||
self.field,
|
||||
(app_label, name_lower),
|
||||
)
|
||||
)
|
||||
return bool(field_references(
|
||||
(app_label, self.model_name_lower), self.field, (app_label, name_lower)
|
||||
))
|
||||
return False
|
||||
|
||||
def references_field(self, model_name, name, app_label):
|
||||
@@ -48,27 +42,22 @@ class FieldOperation(Operation):
|
||||
if model_name_lower == self.model_name_lower:
|
||||
if name == self.name:
|
||||
return True
|
||||
elif (
|
||||
self.field
|
||||
and hasattr(self.field, "from_fields")
|
||||
and name in self.field.from_fields
|
||||
):
|
||||
elif self.field and hasattr(self.field, 'from_fields') and name in self.field.from_fields:
|
||||
return True
|
||||
# Check if this operation remotely references the field.
|
||||
if self.field is None:
|
||||
return False
|
||||
return bool(
|
||||
field_references(
|
||||
(app_label, self.model_name_lower),
|
||||
self.field,
|
||||
(app_label, model_name_lower),
|
||||
name,
|
||||
)
|
||||
)
|
||||
return bool(field_references(
|
||||
(app_label, self.model_name_lower),
|
||||
self.field,
|
||||
(app_label, model_name_lower),
|
||||
name,
|
||||
))
|
||||
|
||||
def reduce(self, operation, app_label):
|
||||
return super().reduce(operation, app_label) or not operation.references_field(
|
||||
self.model_name, self.name, app_label
|
||||
return (
|
||||
super().reduce(operation, app_label) or
|
||||
not operation.references_field(self.model_name, self.name, app_label)
|
||||
)
|
||||
|
||||
|
||||
@@ -81,22 +70,29 @@ class AddField(FieldOperation):
|
||||
|
||||
def deconstruct(self):
|
||||
kwargs = {
|
||||
"model_name": self.model_name,
|
||||
"name": self.name,
|
||||
"field": self.field,
|
||||
'model_name': self.model_name,
|
||||
'name': self.name,
|
||||
'field': self.field,
|
||||
}
|
||||
if self.preserve_default is not True:
|
||||
kwargs["preserve_default"] = self.preserve_default
|
||||
return (self.__class__.__name__, [], kwargs)
|
||||
kwargs['preserve_default'] = self.preserve_default
|
||||
return (
|
||||
self.__class__.__name__,
|
||||
[],
|
||||
kwargs
|
||||
)
|
||||
|
||||
def state_forwards(self, app_label, state):
|
||||
state.add_field(
|
||||
app_label,
|
||||
self.model_name_lower,
|
||||
self.name,
|
||||
self.field,
|
||||
self.preserve_default,
|
||||
)
|
||||
# If preserve default is off, don't use the default for future state
|
||||
if not self.preserve_default:
|
||||
field = self.field.clone()
|
||||
field.default = NOT_PROVIDED
|
||||
else:
|
||||
field = self.field
|
||||
state.models[app_label, self.model_name_lower].fields[self.name] = field
|
||||
# Delay rendering of relationships if it's not a relational field
|
||||
delay = not field.is_relation
|
||||
state.reload_model(app_label, self.model_name_lower, delay=delay)
|
||||
|
||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||
to_model = to_state.apps.get_model(app_label, self.model_name)
|
||||
@@ -115,21 +111,17 @@ class AddField(FieldOperation):
|
||||
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
||||
from_model = from_state.apps.get_model(app_label, self.model_name)
|
||||
if self.allow_migrate_model(schema_editor.connection.alias, from_model):
|
||||
schema_editor.remove_field(
|
||||
from_model, from_model._meta.get_field(self.name)
|
||||
)
|
||||
schema_editor.remove_field(from_model, from_model._meta.get_field(self.name))
|
||||
|
||||
def describe(self):
|
||||
return "Add field %s to %s" % (self.name, self.model_name)
|
||||
|
||||
@property
|
||||
def migration_name_fragment(self):
|
||||
return "%s_%s" % (self.model_name_lower, self.name_lower)
|
||||
return '%s_%s' % (self.model_name_lower, self.name_lower)
|
||||
|
||||
def reduce(self, operation, app_label):
|
||||
if isinstance(operation, FieldOperation) and self.is_same_field_operation(
|
||||
operation
|
||||
):
|
||||
if isinstance(operation, FieldOperation) and self.is_same_field_operation(operation):
|
||||
if isinstance(operation, AlterField):
|
||||
return [
|
||||
AddField(
|
||||
@@ -156,20 +148,26 @@ class RemoveField(FieldOperation):
|
||||
|
||||
def deconstruct(self):
|
||||
kwargs = {
|
||||
"model_name": self.model_name,
|
||||
"name": self.name,
|
||||
'model_name': self.model_name,
|
||||
'name': self.name,
|
||||
}
|
||||
return (self.__class__.__name__, [], kwargs)
|
||||
return (
|
||||
self.__class__.__name__,
|
||||
[],
|
||||
kwargs
|
||||
)
|
||||
|
||||
def state_forwards(self, app_label, state):
|
||||
state.remove_field(app_label, self.model_name_lower, self.name)
|
||||
model_state = state.models[app_label, self.model_name_lower]
|
||||
old_field = model_state.fields.pop(self.name)
|
||||
# Delay rendering of relationships if it's not a relational field
|
||||
delay = not old_field.is_relation
|
||||
state.reload_model(app_label, self.model_name_lower, delay=delay)
|
||||
|
||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||
from_model = from_state.apps.get_model(app_label, self.model_name)
|
||||
if self.allow_migrate_model(schema_editor.connection.alias, from_model):
|
||||
schema_editor.remove_field(
|
||||
from_model, from_model._meta.get_field(self.name)
|
||||
)
|
||||
schema_editor.remove_field(from_model, from_model._meta.get_field(self.name))
|
||||
|
||||
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
||||
to_model = to_state.apps.get_model(app_label, self.model_name)
|
||||
@@ -182,15 +180,11 @@ class RemoveField(FieldOperation):
|
||||
|
||||
@property
|
||||
def migration_name_fragment(self):
|
||||
return "remove_%s_%s" % (self.model_name_lower, self.name_lower)
|
||||
return 'remove_%s_%s' % (self.model_name_lower, self.name_lower)
|
||||
|
||||
def reduce(self, operation, app_label):
|
||||
from .models import DeleteModel
|
||||
|
||||
if (
|
||||
isinstance(operation, DeleteModel)
|
||||
and operation.name_lower == self.model_name_lower
|
||||
):
|
||||
if isinstance(operation, DeleteModel) and operation.name_lower == self.model_name_lower:
|
||||
return [operation]
|
||||
return super().reduce(operation, app_label)
|
||||
|
||||
@@ -207,22 +201,37 @@ class AlterField(FieldOperation):
|
||||
|
||||
def deconstruct(self):
|
||||
kwargs = {
|
||||
"model_name": self.model_name,
|
||||
"name": self.name,
|
||||
"field": self.field,
|
||||
'model_name': self.model_name,
|
||||
'name': self.name,
|
||||
'field': self.field,
|
||||
}
|
||||
if self.preserve_default is not True:
|
||||
kwargs["preserve_default"] = self.preserve_default
|
||||
return (self.__class__.__name__, [], kwargs)
|
||||
kwargs['preserve_default'] = self.preserve_default
|
||||
return (
|
||||
self.__class__.__name__,
|
||||
[],
|
||||
kwargs
|
||||
)
|
||||
|
||||
def state_forwards(self, app_label, state):
|
||||
state.alter_field(
|
||||
app_label,
|
||||
self.model_name_lower,
|
||||
self.name,
|
||||
self.field,
|
||||
self.preserve_default,
|
||||
if not self.preserve_default:
|
||||
field = self.field.clone()
|
||||
field.default = NOT_PROVIDED
|
||||
else:
|
||||
field = self.field
|
||||
model_state = state.models[app_label, self.model_name_lower]
|
||||
model_state.fields[self.name] = field
|
||||
# TODO: investigate if old relational fields must be reloaded or if it's
|
||||
# sufficient if the new field is (#27737).
|
||||
# Delay rendering of relationships if it's not a relational field and
|
||||
# not referenced by a foreign key.
|
||||
delay = (
|
||||
not field.is_relation and
|
||||
not field_is_referenced(
|
||||
state, (app_label, self.model_name_lower), (self.name, field),
|
||||
)
|
||||
)
|
||||
state.reload_model(app_label, self.model_name_lower, delay=delay)
|
||||
|
||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||
to_model = to_state.apps.get_model(app_label, self.model_name)
|
||||
@@ -244,16 +253,12 @@ class AlterField(FieldOperation):
|
||||
|
||||
@property
|
||||
def migration_name_fragment(self):
|
||||
return "alter_%s_%s" % (self.model_name_lower, self.name_lower)
|
||||
return 'alter_%s_%s' % (self.model_name_lower, self.name_lower)
|
||||
|
||||
def reduce(self, operation, app_label):
|
||||
if isinstance(operation, RemoveField) and self.is_same_field_operation(
|
||||
operation
|
||||
):
|
||||
if isinstance(operation, RemoveField) and self.is_same_field_operation(operation):
|
||||
return [operation]
|
||||
elif isinstance(operation, RenameField) and self.is_same_field_operation(
|
||||
operation
|
||||
):
|
||||
elif isinstance(operation, RenameField) and self.is_same_field_operation(operation):
|
||||
return [
|
||||
operation,
|
||||
AlterField(
|
||||
@@ -283,16 +288,60 @@ class RenameField(FieldOperation):
|
||||
|
||||
def deconstruct(self):
|
||||
kwargs = {
|
||||
"model_name": self.model_name,
|
||||
"old_name": self.old_name,
|
||||
"new_name": self.new_name,
|
||||
'model_name': self.model_name,
|
||||
'old_name': self.old_name,
|
||||
'new_name': self.new_name,
|
||||
}
|
||||
return (self.__class__.__name__, [], kwargs)
|
||||
return (
|
||||
self.__class__.__name__,
|
||||
[],
|
||||
kwargs
|
||||
)
|
||||
|
||||
def state_forwards(self, app_label, state):
|
||||
state.rename_field(
|
||||
app_label, self.model_name_lower, self.old_name, self.new_name
|
||||
model_state = state.models[app_label, self.model_name_lower]
|
||||
# Rename the field
|
||||
fields = model_state.fields
|
||||
try:
|
||||
found = fields.pop(self.old_name)
|
||||
except KeyError:
|
||||
raise FieldDoesNotExist(
|
||||
"%s.%s has no field named '%s'" % (app_label, self.model_name, self.old_name)
|
||||
)
|
||||
fields[self.new_name] = found
|
||||
for field in fields.values():
|
||||
# Fix from_fields to refer to the new field.
|
||||
from_fields = getattr(field, 'from_fields', None)
|
||||
if from_fields:
|
||||
field.from_fields = tuple([
|
||||
self.new_name if from_field_name == self.old_name else from_field_name
|
||||
for from_field_name in from_fields
|
||||
])
|
||||
# Fix index/unique_together to refer to the new field
|
||||
options = model_state.options
|
||||
for option in ('index_together', 'unique_together'):
|
||||
if option in options:
|
||||
options[option] = [
|
||||
[self.new_name if n == self.old_name else n for n in together]
|
||||
for together in options[option]
|
||||
]
|
||||
# Fix to_fields to refer to the new field.
|
||||
delay = True
|
||||
references = get_references(
|
||||
state, (app_label, self.model_name_lower), (self.old_name, found),
|
||||
)
|
||||
for *_, field, reference in references:
|
||||
delay = False
|
||||
if reference.to:
|
||||
remote_field, to_fields = reference.to
|
||||
if getattr(remote_field, 'field_name', None) == self.old_name:
|
||||
remote_field.field_name = self.new_name
|
||||
if to_fields:
|
||||
field.to_fields = tuple([
|
||||
self.new_name if to_field_name == self.old_name else to_field_name
|
||||
for to_field_name in to_fields
|
||||
])
|
||||
state.reload_model(app_label, self.model_name_lower, delay=delay)
|
||||
|
||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||
to_model = to_state.apps.get_model(app_label, self.model_name)
|
||||
@@ -315,15 +364,11 @@ class RenameField(FieldOperation):
|
||||
)
|
||||
|
||||
def describe(self):
|
||||
return "Rename field %s on %s to %s" % (
|
||||
self.old_name,
|
||||
self.model_name,
|
||||
self.new_name,
|
||||
)
|
||||
return "Rename field %s on %s to %s" % (self.old_name, self.model_name, self.new_name)
|
||||
|
||||
@property
|
||||
def migration_name_fragment(self):
|
||||
return "rename_%s_%s_%s" % (
|
||||
return 'rename_%s_%s_%s' % (
|
||||
self.old_name_lower,
|
||||
self.model_name_lower,
|
||||
self.new_name_lower,
|
||||
@@ -331,15 +376,14 @@ class RenameField(FieldOperation):
|
||||
|
||||
def references_field(self, model_name, name, app_label):
|
||||
return self.references_model(model_name, app_label) and (
|
||||
name.lower() == self.old_name_lower or name.lower() == self.new_name_lower
|
||||
name.lower() == self.old_name_lower or
|
||||
name.lower() == self.new_name_lower
|
||||
)
|
||||
|
||||
def reduce(self, operation, app_label):
|
||||
if (
|
||||
isinstance(operation, RenameField)
|
||||
and self.is_same_model_operation(operation)
|
||||
and self.new_name_lower == operation.old_name_lower
|
||||
):
|
||||
if (isinstance(operation, RenameField) and
|
||||
self.is_same_model_operation(operation) and
|
||||
self.new_name_lower == operation.old_name_lower):
|
||||
return [
|
||||
RenameField(
|
||||
self.model_name,
|
||||
@@ -348,8 +392,8 @@ class RenameField(FieldOperation):
|
||||
),
|
||||
]
|
||||
# Skip `FieldOperation.reduce` as we want to run `references_field`
|
||||
# against self.old_name and self.new_name.
|
||||
return super(FieldOperation, self).reduce(operation, app_label) or not (
|
||||
operation.references_field(self.model_name, self.old_name, app_label)
|
||||
or operation.references_field(self.model_name, self.new_name, app_label)
|
||||
# against self.new_name.
|
||||
return (
|
||||
super(FieldOperation, self).reduce(operation, app_label) or
|
||||
not operation.references_field(self.model_name, self.new_name, app_label)
|
||||
)
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
from django.db import models
|
||||
from django.db.migrations.operations.base import Operation
|
||||
from django.db.migrations.state import ModelState
|
||||
from django.db.migrations.utils import field_references, resolve_relation
|
||||
from django.db.models.options import normalize_together
|
||||
from django.utils.functional import cached_property
|
||||
|
||||
from .fields import AddField, AlterField, FieldOperation, RemoveField, RenameField
|
||||
from .fields import (
|
||||
AddField, AlterField, FieldOperation, RemoveField, RenameField,
|
||||
)
|
||||
from .utils import field_references, get_references, resolve_relation
|
||||
|
||||
|
||||
def _check_for_duplicates(arg_name, objs):
|
||||
@@ -30,15 +32,16 @@ class ModelOperation(Operation):
|
||||
return name.lower() == self.name_lower
|
||||
|
||||
def reduce(self, operation, app_label):
|
||||
return super().reduce(operation, app_label) or not operation.references_model(
|
||||
self.name, app_label
|
||||
return (
|
||||
super().reduce(operation, app_label) or
|
||||
not operation.references_model(self.name, app_label)
|
||||
)
|
||||
|
||||
|
||||
class CreateModel(ModelOperation):
|
||||
"""Create a model's table."""
|
||||
|
||||
serialization_expand_args = ["fields", "options", "managers"]
|
||||
serialization_expand_args = ['fields', 'options', 'managers']
|
||||
|
||||
def __init__(self, name, fields, options=None, bases=None, managers=None):
|
||||
self.fields = fields
|
||||
@@ -48,44 +51,40 @@ class CreateModel(ModelOperation):
|
||||
super().__init__(name)
|
||||
# Sanity-check that there are no duplicated field names, bases, or
|
||||
# manager names
|
||||
_check_for_duplicates("fields", (name for name, _ in self.fields))
|
||||
_check_for_duplicates(
|
||||
"bases",
|
||||
(
|
||||
base._meta.label_lower
|
||||
if hasattr(base, "_meta")
|
||||
else base.lower()
|
||||
if isinstance(base, str)
|
||||
else base
|
||||
for base in self.bases
|
||||
),
|
||||
)
|
||||
_check_for_duplicates("managers", (name for name, _ in self.managers))
|
||||
_check_for_duplicates('fields', (name for name, _ in self.fields))
|
||||
_check_for_duplicates('bases', (
|
||||
base._meta.label_lower if hasattr(base, '_meta') else
|
||||
base.lower() if isinstance(base, str) else base
|
||||
for base in self.bases
|
||||
))
|
||||
_check_for_duplicates('managers', (name for name, _ in self.managers))
|
||||
|
||||
def deconstruct(self):
|
||||
kwargs = {
|
||||
"name": self.name,
|
||||
"fields": self.fields,
|
||||
'name': self.name,
|
||||
'fields': self.fields,
|
||||
}
|
||||
if self.options:
|
||||
kwargs["options"] = self.options
|
||||
kwargs['options'] = self.options
|
||||
if self.bases and self.bases != (models.Model,):
|
||||
kwargs["bases"] = self.bases
|
||||
if self.managers and self.managers != [("objects", models.Manager())]:
|
||||
kwargs["managers"] = self.managers
|
||||
return (self.__class__.__qualname__, [], kwargs)
|
||||
kwargs['bases'] = self.bases
|
||||
if self.managers and self.managers != [('objects', models.Manager())]:
|
||||
kwargs['managers'] = self.managers
|
||||
return (
|
||||
self.__class__.__qualname__,
|
||||
[],
|
||||
kwargs
|
||||
)
|
||||
|
||||
def state_forwards(self, app_label, state):
|
||||
state.add_model(
|
||||
ModelState(
|
||||
app_label,
|
||||
self.name,
|
||||
list(self.fields),
|
||||
dict(self.options),
|
||||
tuple(self.bases),
|
||||
list(self.managers),
|
||||
)
|
||||
)
|
||||
state.add_model(ModelState(
|
||||
app_label,
|
||||
self.name,
|
||||
list(self.fields),
|
||||
dict(self.options),
|
||||
tuple(self.bases),
|
||||
list(self.managers),
|
||||
))
|
||||
|
||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||
model = to_state.apps.get_model(app_label, self.name)
|
||||
@@ -98,10 +97,7 @@ class CreateModel(ModelOperation):
|
||||
schema_editor.delete_model(model)
|
||||
|
||||
def describe(self):
|
||||
return "Create %smodel %s" % (
|
||||
"proxy " if self.options.get("proxy", False) else "",
|
||||
self.name,
|
||||
)
|
||||
return "Create %smodel %s" % ("proxy " if self.options.get("proxy", False) else "", self.name)
|
||||
|
||||
@property
|
||||
def migration_name_fragment(self):
|
||||
@@ -115,32 +111,22 @@ class CreateModel(ModelOperation):
|
||||
# Check we didn't inherit from the model
|
||||
reference_model_tuple = (app_label, name_lower)
|
||||
for base in self.bases:
|
||||
if (
|
||||
base is not models.Model
|
||||
and isinstance(base, (models.base.ModelBase, str))
|
||||
and resolve_relation(base, app_label) == reference_model_tuple
|
||||
):
|
||||
if (base is not models.Model and isinstance(base, (models.base.ModelBase, str)) and
|
||||
resolve_relation(base, app_label) == reference_model_tuple):
|
||||
return True
|
||||
|
||||
# Check we have no FKs/M2Ms with it
|
||||
for _name, field in self.fields:
|
||||
if field_references(
|
||||
(app_label, self.name_lower), field, reference_model_tuple
|
||||
):
|
||||
if field_references((app_label, self.name_lower), field, reference_model_tuple):
|
||||
return True
|
||||
return False
|
||||
|
||||
def reduce(self, operation, app_label):
|
||||
if (
|
||||
isinstance(operation, DeleteModel)
|
||||
and self.name_lower == operation.name_lower
|
||||
and not self.options.get("proxy", False)
|
||||
):
|
||||
if (isinstance(operation, DeleteModel) and
|
||||
self.name_lower == operation.name_lower and
|
||||
not self.options.get("proxy", False)):
|
||||
return []
|
||||
elif (
|
||||
isinstance(operation, RenameModel)
|
||||
and self.name_lower == operation.old_name_lower
|
||||
):
|
||||
elif isinstance(operation, RenameModel) and self.name_lower == operation.old_name_lower:
|
||||
return [
|
||||
CreateModel(
|
||||
operation.new_name,
|
||||
@@ -150,10 +136,7 @@ class CreateModel(ModelOperation):
|
||||
managers=self.managers,
|
||||
),
|
||||
]
|
||||
elif (
|
||||
isinstance(operation, AlterModelOptions)
|
||||
and self.name_lower == operation.name_lower
|
||||
):
|
||||
elif isinstance(operation, AlterModelOptions) and self.name_lower == operation.name_lower:
|
||||
options = {**self.options, **operation.options}
|
||||
for key in operation.ALTER_OPTION_KEYS:
|
||||
if key not in operation.options:
|
||||
@@ -167,42 +150,27 @@ class CreateModel(ModelOperation):
|
||||
managers=self.managers,
|
||||
),
|
||||
]
|
||||
elif (
|
||||
isinstance(operation, AlterTogetherOptionOperation)
|
||||
and self.name_lower == operation.name_lower
|
||||
):
|
||||
elif isinstance(operation, AlterTogetherOptionOperation) and self.name_lower == operation.name_lower:
|
||||
return [
|
||||
CreateModel(
|
||||
self.name,
|
||||
fields=self.fields,
|
||||
options={
|
||||
**self.options,
|
||||
**{operation.option_name: operation.option_value},
|
||||
},
|
||||
options={**self.options, **{operation.option_name: operation.option_value}},
|
||||
bases=self.bases,
|
||||
managers=self.managers,
|
||||
),
|
||||
]
|
||||
elif (
|
||||
isinstance(operation, AlterOrderWithRespectTo)
|
||||
and self.name_lower == operation.name_lower
|
||||
):
|
||||
elif isinstance(operation, AlterOrderWithRespectTo) and self.name_lower == operation.name_lower:
|
||||
return [
|
||||
CreateModel(
|
||||
self.name,
|
||||
fields=self.fields,
|
||||
options={
|
||||
**self.options,
|
||||
"order_with_respect_to": operation.order_with_respect_to,
|
||||
},
|
||||
options={**self.options, 'order_with_respect_to': operation.order_with_respect_to},
|
||||
bases=self.bases,
|
||||
managers=self.managers,
|
||||
),
|
||||
]
|
||||
elif (
|
||||
isinstance(operation, FieldOperation)
|
||||
and self.name_lower == operation.model_name_lower
|
||||
):
|
||||
elif isinstance(operation, FieldOperation) and self.name_lower == operation.model_name_lower:
|
||||
if isinstance(operation, AddField):
|
||||
return [
|
||||
CreateModel(
|
||||
@@ -228,25 +196,17 @@ class CreateModel(ModelOperation):
|
||||
]
|
||||
elif isinstance(operation, RemoveField):
|
||||
options = self.options.copy()
|
||||
for option_name in ("unique_together", "index_together"):
|
||||
for option_name in ('unique_together', 'index_together'):
|
||||
option = options.pop(option_name, None)
|
||||
if option:
|
||||
option = set(
|
||||
filter(
|
||||
bool,
|
||||
(
|
||||
tuple(
|
||||
f for f in fields if f != operation.name_lower
|
||||
)
|
||||
for fields in option
|
||||
),
|
||||
)
|
||||
)
|
||||
option = set(filter(bool, (
|
||||
tuple(f for f in fields if f != operation.name_lower) for fields in option
|
||||
)))
|
||||
if option:
|
||||
options[option_name] = option
|
||||
order_with_respect_to = options.get("order_with_respect_to")
|
||||
order_with_respect_to = options.get('order_with_respect_to')
|
||||
if order_with_respect_to == operation.name_lower:
|
||||
del options["order_with_respect_to"]
|
||||
del options['order_with_respect_to']
|
||||
return [
|
||||
CreateModel(
|
||||
self.name,
|
||||
@@ -262,19 +222,16 @@ class CreateModel(ModelOperation):
|
||||
]
|
||||
elif isinstance(operation, RenameField):
|
||||
options = self.options.copy()
|
||||
for option_name in ("unique_together", "index_together"):
|
||||
for option_name in ('unique_together', 'index_together'):
|
||||
option = options.get(option_name)
|
||||
if option:
|
||||
options[option_name] = {
|
||||
tuple(
|
||||
operation.new_name if f == operation.old_name else f
|
||||
for f in fields
|
||||
)
|
||||
tuple(operation.new_name if f == operation.old_name else f for f in fields)
|
||||
for fields in option
|
||||
}
|
||||
order_with_respect_to = options.get("order_with_respect_to")
|
||||
order_with_respect_to = options.get('order_with_respect_to')
|
||||
if order_with_respect_to == operation.old_name:
|
||||
options["order_with_respect_to"] = operation.new_name
|
||||
options['order_with_respect_to'] = operation.new_name
|
||||
return [
|
||||
CreateModel(
|
||||
self.name,
|
||||
@@ -295,9 +252,13 @@ class DeleteModel(ModelOperation):
|
||||
|
||||
def deconstruct(self):
|
||||
kwargs = {
|
||||
"name": self.name,
|
||||
'name': self.name,
|
||||
}
|
||||
return (self.__class__.__qualname__, [], kwargs)
|
||||
return (
|
||||
self.__class__.__qualname__,
|
||||
[],
|
||||
kwargs
|
||||
)
|
||||
|
||||
def state_forwards(self, app_label, state):
|
||||
state.remove_model(app_label, self.name_lower)
|
||||
@@ -322,7 +283,7 @@ class DeleteModel(ModelOperation):
|
||||
|
||||
@property
|
||||
def migration_name_fragment(self):
|
||||
return "delete_%s" % self.name_lower
|
||||
return 'delete_%s' % self.name_lower
|
||||
|
||||
|
||||
class RenameModel(ModelOperation):
|
||||
@@ -343,13 +304,41 @@ class RenameModel(ModelOperation):
|
||||
|
||||
def deconstruct(self):
|
||||
kwargs = {
|
||||
"old_name": self.old_name,
|
||||
"new_name": self.new_name,
|
||||
'old_name': self.old_name,
|
||||
'new_name': self.new_name,
|
||||
}
|
||||
return (self.__class__.__qualname__, [], kwargs)
|
||||
return (
|
||||
self.__class__.__qualname__,
|
||||
[],
|
||||
kwargs
|
||||
)
|
||||
|
||||
def state_forwards(self, app_label, state):
|
||||
state.rename_model(app_label, self.old_name, self.new_name)
|
||||
# Add a new model.
|
||||
renamed_model = state.models[app_label, self.old_name_lower].clone()
|
||||
renamed_model.name = self.new_name
|
||||
state.models[app_label, self.new_name_lower] = renamed_model
|
||||
# Repoint all fields pointing to the old model to the new one.
|
||||
old_model_tuple = (app_label, self.old_name_lower)
|
||||
new_remote_model = '%s.%s' % (app_label, self.new_name)
|
||||
to_reload = set()
|
||||
for model_state, name, field, reference in get_references(state, old_model_tuple):
|
||||
changed_field = None
|
||||
if reference.to:
|
||||
changed_field = field.clone()
|
||||
changed_field.remote_field.model = new_remote_model
|
||||
if reference.through:
|
||||
if changed_field is None:
|
||||
changed_field = field.clone()
|
||||
changed_field.remote_field.through = new_remote_model
|
||||
if changed_field:
|
||||
model_state.fields[name] = changed_field
|
||||
to_reload.add((model_state.app_label, model_state.name_lower))
|
||||
# Reload models related to old model before removing the old model.
|
||||
state.reload_models(to_reload, delay=True)
|
||||
# Remove the old model.
|
||||
state.remove_model(app_label, self.old_name_lower)
|
||||
state.reload_model(app_label, self.new_name_lower, delay=True)
|
||||
|
||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||
new_model = to_state.apps.get_model(app_label, self.new_name)
|
||||
@@ -372,24 +361,19 @@ class RenameModel(ModelOperation):
|
||||
related_object.related_model._meta.app_label,
|
||||
related_object.related_model._meta.model_name,
|
||||
)
|
||||
to_field = to_state.apps.get_model(*related_key)._meta.get_field(
|
||||
related_object.field.name
|
||||
)
|
||||
to_field = to_state.apps.get_model(
|
||||
*related_key
|
||||
)._meta.get_field(related_object.field.name)
|
||||
schema_editor.alter_field(
|
||||
model,
|
||||
related_object.field,
|
||||
to_field,
|
||||
)
|
||||
# Rename M2M fields whose name is based on this model's name.
|
||||
fields = zip(
|
||||
old_model._meta.local_many_to_many, new_model._meta.local_many_to_many
|
||||
)
|
||||
fields = zip(old_model._meta.local_many_to_many, new_model._meta.local_many_to_many)
|
||||
for (old_field, new_field) in fields:
|
||||
# Skip self-referential fields as these are renamed above.
|
||||
if (
|
||||
new_field.model == new_field.related_model
|
||||
or not new_field.remote_field.through._meta.auto_created
|
||||
):
|
||||
if new_field.model == new_field.related_model or not new_field.remote_field.through._meta.auto_created:
|
||||
continue
|
||||
# Rename the M2M table that's based on this model's name.
|
||||
old_m2m_model = old_field.remote_field.through
|
||||
@@ -408,23 +392,18 @@ class RenameModel(ModelOperation):
|
||||
)
|
||||
|
||||
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
||||
self.new_name_lower, self.old_name_lower = (
|
||||
self.old_name_lower,
|
||||
self.new_name_lower,
|
||||
)
|
||||
self.new_name_lower, self.old_name_lower = self.old_name_lower, self.new_name_lower
|
||||
self.new_name, self.old_name = self.old_name, self.new_name
|
||||
|
||||
self.database_forwards(app_label, schema_editor, from_state, to_state)
|
||||
|
||||
self.new_name_lower, self.old_name_lower = (
|
||||
self.old_name_lower,
|
||||
self.new_name_lower,
|
||||
)
|
||||
self.new_name_lower, self.old_name_lower = self.old_name_lower, self.new_name_lower
|
||||
self.new_name, self.old_name = self.old_name, self.new_name
|
||||
|
||||
def references_model(self, name, app_label):
|
||||
return (
|
||||
name.lower() == self.old_name_lower or name.lower() == self.new_name_lower
|
||||
name.lower() == self.old_name_lower or
|
||||
name.lower() == self.new_name_lower
|
||||
)
|
||||
|
||||
def describe(self):
|
||||
@@ -432,13 +411,11 @@ class RenameModel(ModelOperation):
|
||||
|
||||
@property
|
||||
def migration_name_fragment(self):
|
||||
return "rename_%s_%s" % (self.old_name_lower, self.new_name_lower)
|
||||
return 'rename_%s_%s' % (self.old_name_lower, self.new_name_lower)
|
||||
|
||||
def reduce(self, operation, app_label):
|
||||
if (
|
||||
isinstance(operation, RenameModel)
|
||||
and self.new_name_lower == operation.old_name_lower
|
||||
):
|
||||
if (isinstance(operation, RenameModel) and
|
||||
self.new_name_lower == operation.old_name_lower):
|
||||
return [
|
||||
RenameModel(
|
||||
self.old_name,
|
||||
@@ -447,17 +424,15 @@ class RenameModel(ModelOperation):
|
||||
]
|
||||
# Skip `ModelOperation.reduce` as we want to run `references_model`
|
||||
# against self.new_name.
|
||||
return super(ModelOperation, self).reduce(
|
||||
operation, app_label
|
||||
) or not operation.references_model(self.new_name, app_label)
|
||||
return (
|
||||
super(ModelOperation, self).reduce(operation, app_label) or
|
||||
not operation.references_model(self.new_name, app_label)
|
||||
)
|
||||
|
||||
|
||||
class ModelOptionOperation(ModelOperation):
|
||||
def reduce(self, operation, app_label):
|
||||
if (
|
||||
isinstance(operation, (self.__class__, DeleteModel))
|
||||
and self.name_lower == operation.name_lower
|
||||
):
|
||||
if isinstance(operation, (self.__class__, DeleteModel)) and self.name_lower == operation.name_lower:
|
||||
return [operation]
|
||||
return super().reduce(operation, app_label)
|
||||
|
||||
@@ -471,13 +446,18 @@ class AlterModelTable(ModelOptionOperation):
|
||||
|
||||
def deconstruct(self):
|
||||
kwargs = {
|
||||
"name": self.name,
|
||||
"table": self.table,
|
||||
'name': self.name,
|
||||
'table': self.table,
|
||||
}
|
||||
return (self.__class__.__qualname__, [], kwargs)
|
||||
return (
|
||||
self.__class__.__qualname__,
|
||||
[],
|
||||
kwargs
|
||||
)
|
||||
|
||||
def state_forwards(self, app_label, state):
|
||||
state.alter_model_options(app_label, self.name_lower, {"db_table": self.table})
|
||||
state.models[app_label, self.name_lower].options["db_table"] = self.table
|
||||
state.reload_model(app_label, self.name_lower, delay=True)
|
||||
|
||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||
new_model = to_state.apps.get_model(app_label, self.name)
|
||||
@@ -489,9 +469,7 @@ class AlterModelTable(ModelOptionOperation):
|
||||
new_model._meta.db_table,
|
||||
)
|
||||
# Rename M2M fields whose name is based on this model's db_table
|
||||
for (old_field, new_field) in zip(
|
||||
old_model._meta.local_many_to_many, new_model._meta.local_many_to_many
|
||||
):
|
||||
for (old_field, new_field) in zip(old_model._meta.local_many_to_many, new_model._meta.local_many_to_many):
|
||||
if new_field.remote_field.through._meta.auto_created:
|
||||
schema_editor.alter_db_table(
|
||||
new_field.remote_field.through,
|
||||
@@ -505,12 +483,12 @@ class AlterModelTable(ModelOptionOperation):
|
||||
def describe(self):
|
||||
return "Rename table for %s to %s" % (
|
||||
self.name,
|
||||
self.table if self.table is not None else "(default)",
|
||||
self.table if self.table is not None else "(default)"
|
||||
)
|
||||
|
||||
@property
|
||||
def migration_name_fragment(self):
|
||||
return "alter_%s_table" % self.name_lower
|
||||
return 'alter_%s_table' % self.name_lower
|
||||
|
||||
|
||||
class AlterTogetherOptionOperation(ModelOptionOperation):
|
||||
@@ -528,23 +506,25 @@ class AlterTogetherOptionOperation(ModelOptionOperation):
|
||||
|
||||
def deconstruct(self):
|
||||
kwargs = {
|
||||
"name": self.name,
|
||||
'name': self.name,
|
||||
self.option_name: self.option_value,
|
||||
}
|
||||
return (self.__class__.__qualname__, [], kwargs)
|
||||
return (
|
||||
self.__class__.__qualname__,
|
||||
[],
|
||||
kwargs
|
||||
)
|
||||
|
||||
def state_forwards(self, app_label, state):
|
||||
state.alter_model_options(
|
||||
app_label,
|
||||
self.name_lower,
|
||||
{self.option_name: self.option_value},
|
||||
)
|
||||
model_state = state.models[app_label, self.name_lower]
|
||||
model_state.options[self.option_name] = self.option_value
|
||||
state.reload_model(app_label, self.name_lower, delay=True)
|
||||
|
||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||
new_model = to_state.apps.get_model(app_label, self.name)
|
||||
if self.allow_migrate_model(schema_editor.connection.alias, new_model):
|
||||
old_model = from_state.apps.get_model(app_label, self.name)
|
||||
alter_together = getattr(schema_editor, "alter_%s" % self.option_name)
|
||||
alter_together = getattr(schema_editor, 'alter_%s' % self.option_name)
|
||||
alter_together(
|
||||
new_model,
|
||||
getattr(old_model._meta, self.option_name, set()),
|
||||
@@ -555,21 +535,20 @@ class AlterTogetherOptionOperation(ModelOptionOperation):
|
||||
return self.database_forwards(app_label, schema_editor, from_state, to_state)
|
||||
|
||||
def references_field(self, model_name, name, app_label):
|
||||
return self.references_model(model_name, app_label) and (
|
||||
not self.option_value
|
||||
or any((name in fields) for fields in self.option_value)
|
||||
return (
|
||||
self.references_model(model_name, app_label) and
|
||||
(
|
||||
not self.option_value or
|
||||
any((name in fields) for fields in self.option_value)
|
||||
)
|
||||
)
|
||||
|
||||
def describe(self):
|
||||
return "Alter %s for %s (%s constraint(s))" % (
|
||||
self.option_name,
|
||||
self.name,
|
||||
len(self.option_value or ""),
|
||||
)
|
||||
return "Alter %s for %s (%s constraint(s))" % (self.option_name, self.name, len(self.option_value or ''))
|
||||
|
||||
@property
|
||||
def migration_name_fragment(self):
|
||||
return "alter_%s_%s" % (self.name_lower, self.option_name)
|
||||
return 'alter_%s_%s' % (self.name_lower, self.option_name)
|
||||
|
||||
|
||||
class AlterUniqueTogether(AlterTogetherOptionOperation):
|
||||
@@ -577,8 +556,7 @@ class AlterUniqueTogether(AlterTogetherOptionOperation):
|
||||
Change the value of unique_together to the target one.
|
||||
Input value of unique_together must be a set of tuples.
|
||||
"""
|
||||
|
||||
option_name = "unique_together"
|
||||
option_name = 'unique_together'
|
||||
|
||||
def __init__(self, name, unique_together):
|
||||
super().__init__(name, unique_together)
|
||||
@@ -589,7 +567,6 @@ class AlterIndexTogether(AlterTogetherOptionOperation):
|
||||
Change the value of index_together to the target one.
|
||||
Input value of index_together must be a set of tuples.
|
||||
"""
|
||||
|
||||
option_name = "index_together"
|
||||
|
||||
def __init__(self, name, index_together):
|
||||
@@ -599,7 +576,7 @@ class AlterIndexTogether(AlterTogetherOptionOperation):
|
||||
class AlterOrderWithRespectTo(ModelOptionOperation):
|
||||
"""Represent a change with the order_with_respect_to option."""
|
||||
|
||||
option_name = "order_with_respect_to"
|
||||
option_name = 'order_with_respect_to'
|
||||
|
||||
def __init__(self, name, order_with_respect_to):
|
||||
self.order_with_respect_to = order_with_respect_to
|
||||
@@ -607,36 +584,30 @@ class AlterOrderWithRespectTo(ModelOptionOperation):
|
||||
|
||||
def deconstruct(self):
|
||||
kwargs = {
|
||||
"name": self.name,
|
||||
"order_with_respect_to": self.order_with_respect_to,
|
||||
'name': self.name,
|
||||
'order_with_respect_to': self.order_with_respect_to,
|
||||
}
|
||||
return (self.__class__.__qualname__, [], kwargs)
|
||||
return (
|
||||
self.__class__.__qualname__,
|
||||
[],
|
||||
kwargs
|
||||
)
|
||||
|
||||
def state_forwards(self, app_label, state):
|
||||
state.alter_model_options(
|
||||
app_label,
|
||||
self.name_lower,
|
||||
{self.option_name: self.order_with_respect_to},
|
||||
)
|
||||
model_state = state.models[app_label, self.name_lower]
|
||||
model_state.options['order_with_respect_to'] = self.order_with_respect_to
|
||||
state.reload_model(app_label, self.name_lower, delay=True)
|
||||
|
||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||
to_model = to_state.apps.get_model(app_label, self.name)
|
||||
if self.allow_migrate_model(schema_editor.connection.alias, to_model):
|
||||
from_model = from_state.apps.get_model(app_label, self.name)
|
||||
# Remove a field if we need to
|
||||
if (
|
||||
from_model._meta.order_with_respect_to
|
||||
and not to_model._meta.order_with_respect_to
|
||||
):
|
||||
schema_editor.remove_field(
|
||||
from_model, from_model._meta.get_field("_order")
|
||||
)
|
||||
if from_model._meta.order_with_respect_to and not to_model._meta.order_with_respect_to:
|
||||
schema_editor.remove_field(from_model, from_model._meta.get_field("_order"))
|
||||
# Add a field if we need to (altering the column is untouched as
|
||||
# it's likely a rename)
|
||||
elif (
|
||||
to_model._meta.order_with_respect_to
|
||||
and not from_model._meta.order_with_respect_to
|
||||
):
|
||||
elif to_model._meta.order_with_respect_to and not from_model._meta.order_with_respect_to:
|
||||
field = to_model._meta.get_field("_order")
|
||||
if not field.has_default():
|
||||
field.default = 0
|
||||
@@ -649,19 +620,20 @@ class AlterOrderWithRespectTo(ModelOptionOperation):
|
||||
self.database_forwards(app_label, schema_editor, from_state, to_state)
|
||||
|
||||
def references_field(self, model_name, name, app_label):
|
||||
return self.references_model(model_name, app_label) and (
|
||||
self.order_with_respect_to is None or name == self.order_with_respect_to
|
||||
return (
|
||||
self.references_model(model_name, app_label) and
|
||||
(
|
||||
self.order_with_respect_to is None or
|
||||
name == self.order_with_respect_to
|
||||
)
|
||||
)
|
||||
|
||||
def describe(self):
|
||||
return "Set order_with_respect_to on %s to %s" % (
|
||||
self.name,
|
||||
self.order_with_respect_to,
|
||||
)
|
||||
return "Set order_with_respect_to on %s to %s" % (self.name, self.order_with_respect_to)
|
||||
|
||||
@property
|
||||
def migration_name_fragment(self):
|
||||
return "alter_%s_order_with_respect_to" % self.name_lower
|
||||
return 'alter_%s_order_with_respect_to' % self.name_lower
|
||||
|
||||
|
||||
class AlterModelOptions(ModelOptionOperation):
|
||||
@@ -692,18 +664,22 @@ class AlterModelOptions(ModelOptionOperation):
|
||||
|
||||
def deconstruct(self):
|
||||
kwargs = {
|
||||
"name": self.name,
|
||||
"options": self.options,
|
||||
'name': self.name,
|
||||
'options': self.options,
|
||||
}
|
||||
return (self.__class__.__qualname__, [], kwargs)
|
||||
return (
|
||||
self.__class__.__qualname__,
|
||||
[],
|
||||
kwargs
|
||||
)
|
||||
|
||||
def state_forwards(self, app_label, state):
|
||||
state.alter_model_options(
|
||||
app_label,
|
||||
self.name_lower,
|
||||
self.options,
|
||||
self.ALTER_OPTION_KEYS,
|
||||
)
|
||||
model_state = state.models[app_label, self.name_lower]
|
||||
model_state.options = {**model_state.options, **self.options}
|
||||
for key in self.ALTER_OPTION_KEYS:
|
||||
if key not in self.options:
|
||||
model_state.options.pop(key, False)
|
||||
state.reload_model(app_label, self.name_lower, delay=True)
|
||||
|
||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||
pass
|
||||
@@ -716,23 +692,29 @@ class AlterModelOptions(ModelOptionOperation):
|
||||
|
||||
@property
|
||||
def migration_name_fragment(self):
|
||||
return "alter_%s_options" % self.name_lower
|
||||
return 'alter_%s_options' % self.name_lower
|
||||
|
||||
|
||||
class AlterModelManagers(ModelOptionOperation):
|
||||
"""Alter the model's managers."""
|
||||
|
||||
serialization_expand_args = ["managers"]
|
||||
serialization_expand_args = ['managers']
|
||||
|
||||
def __init__(self, name, managers):
|
||||
self.managers = managers
|
||||
super().__init__(name)
|
||||
|
||||
def deconstruct(self):
|
||||
return (self.__class__.__qualname__, [self.name, self.managers], {})
|
||||
return (
|
||||
self.__class__.__qualname__,
|
||||
[self.name, self.managers],
|
||||
{}
|
||||
)
|
||||
|
||||
def state_forwards(self, app_label, state):
|
||||
state.alter_model_managers(app_label, self.name_lower, self.managers)
|
||||
model_state = state.models[app_label, self.name_lower]
|
||||
model_state.managers = list(self.managers)
|
||||
state.reload_model(app_label, self.name_lower, delay=True)
|
||||
|
||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||
pass
|
||||
@@ -745,11 +727,11 @@ class AlterModelManagers(ModelOptionOperation):
|
||||
|
||||
@property
|
||||
def migration_name_fragment(self):
|
||||
return "alter_%s_managers" % self.name_lower
|
||||
return 'alter_%s_managers' % self.name_lower
|
||||
|
||||
|
||||
class IndexOperation(Operation):
|
||||
option_name = "indexes"
|
||||
option_name = 'indexes'
|
||||
|
||||
@cached_property
|
||||
def model_name_lower(self):
|
||||
@@ -769,7 +751,9 @@ class AddIndex(IndexOperation):
|
||||
self.index = index
|
||||
|
||||
def state_forwards(self, app_label, state):
|
||||
state.add_index(app_label, self.model_name_lower, self.index)
|
||||
model_state = state.models[app_label, self.model_name_lower]
|
||||
model_state.options[self.option_name] = [*model_state.options[self.option_name], self.index.clone()]
|
||||
state.reload_model(app_label, self.model_name_lower, delay=True)
|
||||
|
||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||
model = to_state.apps.get_model(app_label, self.model_name)
|
||||
@@ -783,8 +767,8 @@ class AddIndex(IndexOperation):
|
||||
|
||||
def deconstruct(self):
|
||||
kwargs = {
|
||||
"model_name": self.model_name,
|
||||
"index": self.index,
|
||||
'model_name': self.model_name,
|
||||
'index': self.index,
|
||||
}
|
||||
return (
|
||||
self.__class__.__qualname__,
|
||||
@@ -794,20 +778,20 @@ class AddIndex(IndexOperation):
|
||||
|
||||
def describe(self):
|
||||
if self.index.expressions:
|
||||
return "Create index %s on %s on model %s" % (
|
||||
return 'Create index %s on %s on model %s' % (
|
||||
self.index.name,
|
||||
", ".join([str(expression) for expression in self.index.expressions]),
|
||||
', '.join([str(expression) for expression in self.index.expressions]),
|
||||
self.model_name,
|
||||
)
|
||||
return "Create index %s on field(s) %s of model %s" % (
|
||||
return 'Create index %s on field(s) %s of model %s' % (
|
||||
self.index.name,
|
||||
", ".join(self.index.fields),
|
||||
', '.join(self.index.fields),
|
||||
self.model_name,
|
||||
)
|
||||
|
||||
@property
|
||||
def migration_name_fragment(self):
|
||||
return "%s_%s" % (self.model_name_lower, self.index.name.lower())
|
||||
return '%s_%s' % (self.model_name_lower, self.index.name.lower())
|
||||
|
||||
|
||||
class RemoveIndex(IndexOperation):
|
||||
@@ -818,7 +802,10 @@ class RemoveIndex(IndexOperation):
|
||||
self.name = name
|
||||
|
||||
def state_forwards(self, app_label, state):
|
||||
state.remove_index(app_label, self.model_name_lower, self.name)
|
||||
model_state = state.models[app_label, self.model_name_lower]
|
||||
indexes = model_state.options[self.option_name]
|
||||
model_state.options[self.option_name] = [idx for idx in indexes if idx.name != self.name]
|
||||
state.reload_model(app_label, self.model_name_lower, delay=True)
|
||||
|
||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||
model = from_state.apps.get_model(app_label, self.model_name)
|
||||
@@ -836,8 +823,8 @@ class RemoveIndex(IndexOperation):
|
||||
|
||||
def deconstruct(self):
|
||||
kwargs = {
|
||||
"model_name": self.model_name,
|
||||
"name": self.name,
|
||||
'model_name': self.model_name,
|
||||
'name': self.name,
|
||||
}
|
||||
return (
|
||||
self.__class__.__qualname__,
|
||||
@@ -846,22 +833,24 @@ class RemoveIndex(IndexOperation):
|
||||
)
|
||||
|
||||
def describe(self):
|
||||
return "Remove index %s from %s" % (self.name, self.model_name)
|
||||
return 'Remove index %s from %s' % (self.name, self.model_name)
|
||||
|
||||
@property
|
||||
def migration_name_fragment(self):
|
||||
return "remove_%s_%s" % (self.model_name_lower, self.name.lower())
|
||||
return 'remove_%s_%s' % (self.model_name_lower, self.name.lower())
|
||||
|
||||
|
||||
class AddConstraint(IndexOperation):
|
||||
option_name = "constraints"
|
||||
option_name = 'constraints'
|
||||
|
||||
def __init__(self, model_name, constraint):
|
||||
self.model_name = model_name
|
||||
self.constraint = constraint
|
||||
|
||||
def state_forwards(self, app_label, state):
|
||||
state.add_constraint(app_label, self.model_name_lower, self.constraint)
|
||||
model_state = state.models[app_label, self.model_name_lower]
|
||||
model_state.options[self.option_name] = [*model_state.options[self.option_name], self.constraint]
|
||||
state.reload_model(app_label, self.model_name_lower, delay=True)
|
||||
|
||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||
model = to_state.apps.get_model(app_label, self.model_name)
|
||||
@@ -874,35 +863,31 @@ class AddConstraint(IndexOperation):
|
||||
schema_editor.remove_constraint(model, self.constraint)
|
||||
|
||||
def deconstruct(self):
|
||||
return (
|
||||
self.__class__.__name__,
|
||||
[],
|
||||
{
|
||||
"model_name": self.model_name,
|
||||
"constraint": self.constraint,
|
||||
},
|
||||
)
|
||||
return self.__class__.__name__, [], {
|
||||
'model_name': self.model_name,
|
||||
'constraint': self.constraint,
|
||||
}
|
||||
|
||||
def describe(self):
|
||||
return "Create constraint %s on model %s" % (
|
||||
self.constraint.name,
|
||||
self.model_name,
|
||||
)
|
||||
return 'Create constraint %s on model %s' % (self.constraint.name, self.model_name)
|
||||
|
||||
@property
|
||||
def migration_name_fragment(self):
|
||||
return "%s_%s" % (self.model_name_lower, self.constraint.name.lower())
|
||||
return '%s_%s' % (self.model_name_lower, self.constraint.name.lower())
|
||||
|
||||
|
||||
class RemoveConstraint(IndexOperation):
|
||||
option_name = "constraints"
|
||||
option_name = 'constraints'
|
||||
|
||||
def __init__(self, model_name, name):
|
||||
self.model_name = model_name
|
||||
self.name = name
|
||||
|
||||
def state_forwards(self, app_label, state):
|
||||
state.remove_constraint(app_label, self.model_name_lower, self.name)
|
||||
model_state = state.models[app_label, self.model_name_lower]
|
||||
constraints = model_state.options[self.option_name]
|
||||
model_state.options[self.option_name] = [c for c in constraints if c.name != self.name]
|
||||
state.reload_model(app_label, self.model_name_lower, delay=True)
|
||||
|
||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||
model = to_state.apps.get_model(app_label, self.model_name)
|
||||
@@ -919,18 +904,14 @@ class RemoveConstraint(IndexOperation):
|
||||
schema_editor.add_constraint(model, constraint)
|
||||
|
||||
def deconstruct(self):
|
||||
return (
|
||||
self.__class__.__name__,
|
||||
[],
|
||||
{
|
||||
"model_name": self.model_name,
|
||||
"name": self.name,
|
||||
},
|
||||
)
|
||||
return self.__class__.__name__, [], {
|
||||
'model_name': self.model_name,
|
||||
'name': self.name,
|
||||
}
|
||||
|
||||
def describe(self):
|
||||
return "Remove constraint %s from model %s" % (self.name, self.model_name)
|
||||
return 'Remove constraint %s from model %s' % (self.name, self.model_name)
|
||||
|
||||
@property
|
||||
def migration_name_fragment(self):
|
||||
return "remove_%s_%s" % (self.model_name_lower, self.name.lower())
|
||||
return 'remove_%s_%s' % (self.model_name_lower, self.name.lower())
|
||||
|
||||
@@ -11,7 +11,7 @@ class SeparateDatabaseAndState(Operation):
|
||||
that affect the state or not the database, or so on.
|
||||
"""
|
||||
|
||||
serialization_expand_args = ["database_operations", "state_operations"]
|
||||
serialization_expand_args = ['database_operations', 'state_operations']
|
||||
|
||||
def __init__(self, database_operations=None, state_operations=None):
|
||||
self.database_operations = database_operations or []
|
||||
@@ -20,10 +20,14 @@ class SeparateDatabaseAndState(Operation):
|
||||
def deconstruct(self):
|
||||
kwargs = {}
|
||||
if self.database_operations:
|
||||
kwargs["database_operations"] = self.database_operations
|
||||
kwargs['database_operations'] = self.database_operations
|
||||
if self.state_operations:
|
||||
kwargs["state_operations"] = self.state_operations
|
||||
return (self.__class__.__qualname__, [], kwargs)
|
||||
kwargs['state_operations'] = self.state_operations
|
||||
return (
|
||||
self.__class__.__qualname__,
|
||||
[],
|
||||
kwargs
|
||||
)
|
||||
|
||||
def state_forwards(self, app_label, state):
|
||||
for state_operation in self.state_operations:
|
||||
@@ -34,9 +38,7 @@ class SeparateDatabaseAndState(Operation):
|
||||
for database_operation in self.database_operations:
|
||||
to_state = from_state.clone()
|
||||
database_operation.state_forwards(app_label, to_state)
|
||||
database_operation.database_forwards(
|
||||
app_label, schema_editor, from_state, to_state
|
||||
)
|
||||
database_operation.database_forwards(app_label, schema_editor, from_state, to_state)
|
||||
from_state = to_state
|
||||
|
||||
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
||||
@@ -52,9 +54,7 @@ class SeparateDatabaseAndState(Operation):
|
||||
for database_operation in reversed(self.database_operations):
|
||||
from_state = to_state
|
||||
to_state = to_states[database_operation]
|
||||
database_operation.database_backwards(
|
||||
app_label, schema_editor, from_state, to_state
|
||||
)
|
||||
database_operation.database_backwards(app_label, schema_editor, from_state, to_state)
|
||||
|
||||
def describe(self):
|
||||
return "Custom state/database change combination"
|
||||
@@ -67,12 +67,9 @@ class RunSQL(Operation):
|
||||
Also accept a list of operations that represent the state change effected
|
||||
by this SQL change, in case it's custom column/table creation/deletion.
|
||||
"""
|
||||
noop = ''
|
||||
|
||||
noop = ""
|
||||
|
||||
def __init__(
|
||||
self, sql, reverse_sql=None, state_operations=None, hints=None, elidable=False
|
||||
):
|
||||
def __init__(self, sql, reverse_sql=None, state_operations=None, hints=None, elidable=False):
|
||||
self.sql = sql
|
||||
self.reverse_sql = reverse_sql
|
||||
self.state_operations = state_operations or []
|
||||
@@ -81,15 +78,19 @@ class RunSQL(Operation):
|
||||
|
||||
def deconstruct(self):
|
||||
kwargs = {
|
||||
"sql": self.sql,
|
||||
'sql': self.sql,
|
||||
}
|
||||
if self.reverse_sql is not None:
|
||||
kwargs["reverse_sql"] = self.reverse_sql
|
||||
kwargs['reverse_sql'] = self.reverse_sql
|
||||
if self.state_operations:
|
||||
kwargs["state_operations"] = self.state_operations
|
||||
kwargs['state_operations'] = self.state_operations
|
||||
if self.hints:
|
||||
kwargs["hints"] = self.hints
|
||||
return (self.__class__.__qualname__, [], kwargs)
|
||||
kwargs['hints'] = self.hints
|
||||
return (
|
||||
self.__class__.__qualname__,
|
||||
[],
|
||||
kwargs
|
||||
)
|
||||
|
||||
@property
|
||||
def reversible(self):
|
||||
@@ -100,17 +101,13 @@ class RunSQL(Operation):
|
||||
state_operation.state_forwards(app_label, state)
|
||||
|
||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||
if router.allow_migrate(
|
||||
schema_editor.connection.alias, app_label, **self.hints
|
||||
):
|
||||
if router.allow_migrate(schema_editor.connection.alias, app_label, **self.hints):
|
||||
self._run_sql(schema_editor, self.sql)
|
||||
|
||||
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
||||
if self.reverse_sql is None:
|
||||
raise NotImplementedError("You cannot reverse this operation")
|
||||
if router.allow_migrate(
|
||||
schema_editor.connection.alias, app_label, **self.hints
|
||||
):
|
||||
if router.allow_migrate(schema_editor.connection.alias, app_label, **self.hints):
|
||||
self._run_sql(schema_editor, self.reverse_sql)
|
||||
|
||||
def describe(self):
|
||||
@@ -140,9 +137,7 @@ class RunPython(Operation):
|
||||
|
||||
reduces_to_sql = False
|
||||
|
||||
def __init__(
|
||||
self, code, reverse_code=None, atomic=None, hints=None, elidable=False
|
||||
):
|
||||
def __init__(self, code, reverse_code=None, atomic=None, hints=None, elidable=False):
|
||||
self.atomic = atomic
|
||||
# Forwards code
|
||||
if not callable(code):
|
||||
@@ -160,15 +155,19 @@ class RunPython(Operation):
|
||||
|
||||
def deconstruct(self):
|
||||
kwargs = {
|
||||
"code": self.code,
|
||||
'code': self.code,
|
||||
}
|
||||
if self.reverse_code is not None:
|
||||
kwargs["reverse_code"] = self.reverse_code
|
||||
kwargs['reverse_code'] = self.reverse_code
|
||||
if self.atomic is not None:
|
||||
kwargs["atomic"] = self.atomic
|
||||
kwargs['atomic'] = self.atomic
|
||||
if self.hints:
|
||||
kwargs["hints"] = self.hints
|
||||
return (self.__class__.__qualname__, [], kwargs)
|
||||
kwargs['hints'] = self.hints
|
||||
return (
|
||||
self.__class__.__qualname__,
|
||||
[],
|
||||
kwargs
|
||||
)
|
||||
|
||||
@property
|
||||
def reversible(self):
|
||||
@@ -183,9 +182,7 @@ class RunPython(Operation):
|
||||
# RunPython has access to all models. Ensure that all models are
|
||||
# reloaded in case any are delayed.
|
||||
from_state.clear_delayed_apps_cache()
|
||||
if router.allow_migrate(
|
||||
schema_editor.connection.alias, app_label, **self.hints
|
||||
):
|
||||
if router.allow_migrate(schema_editor.connection.alias, app_label, **self.hints):
|
||||
# We now execute the Python code in a context that contains a 'models'
|
||||
# object, representing the versioned models as an app registry.
|
||||
# We could try to override the global cache, but then people will still
|
||||
@@ -195,9 +192,7 @@ class RunPython(Operation):
|
||||
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
||||
if self.reverse_code is None:
|
||||
raise NotImplementedError("You cannot reverse this operation")
|
||||
if router.allow_migrate(
|
||||
schema_editor.connection.alias, app_label, **self.hints
|
||||
):
|
||||
if router.allow_migrate(schema_editor.connection.alias, app_label, **self.hints):
|
||||
self.reverse_code(from_state.apps, schema_editor)
|
||||
|
||||
def describe(self):
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
from collections import namedtuple
|
||||
|
||||
from django.db.models.fields.related import RECURSIVE_RELATIONSHIP_CONSTANT
|
||||
|
||||
|
||||
def resolve_relation(model, app_label=None, model_name=None):
|
||||
"""
|
||||
Turn a model class or model reference string and return a model tuple.
|
||||
|
||||
app_label and model_name are used to resolve the scope of recursive and
|
||||
unscoped model relationship.
|
||||
"""
|
||||
if isinstance(model, str):
|
||||
if model == RECURSIVE_RELATIONSHIP_CONSTANT:
|
||||
if app_label is None or model_name is None:
|
||||
raise TypeError(
|
||||
'app_label and model_name must be provided to resolve '
|
||||
'recursive relationships.'
|
||||
)
|
||||
return app_label, model_name
|
||||
if '.' in model:
|
||||
app_label, model_name = model.split('.', 1)
|
||||
return app_label, model_name.lower()
|
||||
if app_label is None:
|
||||
raise TypeError(
|
||||
'app_label must be provided to resolve unscoped model '
|
||||
'relationships.'
|
||||
)
|
||||
return app_label, model.lower()
|
||||
return model._meta.app_label, model._meta.model_name
|
||||
|
||||
|
||||
FieldReference = namedtuple('FieldReference', 'to through')
|
||||
|
||||
|
||||
def field_references(
|
||||
model_tuple,
|
||||
field,
|
||||
reference_model_tuple,
|
||||
reference_field_name=None,
|
||||
reference_field=None,
|
||||
):
|
||||
"""
|
||||
Return either False or a FieldReference if `field` references provided
|
||||
context.
|
||||
|
||||
False positives can be returned if `reference_field_name` is provided
|
||||
without `reference_field` because of the introspection limitation it
|
||||
incurs. This should not be an issue when this function is used to determine
|
||||
whether or not an optimization can take place.
|
||||
"""
|
||||
remote_field = field.remote_field
|
||||
if not remote_field:
|
||||
return False
|
||||
references_to = None
|
||||
references_through = None
|
||||
if resolve_relation(remote_field.model, *model_tuple) == reference_model_tuple:
|
||||
to_fields = getattr(field, 'to_fields', None)
|
||||
if (
|
||||
reference_field_name is None or
|
||||
# Unspecified to_field(s).
|
||||
to_fields is None or
|
||||
# Reference to primary key.
|
||||
(None in to_fields and (reference_field is None or reference_field.primary_key)) or
|
||||
# Reference to field.
|
||||
reference_field_name in to_fields
|
||||
):
|
||||
references_to = (remote_field, to_fields)
|
||||
through = getattr(remote_field, 'through', None)
|
||||
if through and resolve_relation(through, *model_tuple) == reference_model_tuple:
|
||||
through_fields = remote_field.through_fields
|
||||
if (
|
||||
reference_field_name is None or
|
||||
# Unspecified through_fields.
|
||||
through_fields is None or
|
||||
# Reference to field.
|
||||
reference_field_name in through_fields
|
||||
):
|
||||
references_through = (remote_field, through_fields)
|
||||
if not (references_to or references_through):
|
||||
return False
|
||||
return FieldReference(references_to, references_through)
|
||||
|
||||
|
||||
def get_references(state, model_tuple, field_tuple=()):
|
||||
"""
|
||||
Generator of (model_state, name, field, reference) referencing
|
||||
provided context.
|
||||
|
||||
If field_tuple is provided only references to this particular field of
|
||||
model_tuple will be generated.
|
||||
"""
|
||||
for state_model_tuple, model_state in state.models.items():
|
||||
for name, field in model_state.fields.items():
|
||||
reference = field_references(state_model_tuple, field, model_tuple, *field_tuple)
|
||||
if reference:
|
||||
yield model_state, name, field, reference
|
||||
|
||||
|
||||
def field_is_referenced(state, model_tuple, field_tuple):
|
||||
"""Return whether `field_tuple` is referenced by any state models."""
|
||||
return next(get_references(state, model_tuple, field_tuple), None) is not None
|
||||
Reference in New Issue
Block a user