Bläddra i källkod

Fixed #23879 -- Allowed model migration skip based on feature/vendor

Thanks Carl Meyer for the report and review, and Tim Graham for the
review.
Claude Paroz 10 år sedan
förälder
incheckning
8097e54832

+ 1 - 1
django/core/management/commands/migrate.py

@@ -268,7 +268,7 @@ class Command(BaseCommand):
                 deferred_sql = []
                 for app_name, model_list in manifest.items():
                     for model in model_list:
-                        if model._meta.proxy or not model._meta.managed:
+                        if not model._meta.can_migrate(connection):
                             continue
                         if self.verbosity >= 3:
                             self.stdout.write(

+ 1 - 1
django/db/backends/base/creation.py

@@ -106,7 +106,7 @@ class BaseDatabaseCreation(object):
         # Make a function to iteratively return every object
         def get_objects():
             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)):
                     queryset = model._default_manager.using(self.connection.alias).order_by(model._meta.pk.name)
                     for obj in queryset.iterator():

+ 1 - 1
django/db/migrations/operations/base.py

@@ -106,7 +106,7 @@ class Operation(object):
         This is a thin wrapper around router.allow_migrate_model() that
         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 router.allow_migrate_model(connection_alias, model)

+ 21 - 1
django/db/models/options.py

@@ -8,6 +8,7 @@ from itertools import chain
 from django.apps import apps
 from django.conf import settings
 from django.core.exceptions import FieldDoesNotExist
+from django.db import connections
 from django.db.models.fields import AutoField
 from django.db.models.fields.proxy import OrderWrt
 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',
                  'abstract', 'managed', 'proxy', 'swappable', 'auto_created',
                  '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):
@@ -111,6 +113,8 @@ class Options(object):
         self.get_latest_by = None
         self.order_with_respect_to = None
         self.db_tablespace = settings.DEFAULT_TABLESPACE
+        self.required_db_features = []
+        self.required_db_vendor = None
         self.meta = meta
         self.pk = None
         self.has_auto_field = False
@@ -337,6 +341,22 @@ class Options(object):
     def __str__(self):
         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
     def verbose_name_raw(self):
         """

+ 25 - 0
docs/ref/models/options.txt

@@ -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
     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``
 ------------------