Commit a42c5376 authored by Josep Cugat's avatar Josep Cugat Committed by Tim Graham
Browse files

[1.8.x] Fixed #25686 -- Fixed crash on routers without an allow_migrate() method.

Thanks Simon Charette for review.
parent 94d13415
Loading
Loading
Loading
Loading
+20 −15
Original line number Diff line number Diff line
@@ -326,30 +326,35 @@ class ConnectionRouter(object):
                    method = router.allow_migrate
                except AttributeError:
                    method = router.allow_syncdb
                    has_deprecated_signature = True
                    warnings.warn(
                        'Router.allow_syncdb has been deprecated and will stop working in Django 1.9. '
                        'Rename the method to allow_migrate.',
                        RemovedInDjango19Warning, stacklevel=2)
            except AttributeError:
                # If the router doesn't have a method, skip to the next one.
                continue

                else:
                    if HAS_INSPECT_SIGNATURE:
                sig = inspect.signature(router.allow_migrate)
                        sig = inspect.signature(method)
                        has_deprecated_signature = not any(
                            p.kind == inspect.Parameter.VAR_KEYWORD for p in sig.parameters.values()
                        )
                    else:
                argspec = inspect.getargspec(router.allow_migrate)
                        argspec = inspect.getargspec(method)
                        has_deprecated_signature = len(argspec.args) == 3 and not argspec.keywords

                    if has_deprecated_signature:
                        # Raised here because allow_syncdb has to be called with
                        # the deprecated signature but shouldn't show this
                        # warning (only the deprecated method one)
                        warnings.warn(
                            "The signature of allow_migrate has changed from "
                            "allow_migrate(self, db, model) to "
                            "allow_migrate(self, db, app_label, model_name=None, **hints). "
                            "Support for the old signature will be removed in Django 1.10.",
                            RemovedInDjango110Warning)
            except AttributeError:
                # If the router doesn't have a method, skip to the next one.
                continue

            if has_deprecated_signature:
                model = hints.get('model')
                allow = None if model is None else method(db, model)
            else:
+2 −1
Original line number Diff line number Diff line
@@ -12,4 +12,5 @@ Bugfixes
* Fixed a crash of the debug view during the autumn DST change when
  :setting:`USE_TZ` is ``False`` and ``pytz`` is installed.

* ...
* Fixed a regression in 1.8.6 that caused database routers without an
  ``allow_migrate()`` method to crash (:ticket:`25686`).
+21 −0
Original line number Diff line number Diff line
@@ -956,6 +956,27 @@ class RouterTestCase(TestCase):
                self.assertTrue(router.allow_migrate('default', 'app_label'))
                self.assertEqual(force_text(recorded.pop().message), msg)

    def test_allow_syncdb_deprecation(self):
        class LegacyRouter(object):
            def allow_syncdb(self, db, model):
                assert db == 'default'
                assert model is User
                return True

        with override_settings(DATABASE_ROUTERS=[LegacyRouter()]):
            with warnings.catch_warnings(record=True) as recorded:
                warnings.filterwarnings('always')
                msg = (
                    "Router.allow_syncdb has been deprecated and will stop "
                    "working in Django 1.9. Rename the method to allow_migrate."
                )
                self.assertTrue(router.allow_migrate_model('default', User))
                self.assertEqual(force_text(recorded.pop().message), msg)
                self.assertEqual(recorded, [])

                self.assertTrue(router.allow_migrate('default', 'app_label'))
                self.assertEqual(force_text(recorded.pop().message), msg)

    def test_partial_router(self):
        "A router can choose to implement a subset of methods"
        dive = Book.objects.using('other').create(title="Dive into Python",