Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
D
django
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
django
Commits
42f8666f
Kaydet (Commit)
42f8666f
authored
Eki 16, 2013
tarafından
Andrew Godwin
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Improve migration optimizer to be able to optimize through other ops
üst
694d7da6
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
124 additions
and
5 deletions
+124
-5
base.py
django/db/migrations/operations/base.py
+12
-0
models.py
django/db/migrations/operations/models.py
+30
-0
optimizer.py
django/db/migrations/optimizer.py
+20
-5
test_optimizer.py
tests/migrations/test_optimizer.py
+62
-0
No files found.
django/db/migrations/operations/base.py
Dosyayı görüntüle @
42f8666f
...
...
@@ -64,6 +64,18 @@ class Operation(object):
"""
return
"
%
s:
%
s"
%
(
self
.
__class__
.
__name__
,
self
.
_constructor_args
)
def
references_model
(
self
,
name
,
app_label
=
None
):
"""
Returns True if there is a chance this operation references the given
model name (as a string), with an optional app label for accuracy.
Used for optimization. If in doubt, return True;
returning a false positive will merely make the optimizer a little
less efficient, while returning a false negative may result in an
unusable optimized migration.
"""
return
True
def
__repr__
(
self
):
return
"<
%
s
%
s
%
s>"
%
(
self
.
__class__
.
__name__
,
...
...
django/db/migrations/operations/models.py
Dosyayı görüntüle @
42f8666f
from
.base
import
Operation
from
django.utils
import
six
from
django.db
import
models
,
router
from
django.db.models.options
import
normalize_unique_together
from
django.db.migrations.state
import
ModelState
...
...
@@ -33,6 +34,23 @@ class CreateModel(Operation):
def
describe
(
self
):
return
"Create model
%
s"
%
(
self
.
name
,
)
def
references_model
(
self
,
name
,
app_label
=
None
):
strings_to_check
=
[
self
.
name
]
# Check we didn't inherit from the model
for
base
in
self
.
bases
:
if
isinstance
(
base
,
six
.
string_types
):
strings_to_check
.
append
(
base
.
split
(
"."
)[
-
1
])
# Check we have no FKs/M2Ms with it
for
fname
,
field
in
self
.
fields
:
if
field
.
rel
:
if
isinstance
(
field
.
rel
.
to
,
six
.
string_types
):
strings_to_check
.
append
(
field
.
rel
.
to
.
split
(
"."
)[
-
1
])
# Now go over all the strings and compare them
for
string
in
strings_to_check
:
if
string
.
lower
()
==
name
.
lower
():
return
True
return
False
def
__eq__
(
self
,
other
):
return
(
(
self
.
__class__
==
other
.
__class__
)
and
...
...
@@ -66,6 +84,9 @@ class DeleteModel(Operation):
if
router
.
allow_migrate
(
schema_editor
.
connection
.
alias
,
model
):
schema_editor
.
create_model
(
model
)
def
references_model
(
self
,
name
,
app_label
=
None
):
return
name
.
lower
()
==
self
.
name
.
lower
()
def
describe
(
self
):
return
"Delete model
%
s"
%
(
self
.
name
,
)
...
...
@@ -97,6 +118,9 @@ class AlterModelTable(Operation):
def
database_backwards
(
self
,
app_label
,
schema_editor
,
from_state
,
to_state
):
return
self
.
database_forwards
(
app_label
,
schema_editor
,
from_state
,
to_state
)
def
references_model
(
self
,
name
,
app_label
=
None
):
return
name
.
lower
()
==
self
.
name
.
lower
()
def
describe
(
self
):
return
"Rename table for
%
s to
%
s"
%
(
self
.
name
,
self
.
table
)
...
...
@@ -131,6 +155,9 @@ class AlterUniqueTogether(Operation):
def
database_backwards
(
self
,
app_label
,
schema_editor
,
from_state
,
to_state
):
return
self
.
database_forwards
(
app_label
,
schema_editor
,
from_state
,
to_state
)
def
references_model
(
self
,
name
,
app_label
=
None
):
return
name
.
lower
()
==
self
.
name
.
lower
()
def
describe
(
self
):
return
"Alter unique_together for
%
s (
%
s constraints)"
%
(
self
.
name
,
len
(
self
.
unique_together
))
...
...
@@ -164,5 +191,8 @@ class AlterIndexTogether(Operation):
def
database_backwards
(
self
,
app_label
,
schema_editor
,
from_state
,
to_state
):
return
self
.
database_forwards
(
app_label
,
schema_editor
,
from_state
,
to_state
)
def
references_model
(
self
,
name
,
app_label
=
None
):
return
name
.
lower
()
==
self
.
name
.
lower
()
def
describe
(
self
):
return
"Alter index_together for
%
s (
%
s constraints)"
%
(
self
.
name
,
len
(
self
.
index_together
))
django/db/migrations/optimizer.py
Dosyayı görüntüle @
42f8666f
...
...
@@ -11,7 +11,7 @@ class MigrationOptimizer(object):
nothing.
"""
def
optimize
(
self
,
operations
):
def
optimize
(
self
,
operations
,
app_label
=
None
):
"""
Main optimization entry point. Pass in a list of Operation instances,
get out a new list of Operation instances.
...
...
@@ -27,17 +27,20 @@ class MigrationOptimizer(object):
The inner loop is run until the starting list is the same as the result
list, and then the result is returned. This means that operation
optimization must be stable and always return an equal or shorter list.
The app_label argument is optional, but if you pass it you'll get more
efficient optimization.
"""
# Internal tracking variable for test assertions about # of loops
self
.
_iterations
=
0
while
True
:
result
=
self
.
optimize_inner
(
operations
)
result
=
self
.
optimize_inner
(
operations
,
app_label
)
self
.
_iterations
+=
1
if
result
==
operations
:
return
result
operations
=
result
def
optimize_inner
(
self
,
operations
):
def
optimize_inner
(
self
,
operations
,
app_label
=
None
):
"""
Inner optimization loop.
"""
...
...
@@ -52,7 +55,7 @@ class MigrationOptimizer(object):
new_operations
.
extend
(
operations
[
i
+
1
:
i
+
1
+
j
])
new_operations
.
extend
(
operations
[
i
+
j
+
2
:])
return
new_operations
if
not
self
.
can_optimize_through
(
operation
,
other
):
if
not
self
.
can_optimize_through
(
operation
,
other
,
app_label
):
new_operations
.
append
(
operation
)
break
else
:
...
...
@@ -95,10 +98,22 @@ class MigrationOptimizer(object):
#### THROUGH CHECKS ####
def
can_optimize_through
(
self
,
operation
,
other
):
def
can_optimize_through
(
self
,
operation
,
other
,
app_label
=
None
):
"""
Returns True if it's possible to optimize 'operation' with something
the other side of 'other'. This is possible if, for example, they
affect different models.
"""
MODEL_LEVEL_OPERATIONS
=
(
migrations
.
CreateModel
,
migrations
.
DeleteModel
,
migrations
.
AlterModelTable
,
migrations
.
AlterUniqueTogether
,
migrations
.
AlterIndexTogether
,
)
# If it's a model level operation, let it through if there's
# nothing that looks like a reference to us in 'other'.
if
isinstance
(
operation
,
MODEL_LEVEL_OPERATIONS
):
if
not
other
.
references_model
(
operation
.
name
,
app_label
):
return
True
return
False
tests/migrations/test_optimizer.py
Dosyayı görüntüle @
42f8666f
...
...
@@ -93,3 +93,65 @@ class OptimizerTests(TestCase):
],
[],
)
def
test_optimize_through_create
(
self
):
"""
We should be able to optimize away create/delete through a create or delete
of a different model, but only if the create operation does not mention the model
at all.
"""
# These should work
self
.
assertOptimizesTo
(
[
migrations
.
CreateModel
(
"Foo"
,
[(
"name"
,
models
.
CharField
(
max_length
=
255
))]),
migrations
.
CreateModel
(
"Bar"
,
[(
"size"
,
models
.
IntegerField
())]),
migrations
.
DeleteModel
(
"Foo"
),
],
[
migrations
.
CreateModel
(
"Bar"
,
[(
"size"
,
models
.
IntegerField
())]),
],
)
self
.
assertOptimizesTo
(
[
migrations
.
CreateModel
(
"Foo"
,
[(
"name"
,
models
.
CharField
(
max_length
=
255
))]),
migrations
.
CreateModel
(
"Bar"
,
[(
"size"
,
models
.
IntegerField
())]),
migrations
.
DeleteModel
(
"Bar"
),
migrations
.
DeleteModel
(
"Foo"
),
],
[],
)
self
.
assertOptimizesTo
(
[
migrations
.
CreateModel
(
"Foo"
,
[(
"name"
,
models
.
CharField
(
max_length
=
255
))]),
migrations
.
CreateModel
(
"Bar"
,
[(
"size"
,
models
.
IntegerField
())]),
migrations
.
DeleteModel
(
"Foo"
),
migrations
.
DeleteModel
(
"Bar"
),
],
[],
)
# This should not work - FK should block it
self
.
assertOptimizesTo
(
[
migrations
.
CreateModel
(
"Foo"
,
[(
"name"
,
models
.
CharField
(
max_length
=
255
))]),
migrations
.
CreateModel
(
"Bar"
,
[(
"other"
,
models
.
ForeignKey
(
"testapp.Foo"
))]),
migrations
.
DeleteModel
(
"Foo"
),
],
[
migrations
.
CreateModel
(
"Foo"
,
[(
"name"
,
models
.
CharField
(
max_length
=
255
))]),
migrations
.
CreateModel
(
"Bar"
,
[(
"other"
,
models
.
ForeignKey
(
"testapp.Foo"
))]),
migrations
.
DeleteModel
(
"Foo"
),
],
)
# This should not work - bases should block it
self
.
assertOptimizesTo
(
[
migrations
.
CreateModel
(
"Foo"
,
[(
"name"
,
models
.
CharField
(
max_length
=
255
))]),
migrations
.
CreateModel
(
"Bar"
,
[(
"size"
,
models
.
IntegerField
())],
bases
=
(
"testapp.Foo"
,
)),
migrations
.
DeleteModel
(
"Foo"
),
],
[
migrations
.
CreateModel
(
"Foo"
,
[(
"name"
,
models
.
CharField
(
max_length
=
255
))]),
migrations
.
CreateModel
(
"Bar"
,
[(
"size"
,
models
.
IntegerField
())],
bases
=
(
"testapp.Foo"
,
)),
migrations
.
DeleteModel
(
"Foo"
),
],
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment