Commit 8097e548 authored by Claude Paroz's avatar Claude Paroz
Browse files

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

Thanks Carl Meyer for the report and review, and Tim Graham for the
review.
parent f0434341
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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``
------------------