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
f179113e
Unverified
Kaydet (Commit)
f179113e
authored
Ara 18, 2015
tarafından
Simon Charette
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Fixed #24067 -- Renamed content types upon model renaming.
Thanks to Tim for the extensive review.
üst
354acd04
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
198 additions
and
11 deletions
+198
-11
apps.py
django/contrib/contenttypes/apps.py
+5
-2
management.py
django/contrib/contenttypes/management.py
+83
-1
0001_initial.py
.../contenttypes_tests/operations_migrations/0001_initial.py
+34
-0
__init__.py
tests/contenttypes_tests/operations_migrations/__init__.py
+0
-0
tests.py
tests/contenttypes_tests/tests.py
+76
-8
No files found.
django/contrib/contenttypes/apps.py
Dosyayı görüntüle @
f179113e
from
django.apps
import
AppConfig
from
django.contrib.contenttypes.checks
import
check_generic_foreign_keys
from
django.core
import
checks
from
django.db.models.signals
import
post_migrate
from
django.db.models.signals
import
post_migrate
,
pre_migrate
from
django.utils.translation
import
ugettext_lazy
as
_
from
.management
import
update_contenttypes
from
.management
import
(
inject_rename_contenttypes_operations
,
update_contenttypes
,
)
class
ContentTypesConfig
(
AppConfig
):
...
...
@@ -12,5 +14,6 @@ class ContentTypesConfig(AppConfig):
verbose_name
=
_
(
"Content Types"
)
def
ready
(
self
):
pre_migrate
.
connect
(
inject_rename_contenttypes_operations
,
sender
=
self
)
post_migrate
.
connect
(
update_contenttypes
)
checks
.
register
(
check_generic_foreign_keys
,
checks
.
Tags
.
models
)
django/contrib/contenttypes/management.py
Dosyayı görüntüle @
f179113e
from
django.apps
import
apps
as
global_apps
from
django.db
import
DEFAULT_DB_ALIAS
,
router
from
django.db
import
DEFAULT_DB_ALIAS
,
migrations
,
router
,
transaction
from
django.db.utils
import
IntegrityError
from
django.utils
import
six
from
django.utils.six.moves
import
input
class
RenameContentType
(
migrations
.
RunPython
):
def
__init__
(
self
,
app_label
,
old_model
,
new_model
):
self
.
app_label
=
app_label
self
.
old_model
=
old_model
self
.
new_model
=
new_model
super
(
RenameContentType
,
self
)
.
__init__
(
self
.
rename_forward
,
self
.
rename_backward
)
def
_rename
(
self
,
apps
,
schema_editor
,
old_model
,
new_model
):
ContentType
=
apps
.
get_model
(
'contenttypes'
,
'ContentType'
)
db
=
schema_editor
.
connection
.
alias
if
not
router
.
allow_migrate_model
(
db
,
ContentType
):
return
try
:
content_type
=
ContentType
.
objects
.
db_manager
(
db
)
.
get_by_natural_key
(
self
.
app_label
,
old_model
)
except
ContentType
.
DoesNotExist
:
pass
else
:
content_type
.
model
=
new_model
try
:
with
transaction
.
atomic
(
using
=
db
):
content_type
.
save
(
update_fields
=
{
'model'
})
except
IntegrityError
:
# Gracefully fallback if a stale content type causes a
# conflict as update_contenttypes will take care of asking the
# user what should be done next.
content_type
.
model
=
old_model
else
:
# Clear the cache as the `get_by_natual_key()` call will cache
# the renamed ContentType instance by its old model name.
ContentType
.
objects
.
clear_cache
()
def
rename_forward
(
self
,
apps
,
schema_editor
):
self
.
_rename
(
apps
,
schema_editor
,
self
.
old_model
,
self
.
new_model
)
def
rename_backward
(
self
,
apps
,
schema_editor
):
self
.
_rename
(
apps
,
schema_editor
,
self
.
new_model
,
self
.
old_model
)
def
inject_rename_contenttypes_operations
(
plan
=
None
,
apps
=
global_apps
,
using
=
DEFAULT_DB_ALIAS
,
**
kwargs
):
"""
Insert a `RenameContentType` operation after every planned `RenameModel`
operation.
"""
if
plan
is
None
:
return
# Determine whether or not the ContentType model is available.
try
:
ContentType
=
apps
.
get_model
(
'contenttypes'
,
'ContentType'
)
except
LookupError
:
available
=
False
else
:
if
not
router
.
allow_migrate_model
(
using
,
ContentType
):
return
available
=
True
for
migration
,
backward
in
plan
:
if
((
migration
.
app_label
,
migration
.
name
)
==
(
'contenttypes'
,
'0001_initial'
)):
# There's no point in going forward if the initial contenttypes
# migration is unapplied as the ContentType model will be
# unavailable from this point.
if
backward
:
break
else
:
available
=
True
continue
# The ContentType model is not available yet.
if
not
available
:
continue
inserts
=
[]
for
index
,
operation
in
enumerate
(
migration
.
operations
):
if
isinstance
(
operation
,
migrations
.
RenameModel
):
operation
=
RenameContentType
(
migration
.
app_label
,
operation
.
old_name_lower
,
operation
.
new_name_lower
)
inserts
.
append
((
index
+
1
,
operation
))
for
inserted
,
(
index
,
operation
)
in
enumerate
(
inserts
):
migration
.
operations
.
insert
(
inserted
+
index
,
operation
)
def
update_contenttypes
(
app_config
,
verbosity
=
2
,
interactive
=
True
,
using
=
DEFAULT_DB_ALIAS
,
apps
=
global_apps
,
**
kwargs
):
"""
Creates content types for models in the given app, removing any model
...
...
tests/contenttypes_tests/operations_migrations/0001_initial.py
0 → 100644
Dosyayı görüntüle @
f179113e
# -*- coding: utf-8 -*-
from
__future__
import
unicode_literals
from
django.db
import
migrations
,
models
def
assert_foo_contenttype_not_cached
(
apps
,
schema_editor
):
ContentType
=
apps
.
get_model
(
'contenttypes'
,
'ContentType'
)
try
:
content_type
=
ContentType
.
objects
.
get_by_natural_key
(
'contenttypes_tests'
,
'foo'
)
except
ContentType
.
DoesNotExist
:
pass
else
:
if
not
ContentType
.
objects
.
filter
(
app_label
=
'contenttypes_tests'
,
model
=
'foo'
)
.
exists
():
raise
AssertionError
(
'The contenttypes_tests.Foo ContentType should not be cached.'
)
elif
content_type
.
model
!=
'foo'
:
raise
AssertionError
(
"The cached contenttypes_tests.Foo ContentType should have "
"its model set to 'foo'."
)
class
Migration
(
migrations
.
Migration
):
operations
=
[
migrations
.
CreateModel
(
'Foo'
,
[
(
'id'
,
models
.
AutoField
(
primary_key
=
True
)),
],
),
migrations
.
RenameModel
(
'Foo'
,
'RenamedFoo'
),
migrations
.
RunPython
(
assert_foo_contenttype_not_cached
,
migrations
.
RunPython
.
noop
)
]
tests/contenttypes_tests/operations_migrations/__init__.py
0 → 100644
Dosyayı görüntüle @
f179113e
tests/contenttypes_tests/tests.py
Dosyayı görüntüle @
f179113e
...
...
@@ -4,15 +4,18 @@ from __future__ import unicode_literals
import
datetime
from
django.apps.registry
import
Apps
,
apps
from
django.contrib.contenttypes
import
management
from
django.conf
import
settings
from
django.contrib.contenttypes
import
management
as
contenttypes_management
from
django.contrib.contenttypes.fields
import
(
GenericForeignKey
,
GenericRelation
,
)
from
django.contrib.contenttypes.models
import
ContentType
from
django.contrib.sites.models
import
Site
from
django.core
import
checks
from
django.db
import
connections
,
models
from
django.test
import
SimpleTestCase
,
TestCase
,
mock
,
override_settings
from
django.core
import
checks
,
management
from
django.db
import
connections
,
migrations
,
models
from
django.test
import
(
SimpleTestCase
,
TestCase
,
TransactionTestCase
,
mock
,
override_settings
,
)
from
django.test.utils
import
captured_stdout
,
isolate_apps
from
django.utils.encoding
import
force_str
,
force_text
...
...
@@ -388,9 +391,9 @@ class UpdateContentTypesTests(TestCase):
interactive mode of update_contenttypes() (the default) should delete
stale contenttypes.
"""
management
.
input
=
lambda
x
:
force_str
(
"yes"
)
contenttypes_
management
.
input
=
lambda
x
:
force_str
(
"yes"
)
with
captured_stdout
()
as
stdout
:
management
.
update_contenttypes
(
self
.
app_config
)
contenttypes_
management
.
update_contenttypes
(
self
.
app_config
)
self
.
assertIn
(
"Deleting stale content type"
,
stdout
.
getvalue
())
self
.
assertEqual
(
ContentType
.
objects
.
count
(),
self
.
before_count
)
...
...
@@ -400,7 +403,7 @@ class UpdateContentTypesTests(TestCase):
content types.
"""
with
captured_stdout
()
as
stdout
:
management
.
update_contenttypes
(
self
.
app_config
,
interactive
=
False
)
contenttypes_
management
.
update_contenttypes
(
self
.
app_config
,
interactive
=
False
)
self
.
assertIn
(
"Stale content types remain."
,
stdout
.
getvalue
())
self
.
assertEqual
(
ContentType
.
objects
.
count
(),
self
.
before_count
+
1
)
...
...
@@ -411,7 +414,7 @@ class UpdateContentTypesTests(TestCase):
"""
apps
=
Apps
()
with
self
.
assertNumQueries
(
0
):
management
.
update_contenttypes
(
self
.
app_config
,
interactive
=
False
,
verbosity
=
0
,
apps
=
apps
)
contenttypes_
management
.
update_contenttypes
(
self
.
app_config
,
interactive
=
False
,
verbosity
=
0
,
apps
=
apps
)
self
.
assertEqual
(
ContentType
.
objects
.
count
(),
self
.
before_count
+
1
)
...
...
@@ -445,3 +448,68 @@ class ContentTypesMultidbTestCase(TestCase):
with
self
.
assertNumQueries
(
0
,
using
=
'default'
),
\
self
.
assertNumQueries
(
1
,
using
=
'other'
):
ContentType
.
objects
.
get_for_model
(
Author
)
@override_settings
(
MIGRATION_MODULES
=
dict
(
settings
.
MIGRATION_MODULES
,
contenttypes_tests
=
'contenttypes_tests.operations_migrations'
),
)
class
ContentTypeOperationsTests
(
TransactionTestCase
):
available_apps
=
[
'django.contrib.contenttypes'
,
'contenttypes_tests'
]
def
setUp
(
self
):
app_config
=
apps
.
get_app_config
(
'contenttypes_tests'
)
models
.
signals
.
post_migrate
.
connect
(
self
.
assertOperationsInjected
,
sender
=
app_config
)
def
tearDown
(
self
):
app_config
=
apps
.
get_app_config
(
'contenttypes_tests'
)
models
.
signals
.
post_migrate
.
disconnect
(
self
.
assertOperationsInjected
,
sender
=
app_config
)
def
assertOperationsInjected
(
self
,
plan
,
**
kwargs
):
for
migration
,
_backward
in
plan
:
operations
=
iter
(
migration
.
operations
)
for
operation
in
operations
:
if
isinstance
(
operation
,
migrations
.
RenameModel
):
next_operation
=
next
(
operations
)
self
.
assertIsInstance
(
next_operation
,
contenttypes_management
.
RenameContentType
)
self
.
assertEqual
(
next_operation
.
app_label
,
migration
.
app_label
)
self
.
assertEqual
(
next_operation
.
old_model
,
operation
.
old_name_lower
)
self
.
assertEqual
(
next_operation
.
new_model
,
operation
.
new_name_lower
)
def
test_existing_content_type_rename
(
self
):
ContentType
.
objects
.
create
(
app_label
=
'contenttypes_tests'
,
model
=
'foo'
)
management
.
call_command
(
'migrate'
,
'contenttypes_tests'
,
database
=
'default'
,
interactive
=
False
,
verbosity
=
0
,
)
self
.
assertFalse
(
ContentType
.
objects
.
filter
(
app_label
=
'contenttypes_tests'
,
model
=
'foo'
)
.
exists
())
self
.
assertTrue
(
ContentType
.
objects
.
filter
(
app_label
=
'contenttypes_tests'
,
model
=
'renamedfoo'
)
.
exists
())
management
.
call_command
(
'migrate'
,
'contenttypes_tests'
,
'zero'
,
database
=
'default'
,
interactive
=
False
,
verbosity
=
0
,
)
self
.
assertTrue
(
ContentType
.
objects
.
filter
(
app_label
=
'contenttypes_tests'
,
model
=
'foo'
)
.
exists
())
self
.
assertFalse
(
ContentType
.
objects
.
filter
(
app_label
=
'contenttypes_tests'
,
model
=
'renamedfoo'
)
.
exists
())
def
test_missing_content_type_rename_ignore
(
self
):
management
.
call_command
(
'migrate'
,
'contenttypes_tests'
,
database
=
'default'
,
interactive
=
False
,
verbosity
=
0
,
)
self
.
assertFalse
(
ContentType
.
objects
.
filter
(
app_label
=
'contenttypes_tests'
,
model
=
'foo'
)
.
exists
())
self
.
assertTrue
(
ContentType
.
objects
.
filter
(
app_label
=
'contenttypes_tests'
,
model
=
'renamedfoo'
)
.
exists
())
management
.
call_command
(
'migrate'
,
'contenttypes_tests'
,
'zero'
,
database
=
'default'
,
interactive
=
False
,
verbosity
=
0
,
)
self
.
assertTrue
(
ContentType
.
objects
.
filter
(
app_label
=
'contenttypes_tests'
,
model
=
'foo'
)
.
exists
())
self
.
assertFalse
(
ContentType
.
objects
.
filter
(
app_label
=
'contenttypes_tests'
,
model
=
'renamedfoo'
)
.
exists
())
def
test_content_type_rename_conflict
(
self
):
ContentType
.
objects
.
create
(
app_label
=
'contenttypes_tests'
,
model
=
'foo'
)
ContentType
.
objects
.
create
(
app_label
=
'contenttypes_tests'
,
model
=
'renamedfoo'
)
management
.
call_command
(
'migrate'
,
'contenttypes_tests'
,
database
=
'default'
,
interactive
=
False
,
verbosity
=
0
,
)
self
.
assertTrue
(
ContentType
.
objects
.
filter
(
app_label
=
'contenttypes_tests'
,
model
=
'foo'
)
.
exists
())
self
.
assertTrue
(
ContentType
.
objects
.
filter
(
app_label
=
'contenttypes_tests'
,
model
=
'renamedfoo'
)
.
exists
())
management
.
call_command
(
'migrate'
,
'contenttypes_tests'
,
'zero'
,
database
=
'default'
,
interactive
=
False
,
verbosity
=
0
,
)
self
.
assertTrue
(
ContentType
.
objects
.
filter
(
app_label
=
'contenttypes_tests'
,
model
=
'foo'
)
.
exists
())
self
.
assertTrue
(
ContentType
.
objects
.
filter
(
app_label
=
'contenttypes_tests'
,
model
=
'renamedfoo'
)
.
exists
())
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