mirror of
https://github.com/django/django.git
synced 2025-04-26 02:04:38 +00:00
Fixed #23879 -- Allowed model migration skip based on feature/vendor
Thanks Carl Meyer for the report and review, and Tim Graham for the review.
This commit is contained in:
parent
f043434174
commit
8097e54832
@ -268,7 +268,7 @@ class Command(BaseCommand):
|
|||||||
deferred_sql = []
|
deferred_sql = []
|
||||||
for app_name, model_list in manifest.items():
|
for app_name, model_list in manifest.items():
|
||||||
for model in model_list:
|
for model in model_list:
|
||||||
if model._meta.proxy or not model._meta.managed:
|
if not model._meta.can_migrate(connection):
|
||||||
continue
|
continue
|
||||||
if self.verbosity >= 3:
|
if self.verbosity >= 3:
|
||||||
self.stdout.write(
|
self.stdout.write(
|
||||||
|
@ -106,7 +106,7 @@ class BaseDatabaseCreation(object):
|
|||||||
# Make a function to iteratively return every object
|
# Make a function to iteratively return every object
|
||||||
def get_objects():
|
def get_objects():
|
||||||
for model in serializers.sort_dependencies(app_list):
|
for model in serializers.sort_dependencies(app_list):
|
||||||
if (not model._meta.proxy and model._meta.managed and
|
if (model._meta.can_migrate(self.connection) and
|
||||||
router.allow_migrate_model(self.connection.alias, model)):
|
router.allow_migrate_model(self.connection.alias, model)):
|
||||||
queryset = model._default_manager.using(self.connection.alias).order_by(model._meta.pk.name)
|
queryset = model._default_manager.using(self.connection.alias).order_by(model._meta.pk.name)
|
||||||
for obj in queryset.iterator():
|
for obj in queryset.iterator():
|
||||||
|
@ -106,7 +106,7 @@ class Operation(object):
|
|||||||
This is a thin wrapper around router.allow_migrate_model() that
|
This is a thin wrapper around router.allow_migrate_model() that
|
||||||
preemptively rejects any proxy, swapped out, or unmanaged model.
|
preemptively rejects any proxy, swapped out, or unmanaged model.
|
||||||
"""
|
"""
|
||||||
if model._meta.proxy or model._meta.swapped or not model._meta.managed:
|
if not model._meta.can_migrate(connection_alias):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return router.allow_migrate_model(connection_alias, model)
|
return router.allow_migrate_model(connection_alias, model)
|
||||||
|
@ -8,6 +8,7 @@ from itertools import chain
|
|||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import FieldDoesNotExist
|
from django.core.exceptions import FieldDoesNotExist
|
||||||
|
from django.db import connections
|
||||||
from django.db.models.fields import AutoField
|
from django.db.models.fields import AutoField
|
||||||
from django.db.models.fields.proxy import OrderWrt
|
from django.db.models.fields.proxy import OrderWrt
|
||||||
from django.db.models.fields.related import ManyToManyField
|
from django.db.models.fields.related import ManyToManyField
|
||||||
@ -36,7 +37,8 @@ DEFAULT_NAMES = ('verbose_name', 'verbose_name_plural', 'db_table', 'ordering',
|
|||||||
'order_with_respect_to', 'app_label', 'db_tablespace',
|
'order_with_respect_to', 'app_label', 'db_tablespace',
|
||||||
'abstract', 'managed', 'proxy', 'swappable', 'auto_created',
|
'abstract', 'managed', 'proxy', 'swappable', 'auto_created',
|
||||||
'index_together', 'apps', 'default_permissions',
|
'index_together', 'apps', 'default_permissions',
|
||||||
'select_on_save', 'default_related_name')
|
'select_on_save', 'default_related_name',
|
||||||
|
'required_db_features', 'required_db_vendor')
|
||||||
|
|
||||||
|
|
||||||
class raise_deprecation(object):
|
class raise_deprecation(object):
|
||||||
@ -111,6 +113,8 @@ class Options(object):
|
|||||||
self.get_latest_by = None
|
self.get_latest_by = None
|
||||||
self.order_with_respect_to = None
|
self.order_with_respect_to = None
|
||||||
self.db_tablespace = settings.DEFAULT_TABLESPACE
|
self.db_tablespace = settings.DEFAULT_TABLESPACE
|
||||||
|
self.required_db_features = []
|
||||||
|
self.required_db_vendor = None
|
||||||
self.meta = meta
|
self.meta = meta
|
||||||
self.pk = None
|
self.pk = None
|
||||||
self.has_auto_field = False
|
self.has_auto_field = False
|
||||||
@ -337,6 +341,22 @@ class Options(object):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s.%s" % (smart_text(self.app_label), smart_text(self.model_name))
|
return "%s.%s" % (smart_text(self.app_label), smart_text(self.model_name))
|
||||||
|
|
||||||
|
def can_migrate(self, connection):
|
||||||
|
"""
|
||||||
|
Return True if the model can/should be migrated on the `connection`.
|
||||||
|
`connection` can be either a real connection or a connection alias.
|
||||||
|
"""
|
||||||
|
if self.proxy or self.swapped or not self.managed:
|
||||||
|
return False
|
||||||
|
if isinstance(connection, six.string_types):
|
||||||
|
connection = connections[connection]
|
||||||
|
if self.required_db_vendor:
|
||||||
|
return self.required_db_vendor == connection.vendor
|
||||||
|
if self.required_db_features:
|
||||||
|
return all(getattr(connection.features, feat, False)
|
||||||
|
for feat in self.required_db_features)
|
||||||
|
return True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def verbose_name_raw(self):
|
def verbose_name_raw(self):
|
||||||
"""
|
"""
|
||||||
|
@ -283,6 +283,31 @@ Django quotes column and table names behind the scenes.
|
|||||||
If ``proxy = True``, a model which subclasses another model will be treated as
|
If ``proxy = True``, a model which subclasses another model will be treated as
|
||||||
a :ref:`proxy model <proxy-models>`.
|
a :ref:`proxy model <proxy-models>`.
|
||||||
|
|
||||||
|
``required_db_features``
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
.. attribute:: Options.required_db_features
|
||||||
|
|
||||||
|
.. versionadded:: 1.9
|
||||||
|
|
||||||
|
List of database features that the current connection should have so that
|
||||||
|
the model is considered during the migration phase. For example, if you set
|
||||||
|
this list to ``['gis_enabled']``, the model will only be synchronized on
|
||||||
|
GIS-enabled databases. It's also useful to skip some models when testing
|
||||||
|
with several database backends.
|
||||||
|
|
||||||
|
``required_db_vendor``
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
.. attribute:: Options.required_db_vendor
|
||||||
|
|
||||||
|
.. versionadded:: 1.9
|
||||||
|
|
||||||
|
Name of a supported database vendor that this model is specific to. Current
|
||||||
|
built-in vendor names are: ``sqlite``, ``postgresql``, ``mysql``,
|
||||||
|
``oracle``. If this attribute is not empty and the current connection vendor
|
||||||
|
doesn't match it, the model will not be synchronized.
|
||||||
|
|
||||||
``select_on_save``
|
``select_on_save``
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user