Skip to content

Commit 8aca9ed

Browse files
committed
Allow using MongoDB connection string in DATABASES["HOST"]
1 parent 8dd7758 commit 8aca9ed

File tree

5 files changed

+53
-28
lines changed

5 files changed

+53
-28
lines changed

.github/workflows/mongodb_settings.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import os
22

3-
from django_mongodb_backend import parse_uri
3+
from pymongo.uri_parser import parse_uri
44

55
if mongodb_uri := os.getenv("MONGODB_URI"):
6-
db_settings = parse_uri(mongodb_uri, db_name="dummy")
7-
6+
db_settings = {
7+
"ENGINE": "django_mongodb_backend",
8+
"HOST": mongodb_uri,
9+
}
810
# Workaround for https://github.com/mongodb-labs/mongo-orchestration/issues/268
9-
if db_settings["USER"] and db_settings["PASSWORD"]:
10-
db_settings["OPTIONS"].update({"tls": True, "tlsAllowInvalidCertificates": True})
11+
uri = parse_uri(mongodb_uri)
12+
if uri.get("username") and uri.get("password"):
13+
db_settings["OPTIONS"] = {"tls": True, "tlsAllowInvalidCertificates": True}
1114
DATABASES = {
1215
"default": {**db_settings, "NAME": "djangotests"},
1316
"other": {**db_settings, "NAME": "djangotests-other"},

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,10 @@ setting like so:
4545

4646
```python
4747
DATABASES = {
48-
"default": django_mongodb_backend.parse_uri(
49-
"<CONNECTION_STRING_URI>", db_name="example"
50-
),
48+
"default": {
49+
"HOST": "<CONNECTION_STRING_URI>",
50+
"Name": "db_name",
51+
},
5152
}
5253
```
5354

django_mongodb_backend/base.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -185,13 +185,17 @@ def get_connection_params(self):
185185
settings_dict = self.settings_dict
186186
if not settings_dict["NAME"]:
187187
raise ImproperlyConfigured('settings.DATABASES is missing the "NAME" value.')
188-
return {
188+
params = {
189189
"host": settings_dict["HOST"] or None,
190-
"port": int(settings_dict["PORT"] or 27017),
191-
"username": settings_dict.get("USER"),
192-
"password": settings_dict.get("PASSWORD"),
193190
**settings_dict["OPTIONS"],
194191
}
192+
if user := settings_dict.get("USER"):
193+
params["username"] = user
194+
if password := settings_dict.get("PASSWORD"):
195+
params["password"] = password
196+
if port := settings_dict.get("PORT"):
197+
params["port"] = int(port)
198+
return params
195199

196200
@async_unsafe
197201
def get_new_connection(self, conn_params):

docs/source/intro/configure.rst

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,21 @@ to match the first two numbers from your version.)
105105
Configuring the ``DATABASES`` setting
106106
=====================================
107107

108-
After you've set up a project, configure Django's :setting:`DATABASES` setting
109-
similar to this::
108+
After you've set up a project, configure Django's :setting:`DATABASES` setting.
109+
110+
If you have a connection string, you can provide it like this::
111+
112+
DATABASES = {
113+
"default": {
114+
"ENGINE": "django_mongodb_backend",
115+
"HOST": "mongodb+srv://my_user:my_password@cluster0.example.mongodb.net/myDatabase?retryWrites=true&w=majority&tls=false",
116+
"NAME": "my_database",
117+
},
118+
}
119+
120+
Alternatively, you can separate the connection string so that your settings
121+
look more like what you usually see with Django. This constructs a
122+
:setting:`DATABASES` setting equivalent to the first example::
110123

111124
DATABASES = {
112125
"default": {
@@ -117,7 +130,6 @@ similar to this::
117130
"PASSWORD": "my_password",
118131
"PORT": 27017,
119132
"OPTIONS": {
120-
# Example:
121133
"retryWrites": "true",
122134
"w": "majority",
123135
"tls": "false",
@@ -128,8 +140,8 @@ similar to this::
128140
For a localhost configuration, you can omit :setting:`HOST` or specify
129141
``"HOST": "localhost"``.
130142

131-
:setting:`HOST` only needs a scheme prefix for SRV connections
132-
(``mongodb+srv://``). A ``mongodb://`` prefix is never required.
143+
If you provide a connection string in ``HOST``, any of the other values below
144+
will override the values in the connection string.
133145

134146
:setting:`OPTIONS` is an optional dictionary of parameters that will be passed
135147
to :class:`~pymongo.mongo_client.MongoClient`.
@@ -143,17 +155,6 @@ For a replica set or sharded cluster where you have multiple hosts, include
143155
all of them in :setting:`HOST`, e.g.
144156
``"mongodb://mongos0.example.com:27017,mongos1.example.com:27017"``.
145157

146-
Alternatively, if you prefer to simply paste in a MongoDB URI rather than parse
147-
it into the format above, you can use
148-
:func:`~django_mongodb_backend.utils.parse_uri`::
149-
150-
import django_mongodb_backend
151-
152-
MONGODB_URI = "mongodb+srv://my_user:my_password@cluster0.example.mongodb.net/myDatabase?retryWrites=true&w=majority&tls=false"
153-
DATABASES["default"] = django_mongodb_backend.parse_uri(MONGODB_URI)
154-
155-
This constructs a :setting:`DATABASES` setting equivalent to the first example.
156-
157158
.. _configuring-database-routers-setting:
158159

159160
Configuring the ``DATABASE_ROUTERS`` setting

tests/backend_/test_base.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,22 @@ def test_options(self):
5656
params = DatabaseWrapper(settings).get_connection_params()
5757
self.assertEqual(params["extra"], "option")
5858

59+
def test_unspecified_settings_omitted(self):
60+
settings = connection.settings_dict.copy()
61+
# django.db.utils.ConnectionHandler sets unspecified values to an empty
62+
# string.
63+
settings.update(
64+
{
65+
"USER": "",
66+
"PASSWORD": "",
67+
"PORT": "",
68+
}
69+
)
70+
params = DatabaseWrapper(settings).get_connection_params()
71+
self.assertNotIn("username", params)
72+
self.assertNotIn("password", params)
73+
self.assertNotIn("port", params)
74+
5975

6076
class DatabaseWrapperConnectionTests(TestCase):
6177
def test_set_autocommit(self):

0 commit comments

Comments
 (0)