mirror of
https://github.com/django/django.git
synced 2025-08-21 17:29:13 +00:00
Fixed #36377 -- Added hints support to CreateExtension and subclasses.
This commit is contained in:
parent
14fc2e9703
commit
5488530a27
1
AUTHORS
1
AUTHORS
@ -100,6 +100,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Anssi Kääriäinen <akaariai@gmail.com>
|
Anssi Kääriäinen <akaariai@gmail.com>
|
||||||
ant9000@netwise.it
|
ant9000@netwise.it
|
||||||
Anthony Briggs <anthony.briggs@gmail.com>
|
Anthony Briggs <anthony.briggs@gmail.com>
|
||||||
|
anthony sottile
|
||||||
Anthony Wright <ryow.college@gmail.com>
|
Anthony Wright <ryow.college@gmail.com>
|
||||||
Antoine Chéneau <antoine.cheneau@outlook.com>
|
Antoine Chéneau <antoine.cheneau@outlook.com>
|
||||||
Anton Samarchyan <desecho@gmail.com>
|
Anton Samarchyan <desecho@gmail.com>
|
||||||
|
@ -13,15 +13,16 @@ class CreateExtension(Operation):
|
|||||||
reversible = True
|
reversible = True
|
||||||
category = OperationCategory.ADDITION
|
category = OperationCategory.ADDITION
|
||||||
|
|
||||||
def __init__(self, name):
|
def __init__(self, name, hints=None):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
self.hints = hints or {}
|
||||||
|
|
||||||
def state_forwards(self, app_label, state):
|
def state_forwards(self, app_label, state):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
if schema_editor.connection.vendor != "postgresql" or not router.allow_migrate(
|
if schema_editor.connection.vendor != "postgresql" or not router.allow_migrate(
|
||||||
schema_editor.connection.alias, app_label
|
schema_editor.connection.alias, app_label, **self.hints
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
if not self.extension_exists(schema_editor, self.name):
|
if not self.extension_exists(schema_editor, self.name):
|
||||||
@ -42,7 +43,9 @@ class CreateExtension(Operation):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
if not router.allow_migrate(schema_editor.connection.alias, app_label):
|
if not router.allow_migrate(
|
||||||
|
schema_editor.connection.alias, app_label, **self.hints
|
||||||
|
):
|
||||||
return
|
return
|
||||||
if self.extension_exists(schema_editor, self.name):
|
if self.extension_exists(schema_editor, self.name):
|
||||||
schema_editor.execute(
|
schema_editor.execute(
|
||||||
@ -69,43 +72,43 @@ class CreateExtension(Operation):
|
|||||||
|
|
||||||
|
|
||||||
class BloomExtension(CreateExtension):
|
class BloomExtension(CreateExtension):
|
||||||
def __init__(self):
|
def __init__(self, hints=None):
|
||||||
self.name = "bloom"
|
super().__init__("bloom", hints=hints)
|
||||||
|
|
||||||
|
|
||||||
class BtreeGinExtension(CreateExtension):
|
class BtreeGinExtension(CreateExtension):
|
||||||
def __init__(self):
|
def __init__(self, hints=None):
|
||||||
self.name = "btree_gin"
|
super().__init__("btree_gin", hints=hints)
|
||||||
|
|
||||||
|
|
||||||
class BtreeGistExtension(CreateExtension):
|
class BtreeGistExtension(CreateExtension):
|
||||||
def __init__(self):
|
def __init__(self, hints=None):
|
||||||
self.name = "btree_gist"
|
super().__init__("btree_gist", hints=hints)
|
||||||
|
|
||||||
|
|
||||||
class CITextExtension(CreateExtension):
|
class CITextExtension(CreateExtension):
|
||||||
def __init__(self):
|
def __init__(self, hints=None):
|
||||||
self.name = "citext"
|
super().__init__("citext", hints=hints)
|
||||||
|
|
||||||
|
|
||||||
class CryptoExtension(CreateExtension):
|
class CryptoExtension(CreateExtension):
|
||||||
def __init__(self):
|
def __init__(self, hints=None):
|
||||||
self.name = "pgcrypto"
|
super().__init__("pgcrypto", hints=hints)
|
||||||
|
|
||||||
|
|
||||||
class HStoreExtension(CreateExtension):
|
class HStoreExtension(CreateExtension):
|
||||||
def __init__(self):
|
def __init__(self, hints=None):
|
||||||
self.name = "hstore"
|
super().__init__("hstore", hints=hints)
|
||||||
|
|
||||||
|
|
||||||
class TrigramExtension(CreateExtension):
|
class TrigramExtension(CreateExtension):
|
||||||
def __init__(self):
|
def __init__(self, hints=None):
|
||||||
self.name = "pg_trgm"
|
super().__init__("pg_trgm", hints=hints)
|
||||||
|
|
||||||
|
|
||||||
class UnaccentExtension(CreateExtension):
|
class UnaccentExtension(CreateExtension):
|
||||||
def __init__(self):
|
def __init__(self, hints=None):
|
||||||
self.name = "unaccent"
|
super().__init__("unaccent", hints=hints)
|
||||||
|
|
||||||
|
|
||||||
class NotInTransactionMixin:
|
class NotInTransactionMixin:
|
||||||
|
@ -41,7 +41,7 @@ them. In that case, connect to your Django database and run the query
|
|||||||
``CreateExtension``
|
``CreateExtension``
|
||||||
===================
|
===================
|
||||||
|
|
||||||
.. class:: CreateExtension(name)
|
.. class:: CreateExtension(name, hints=None)
|
||||||
|
|
||||||
An ``Operation`` subclass which installs a PostgreSQL extension. For common
|
An ``Operation`` subclass which installs a PostgreSQL extension. For common
|
||||||
extensions, use one of the more specific subclasses below.
|
extensions, use one of the more specific subclasses below.
|
||||||
@ -50,63 +50,135 @@ them. In that case, connect to your Django database and run the query
|
|||||||
|
|
||||||
This is a required argument. The name of the extension to be installed.
|
This is a required argument. The name of the extension to be installed.
|
||||||
|
|
||||||
|
.. attribute:: hints
|
||||||
|
|
||||||
|
.. versionadded:: 6.0
|
||||||
|
|
||||||
|
The optional ``hints`` argument will be passed as ``**hints`` to the
|
||||||
|
:meth:`allow_migrate` method of database routers to assist them in
|
||||||
|
:ref:`making routing decisions <topics-db-multi-db-hints>`.
|
||||||
|
|
||||||
``BloomExtension``
|
``BloomExtension``
|
||||||
==================
|
==================
|
||||||
|
|
||||||
.. class:: BloomExtension()
|
.. class:: BloomExtension(hints=None)
|
||||||
|
|
||||||
Installs the ``bloom`` extension.
|
Installs the ``bloom`` extension.
|
||||||
|
|
||||||
|
.. attribute:: hints
|
||||||
|
|
||||||
|
.. versionadded:: 6.0
|
||||||
|
|
||||||
|
The optional ``hints`` argument will be passed as ``**hints`` to the
|
||||||
|
:meth:`allow_migrate` method of database routers to assist them in
|
||||||
|
:ref:`making routing decisions <topics-db-multi-db-hints>`.
|
||||||
|
|
||||||
``BtreeGinExtension``
|
``BtreeGinExtension``
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
.. class:: BtreeGinExtension()
|
.. class:: BtreeGinExtension(hints=None)
|
||||||
|
|
||||||
Installs the ``btree_gin`` extension.
|
Installs the ``btree_gin`` extension.
|
||||||
|
|
||||||
|
.. attribute:: hints
|
||||||
|
|
||||||
|
.. versionadded:: 6.0
|
||||||
|
|
||||||
|
The optional ``hints`` argument will be passed as ``**hints`` to the
|
||||||
|
:meth:`allow_migrate` method of database routers to assist them in
|
||||||
|
:ref:`making routing decisions <topics-db-multi-db-hints>`.
|
||||||
|
|
||||||
``BtreeGistExtension``
|
``BtreeGistExtension``
|
||||||
======================
|
======================
|
||||||
|
|
||||||
.. class:: BtreeGistExtension()
|
.. class:: BtreeGistExtension(hints=None)
|
||||||
|
|
||||||
Installs the ``btree_gist`` extension.
|
Installs the ``btree_gist`` extension.
|
||||||
|
|
||||||
|
.. attribute:: hints
|
||||||
|
|
||||||
|
.. versionadded:: 6.0
|
||||||
|
|
||||||
|
The optional ``hints`` argument will be passed as ``**hints`` to the
|
||||||
|
:meth:`allow_migrate` method of database routers to assist them in
|
||||||
|
:ref:`making routing decisions <topics-db-multi-db-hints>`.
|
||||||
|
|
||||||
``CITextExtension``
|
``CITextExtension``
|
||||||
===================
|
===================
|
||||||
|
|
||||||
.. class:: CITextExtension()
|
.. class:: CITextExtension(hints=None)
|
||||||
|
|
||||||
Installs the ``citext`` extension.
|
Installs the ``citext`` extension.
|
||||||
|
|
||||||
|
.. attribute:: hints
|
||||||
|
|
||||||
|
.. versionadded:: 6.0
|
||||||
|
|
||||||
|
The optional ``hints`` argument will be passed as ``**hints`` to the
|
||||||
|
:meth:`allow_migrate` method of database routers to assist them in
|
||||||
|
:ref:`making routing decisions <topics-db-multi-db-hints>`.
|
||||||
|
|
||||||
``CryptoExtension``
|
``CryptoExtension``
|
||||||
===================
|
===================
|
||||||
|
|
||||||
.. class:: CryptoExtension()
|
.. class:: CryptoExtension(hints=None)
|
||||||
|
|
||||||
Installs the ``pgcrypto`` extension.
|
Installs the ``pgcrypto`` extension.
|
||||||
|
|
||||||
|
.. attribute:: hints
|
||||||
|
|
||||||
|
.. versionadded:: 6.0
|
||||||
|
|
||||||
|
The optional ``hints`` argument will be passed as ``**hints`` to the
|
||||||
|
:meth:`allow_migrate` method of database routers to assist them in
|
||||||
|
:ref:`making routing decisions <topics-db-multi-db-hints>`.
|
||||||
|
|
||||||
``HStoreExtension``
|
``HStoreExtension``
|
||||||
===================
|
===================
|
||||||
|
|
||||||
.. class:: HStoreExtension()
|
.. class:: HStoreExtension(hints=None)
|
||||||
|
|
||||||
Installs the ``hstore`` extension and also sets up the connection to
|
Installs the ``hstore`` extension and also sets up the connection to
|
||||||
interpret hstore data for possible use in subsequent migrations.
|
interpret hstore data for possible use in subsequent migrations.
|
||||||
|
|
||||||
|
.. attribute:: hints
|
||||||
|
|
||||||
|
.. versionadded:: 6.0
|
||||||
|
|
||||||
|
The optional ``hints`` argument will be passed as ``**hints`` to the
|
||||||
|
:meth:`allow_migrate` method of database routers to assist them in
|
||||||
|
:ref:`making routing decisions <topics-db-multi-db-hints>`.
|
||||||
|
|
||||||
``TrigramExtension``
|
``TrigramExtension``
|
||||||
====================
|
====================
|
||||||
|
|
||||||
.. class:: TrigramExtension()
|
.. class:: TrigramExtension(hints=None)
|
||||||
|
|
||||||
Installs the ``pg_trgm`` extension.
|
Installs the ``pg_trgm`` extension.
|
||||||
|
|
||||||
|
.. attribute:: hints
|
||||||
|
|
||||||
|
.. versionadded:: 6.0
|
||||||
|
|
||||||
|
The optional ``hints`` argument will be passed as ``**hints`` to the
|
||||||
|
:meth:`allow_migrate` method of database routers to assist them in
|
||||||
|
:ref:`making routing decisions <topics-db-multi-db-hints>`.
|
||||||
|
|
||||||
``UnaccentExtension``
|
``UnaccentExtension``
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
.. class:: UnaccentExtension()
|
.. class:: UnaccentExtension(hints=None)
|
||||||
|
|
||||||
Installs the ``unaccent`` extension.
|
Installs the ``unaccent`` extension.
|
||||||
|
|
||||||
|
.. attribute:: hints
|
||||||
|
|
||||||
|
.. versionadded:: 6.0
|
||||||
|
|
||||||
|
The optional ``hints`` argument will be passed as ``**hints`` to the
|
||||||
|
:meth:`allow_migrate` method of database routers to assist them in
|
||||||
|
:ref:`making routing decisions <topics-db-multi-db-hints>`.
|
||||||
|
|
||||||
.. _manage-postgresql-collations:
|
.. _manage-postgresql-collations:
|
||||||
|
|
||||||
Managing collations using migrations
|
Managing collations using migrations
|
||||||
|
@ -135,6 +135,14 @@ Minor features
|
|||||||
now include system checks to verify that ``django.contrib.postgres`` is an
|
now include system checks to verify that ``django.contrib.postgres`` is an
|
||||||
installed app.
|
installed app.
|
||||||
|
|
||||||
|
* The :class:`.CreateExtension`, :class:`.BloomExtension`,
|
||||||
|
:class:`.BtreeGinExtension`, :class:`.BtreeGistExtension`,
|
||||||
|
:class:`.CITextExtension`, :class:`.CryptoExtension`,
|
||||||
|
:class:`.HStoreExtension`, :class:`.TrigramExtension`, and
|
||||||
|
:class:`.UnaccentExtension` operations now support the optional ``hints``
|
||||||
|
parameter. This allows providing database hints to database routers to assist
|
||||||
|
them in :ref:`making routing decisions <topics-db-multi-db-hints>`.
|
||||||
|
|
||||||
:mod:`django.contrib.redirects`
|
:mod:`django.contrib.redirects`
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -238,6 +238,11 @@ class NoMigrationRouter:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class MigrateWhenHinted:
|
||||||
|
def allow_migrate(self, db, app_label, **hints):
|
||||||
|
return hints.get("a_hint", False)
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(connection.vendor == "postgresql", "PostgreSQL specific tests.")
|
@unittest.skipUnless(connection.vendor == "postgresql", "PostgreSQL specific tests.")
|
||||||
class CreateExtensionTests(PostgreSQLTestCase):
|
class CreateExtensionTests(PostgreSQLTestCase):
|
||||||
app_label = "test_allow_create_extention"
|
app_label = "test_allow_create_extention"
|
||||||
@ -289,6 +294,55 @@ class CreateExtensionTests(PostgreSQLTestCase):
|
|||||||
self.assertEqual(len(captured_queries), 2)
|
self.assertEqual(len(captured_queries), 2)
|
||||||
self.assertIn("DROP EXTENSION IF EXISTS", captured_queries[1]["sql"])
|
self.assertIn("DROP EXTENSION IF EXISTS", captured_queries[1]["sql"])
|
||||||
|
|
||||||
|
@override_settings(DATABASE_ROUTERS=[MigrateWhenHinted()])
|
||||||
|
def test_allow_migrate_based_on_hints(self):
|
||||||
|
operation_no_hints = CreateExtension("tablefunc")
|
||||||
|
self.assertEqual(operation_no_hints.hints, {})
|
||||||
|
|
||||||
|
operation_hints = CreateExtension("tablefunc", hints={"a_hint": True})
|
||||||
|
self.assertEqual(operation_hints.hints, {"a_hint": True})
|
||||||
|
|
||||||
|
project_state = ProjectState()
|
||||||
|
new_state = project_state.clone()
|
||||||
|
|
||||||
|
with (
|
||||||
|
CaptureQueriesContext(connection) as captured_queries,
|
||||||
|
connection.schema_editor(atomic=False) as editor,
|
||||||
|
):
|
||||||
|
operation_no_hints.database_forwards(
|
||||||
|
self.app_label, editor, project_state, new_state
|
||||||
|
)
|
||||||
|
self.assertEqual(len(captured_queries), 0)
|
||||||
|
|
||||||
|
with (
|
||||||
|
CaptureQueriesContext(connection) as captured_queries,
|
||||||
|
connection.schema_editor(atomic=False) as editor,
|
||||||
|
):
|
||||||
|
operation_no_hints.database_backwards(
|
||||||
|
self.app_label, editor, project_state, new_state
|
||||||
|
)
|
||||||
|
self.assertEqual(len(captured_queries), 0)
|
||||||
|
|
||||||
|
with (
|
||||||
|
CaptureQueriesContext(connection) as captured_queries,
|
||||||
|
connection.schema_editor(atomic=False) as editor,
|
||||||
|
):
|
||||||
|
operation_hints.database_forwards(
|
||||||
|
self.app_label, editor, project_state, new_state
|
||||||
|
)
|
||||||
|
self.assertEqual(len(captured_queries), 4)
|
||||||
|
self.assertIn("CREATE EXTENSION IF NOT EXISTS", captured_queries[1]["sql"])
|
||||||
|
|
||||||
|
with (
|
||||||
|
CaptureQueriesContext(connection) as captured_queries,
|
||||||
|
connection.schema_editor(atomic=False) as editor,
|
||||||
|
):
|
||||||
|
operation_hints.database_backwards(
|
||||||
|
self.app_label, editor, project_state, new_state
|
||||||
|
)
|
||||||
|
self.assertEqual(len(captured_queries), 2)
|
||||||
|
self.assertIn("DROP EXTENSION IF EXISTS", captured_queries[1]["sql"])
|
||||||
|
|
||||||
def test_create_existing_extension(self):
|
def test_create_existing_extension(self):
|
||||||
operation = BloomExtension()
|
operation = BloomExtension()
|
||||||
self.assertEqual(operation.migration_name_fragment, "create_extension_bloom")
|
self.assertEqual(operation.migration_name_fragment, "create_extension_bloom")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user