|
| 1 | +.. include:: ./snippets/postgres_doc_links.rst |
| 2 | + |
| 3 | +.. _schemas_page: |
| 4 | + |
| 5 | +Schema |
| 6 | +====== |
| 7 | + |
| 8 | +The :meth:`~psqlextra.schema.PostgresSchema` class provides basic schema management functionality. |
| 9 | + |
| 10 | +Django does **NOT** support custom schemas. This module does not attempt to solve that problem. |
| 11 | + |
| 12 | +This module merely allows you to create/drop schemas and allow you to execute raw SQL in a schema. It is not attempt at bringing multi-schema support to Django. |
| 13 | + |
| 14 | + |
| 15 | +Reference an existing schema |
| 16 | +---------------------------- |
| 17 | + |
| 18 | +.. code-block:: python |
| 19 | +
|
| 20 | + for psqlextra.schema import PostgresSchema |
| 21 | +
|
| 22 | + schema = PostgresSchema("myschema") |
| 23 | +
|
| 24 | + with schema.connection.cursor() as cursor: |
| 25 | + cursor.execute("SELECT * FROM tablethatexistsinmyschema") |
| 26 | +
|
| 27 | +
|
| 28 | +Checking if a schema exists |
| 29 | +--------------------------- |
| 30 | +
|
| 31 | +.. code-block:: python |
| 32 | +
|
| 33 | + for psqlextra.schema import PostgresSchema |
| 34 | +
|
| 35 | + schema = PostgresSchema("myschema") |
| 36 | + if PostgresSchema.exists("myschema"): |
| 37 | + print("exists!") |
| 38 | + else: |
| 39 | + print('does not exist!") |
| 40 | +
|
| 41 | +
|
| 42 | +Creating a new schema |
| 43 | +--------------------- |
| 44 | +
|
| 45 | +With a custom name |
| 46 | +****************** |
| 47 | +
|
| 48 | +.. code-block:: python |
| 49 | +
|
| 50 | + for psqlextra.schema import PostgresSchema |
| 51 | +
|
| 52 | + # will raise an error if the schema already exists |
| 53 | + schema = PostgresSchema.create("myschema") |
| 54 | +
|
| 55 | +
|
| 56 | +Re-create if necessary with a custom name |
| 57 | +***************************************** |
| 58 | +
|
| 59 | +.. warning:: |
| 60 | +
|
| 61 | + If the schema already exists and it is non-empty or something is referencing it, it will **NOT** be dropped. Specify ``cascade=True`` to drop all of the schema's contents and **anything referencing it**. |
| 62 | +
|
| 63 | +.. code-block:: python |
| 64 | +
|
| 65 | + for psqlextra.schema import PostgresSchema |
| 66 | +
|
| 67 | + # will drop existing schema named `myschema` if it |
| 68 | + # exists and re-create it |
| 69 | + schema = PostgresSchema.drop_and_create("myschema") |
| 70 | +
|
| 71 | + # will drop the schema and cascade it to its contents |
| 72 | + # and anything referencing the schema |
| 73 | + schema = PostgresSchema.drop_and_create("otherschema", cascade=True) |
| 74 | +
|
| 75 | +
|
| 76 | +With a random name |
| 77 | +****************** |
| 78 | +
|
| 79 | +.. code-block:: python |
| 80 | +
|
| 81 | + for psqlextra.schema import PostgresSchema |
| 82 | +
|
| 83 | + # schema name will be "myprefix_<timestamp>" |
| 84 | + schema = PostgresSchema.create_random("myprefix") |
| 85 | + print(schema.name) |
| 86 | +
|
| 87 | +
|
| 88 | +Temporary schema with random name |
| 89 | +********************************* |
| 90 | +
|
| 91 | +Use the :meth:`~psqlextra.schema.postgres_temporary_schema` context manager to create a schema with a random name. The schema will only exist within the context manager. |
| 92 | +
|
| 93 | +By default, the schema is not dropped if an exception occurs in the context manager. This prevents unexpected data loss. Specify ``drop_on_throw=True`` to drop the schema if an exception occurs. |
| 94 | +
|
| 95 | +Without an outer transaction, the temporary schema might not be dropped when your program is exits unexpectedly (for example; if it is killed with SIGKILL). Wrap the creation of the schema in a transaction to make sure the schema is cleaned up when an error occurs or your program exits suddenly. |
| 96 | +
|
| 97 | +.. warning:: |
| 98 | +
|
| 99 | + By default, the drop will fail if the schema is not empty or there is anything referencing the schema. Specify ``cascade=True`` to drop all of the schema's contents and **anything referencing it**. |
| 100 | +
|
| 101 | +.. note:: |
| 102 | +
|
| 103 | +
|
| 104 | +.. code-block:: python |
| 105 | +
|
| 106 | + for psqlextra.schema import postgres_temporary_schema |
| 107 | +
|
| 108 | + with postgres_temporary_schema("myprefix") as schema: |
| 109 | + pass |
| 110 | +
|
| 111 | + with postgres_temporary_schema("otherprefix", drop_on_throw=True) as schema: |
| 112 | + raise ValueError("drop it like it's hot") |
| 113 | +
|
| 114 | + with postgres_temporary_schema("greatprefix", cascade=True) as schema: |
| 115 | + with schema.connection.cursor() as cursor: |
| 116 | + cursor.execute(f"CREATE TABLE {schema.name} AS SELECT 'hello'") |
| 117 | +
|
| 118 | + with postgres_temporary_schema("amazingprefix", drop_on_throw=True, cascade=True) as schema: |
| 119 | + with schema.connection.cursor() as cursor: |
| 120 | + cursor.execute(f"CREATE TABLE {schema.name} AS SELECT 'hello'") |
| 121 | +
|
| 122 | + raise ValueError("oops") |
| 123 | +
|
| 124 | +Deleting a schema |
| 125 | +----------------- |
| 126 | +
|
| 127 | +Any schema can be dropped, including ones not created by :class:`~psqlextra.schema.PostgresSchema`. |
| 128 | +
|
| 129 | +The ``public`` schema cannot be dropped. This is a Postgres built-in and it is almost always a mistake to drop it. A :class:`~django.core.exceptions.SuspiciousOperation` erorr will be raised if you attempt to drop the ``public`` schema. |
| 130 | +
|
| 131 | +.. warning:: |
| 132 | +
|
| 133 | + By default, the drop will fail if the schema is not empty or there is anything referencing the schema. Specify ``cascade=True`` to drop all of the schema's contents and **anything referencing it**. |
| 134 | +
|
| 135 | +.. code-block:: python |
| 136 | +
|
| 137 | + for psqlextra.schema import PostgresSchema |
| 138 | +
|
| 139 | + schema = PostgresSchema.drop("myprefix") |
| 140 | + schema = PostgresSchema.drop("myprefix", cascade=True) |
| 141 | +
|
| 142 | +
|
| 143 | +Executing queries within a schema |
| 144 | +--------------------------------- |
| 145 | +
|
| 146 | +By default, a connection operates in the ``public`` schema. The schema offers a connection scoped to that schema that sets the Postgres ``search_path`` to only search within that schema. |
| 147 | +
|
| 148 | +.. warning:: |
| 149 | +
|
| 150 | + This can be abused to manage Django models in a custom schema. This is not a supported workflow and there might be unexpected issues from attempting to do so. |
| 151 | +
|
| 152 | +.. warning:: |
| 153 | +
|
| 154 | + Do not pass the connection to a different thread. It is **NOT** thread safe. |
| 155 | +
|
| 156 | +.. code-block:: python |
| 157 | +
|
| 158 | + from psqlextra.schema import PostgresSchema |
| 159 | +
|
| 160 | + schema = PostgresSchema.create("myschema") |
| 161 | +
|
| 162 | + with schema.connection.cursor() as cursor: |
| 163 | + # table gets created within the `myschema` schema, without |
| 164 | + # explicitly specifying the schema name |
| 165 | + cursor.execute("CREATE TABLE mytable AS SELECT 'hello'") |
| 166 | +
|
| 167 | + with schema.connection.schema_editor() as schema_editor: |
| 168 | + # creates a table for the model within the schema |
| 169 | + schema_editor.create_model(MyModel) |
0 commit comments