Fixed #32292 -- Added support for connection by service name to PostgreSQL.
This commit is contained in:
parent
f054468cac
commit
dcb3ad3319
|
@ -152,10 +152,14 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
|||
def get_connection_params(self):
|
||||
settings_dict = self.settings_dict
|
||||
# None may be used to connect to the default 'postgres' db
|
||||
if settings_dict['NAME'] == '':
|
||||
if (
|
||||
settings_dict['NAME'] == '' and
|
||||
not settings_dict.get('OPTIONS', {}).get('service')
|
||||
):
|
||||
raise ImproperlyConfigured(
|
||||
"settings.DATABASES is improperly configured. "
|
||||
"Please supply the NAME value.")
|
||||
"Please supply the NAME or OPTIONS['service'] value."
|
||||
)
|
||||
if len(settings_dict['NAME'] or '') > self.ops.max_name_length():
|
||||
raise ImproperlyConfigured(
|
||||
"The database name '%s' (%d characters) is longer than "
|
||||
|
@ -166,10 +170,19 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
|||
self.ops.max_name_length(),
|
||||
)
|
||||
)
|
||||
conn_params = {
|
||||
'database': settings_dict['NAME'] or 'postgres',
|
||||
**settings_dict['OPTIONS'],
|
||||
}
|
||||
conn_params = {}
|
||||
if settings_dict['NAME']:
|
||||
conn_params = {
|
||||
'database': settings_dict['NAME'],
|
||||
**settings_dict['OPTIONS'],
|
||||
}
|
||||
elif settings_dict['NAME'] is None:
|
||||
# Connect to the default 'postgres' db.
|
||||
settings_dict.get('OPTIONS', {}).pop('service', None)
|
||||
conn_params = {'database': 'postgres', **settings_dict['OPTIONS']}
|
||||
else:
|
||||
conn_params = {**settings_dict['OPTIONS']}
|
||||
|
||||
conn_params.pop('isolation_level', None)
|
||||
if settings_dict['USER']:
|
||||
conn_params['user'] = settings_dict['USER']
|
||||
|
|
|
@ -16,6 +16,7 @@ class DatabaseClient(BaseDatabaseClient):
|
|||
dbname = settings_dict.get('NAME') or 'postgres'
|
||||
user = settings_dict.get('USER')
|
||||
passwd = settings_dict.get('PASSWORD')
|
||||
service = options.get('service')
|
||||
sslmode = options.get('sslmode')
|
||||
sslrootcert = options.get('sslrootcert')
|
||||
sslcert = options.get('sslcert')
|
||||
|
@ -33,6 +34,8 @@ class DatabaseClient(BaseDatabaseClient):
|
|||
env = {}
|
||||
if passwd:
|
||||
env['PGPASSWORD'] = str(passwd)
|
||||
if service:
|
||||
env['PGSERVICE'] = str(service)
|
||||
if sslmode:
|
||||
env['PGSSLMODE'] = str(sslmode)
|
||||
if sslrootcert:
|
||||
|
|
|
@ -108,11 +108,43 @@ required, though the latest release is recommended.
|
|||
|
||||
.. _psycopg2: https://www.psycopg.org/
|
||||
|
||||
.. _postgresql-connection-settings:
|
||||
|
||||
PostgreSQL connection settings
|
||||
-------------------------------
|
||||
|
||||
See :setting:`HOST` for details.
|
||||
|
||||
To connect using a service name from the `connection service file`_, you must
|
||||
specify it in the :setting:`OPTIONS` part of your database configuration in
|
||||
:setting:`DATABASES`:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: settings.py
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql',
|
||||
'OPTIONS': {'service': 'my_service'},
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: text
|
||||
:caption: .pg_service.conf
|
||||
|
||||
[my_service]
|
||||
host=localhost
|
||||
user=USER
|
||||
dbname=NAME
|
||||
password=PASSWORD
|
||||
port=5432
|
||||
|
||||
.. _connection service file: https://www.postgresql.org/docs/current/libpq-pgservice.html
|
||||
|
||||
.. versionchanged:: 4.0
|
||||
|
||||
Support for connecting by a service name was added.
|
||||
|
||||
Optimizing PostgreSQL's configuration
|
||||
-------------------------------------
|
||||
|
||||
|
|
|
@ -64,7 +64,8 @@ Minor features
|
|||
:mod:`django.contrib.postgres`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* ...
|
||||
* The PostgreSQL backend now supports connecting by a service name. See
|
||||
:ref:`postgresql-connection-settings` for more details.
|
||||
|
||||
:mod:`django.contrib.redirects`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -68,6 +68,36 @@ class Tests(TestCase):
|
|||
with self.assertRaisesMessage(ImproperlyConfigured, msg):
|
||||
DatabaseWrapper(settings).get_connection_params()
|
||||
|
||||
def test_database_name_empty(self):
|
||||
from django.db.backends.postgresql.base import DatabaseWrapper
|
||||
settings = connection.settings_dict.copy()
|
||||
settings['NAME'] = ''
|
||||
msg = (
|
||||
"settings.DATABASES is improperly configured. Please supply the "
|
||||
"NAME or OPTIONS['service'] value."
|
||||
)
|
||||
with self.assertRaisesMessage(ImproperlyConfigured, msg):
|
||||
DatabaseWrapper(settings).get_connection_params()
|
||||
|
||||
def test_service_name(self):
|
||||
from django.db.backends.postgresql.base import DatabaseWrapper
|
||||
settings = connection.settings_dict.copy()
|
||||
settings['OPTIONS'] = {'service': 'my_service'}
|
||||
settings['NAME'] = ''
|
||||
params = DatabaseWrapper(settings).get_connection_params()
|
||||
self.assertEqual(params['service'], 'my_service')
|
||||
self.assertNotIn('database', params)
|
||||
|
||||
def test_service_name_default_db(self):
|
||||
# None is used to connect to the default 'postgres' db.
|
||||
from django.db.backends.postgresql.base import DatabaseWrapper
|
||||
settings = connection.settings_dict.copy()
|
||||
settings['NAME'] = None
|
||||
settings['OPTIONS'] = {'service': 'django_test'}
|
||||
params = DatabaseWrapper(settings).get_connection_params()
|
||||
self.assertEqual(params['database'], 'postgres')
|
||||
self.assertNotIn('service', params)
|
||||
|
||||
def test_connect_and_rollback(self):
|
||||
"""
|
||||
PostgreSQL shouldn't roll back SET TIME ZONE, even if the first
|
||||
|
|
|
@ -67,6 +67,12 @@ class PostgreSqlDbshellCommandTestCase(SimpleTestCase):
|
|||
)
|
||||
)
|
||||
|
||||
def test_service(self):
|
||||
self.assertEqual(
|
||||
self.settings_to_cmd_args_env({'OPTIONS': {'service': 'django_test'}}),
|
||||
(['psql', 'postgres'], {'PGSERVICE': 'django_test'}),
|
||||
)
|
||||
|
||||
def test_column(self):
|
||||
self.assertEqual(
|
||||
self.settings_to_cmd_args_env({
|
||||
|
|
Loading…
Reference in New Issue