Skip to content

Commit

Permalink
INTPYTHON-509 add db_name parameter to parse_uri()
Browse files Browse the repository at this point in the history
  • Loading branch information
timgraham committed Feb 6, 2025
1 parent 75d42fa commit 28426f7
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 25 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/mongodb_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django_mongodb_backend import parse_uri

if mongodb_uri := os.getenv("MONGODB_URI"):
db_settings = parse_uri(mongodb_uri)
db_settings = parse_uri(mongodb_uri, db_name="dummy")

# Workaround for https://github.com/mongodb-labs/mongo-orchestration/issues/268
if db_settings["USER"] and db_settings["PASSWORD"]:
Expand Down
17 changes: 5 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,17 @@ $ django-admin startproject example --template https://github.com/mongodb-labs/d

### Connect to the database

Navigate to your `example/settings.py` file and find the variable named
`DATABASES` Replace the `DATABASES` variable with this:
Navigate to your `example/settings.py` file and replace the `DATABASES`
setting like so:

```python
DATABASES = {
"default": django_mongodb_backend.parse_uri("<CONNECTION_STRING_URI>"),
"default": django_mongodb_backend.parse_uri(
"<CONNECTION_STRING_URI>", db_name="example"
),
}
```

The MongoDB `<CONNECTION_STRING_URI>` must also specify a database for the
`parse_uri` function to work.
If not already included, make sure you provide a value for `<DATABASE_NAME>`
in your URI as shown in the example below:
```bash
mongodb+srv://myDatabaseUser:D1fficultP%[email protected]/<DATABASE_NAME>?retryWrites=true&w=majority
```


### Run the server
To verify that you installed Django MongoDB Backend and correctly configured your project, run the following command from your project root:
```bash
Expand Down
9 changes: 7 additions & 2 deletions django_mongodb_backend/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def check_django_compatability():
)


def parse_uri(uri, conn_max_age=0, test=None):
def parse_uri(uri, *, db_name=None, conn_max_age=0, test=None):
"""
Convert the given uri into a dictionary suitable for Django's DATABASES
setting.
Expand All @@ -45,16 +45,21 @@ def parse_uri(uri, conn_max_age=0, test=None):
host, port = nodelist[0]
elif len(nodelist) > 1:
host = ",".join([f"{host}:{port}" for host, port in nodelist])
db_name = db_name or uri["database"]
if not db_name:
raise ImproperlyConfigured("You must provide the db_name parameter.")
settings_dict = {
"ENGINE": "django_mongodb_backend",
"NAME": uri["database"],
"NAME": db_name,
"HOST": host,
"PORT": port,
"USER": uri.get("username"),
"PASSWORD": uri.get("password"),
"OPTIONS": uri.get("options"),
"CONN_MAX_AGE": conn_max_age,
}
if "authSource" not in settings_dict["OPTIONS"] and uri["database"]:
settings_dict["OPTIONS"]["authSource"] = uri["database"]
if test:
settings_dict["TEST"] = test
return settings_dict
Expand Down
49 changes: 39 additions & 10 deletions tests/backend_/utils/test_parse_uri.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from unittest.mock import patch

import pymongo
from django.core.exceptions import ImproperlyConfigured
from django.test import SimpleTestCase

from django_mongodb_backend import parse_uri
Expand All @@ -12,11 +13,28 @@ def test_simple_uri(self):
self.assertEqual(settings_dict["ENGINE"], "django_mongodb_backend")
self.assertEqual(settings_dict["NAME"], "myDatabase")
self.assertEqual(settings_dict["HOST"], "cluster0.example.mongodb.net")
self.assertEqual(settings_dict["OPTIONS"], {"authSource": "myDatabase"})

def test_no_database(self):
settings_dict = parse_uri("mongodb://cluster0.example.mongodb.net")
self.assertIsNone(settings_dict["NAME"])
def test_db_name(self):
settings_dict = parse_uri("mongodb://cluster0.example.mongodb.net/", db_name="myDatabase")
self.assertEqual(settings_dict["ENGINE"], "django_mongodb_backend")
self.assertEqual(settings_dict["NAME"], "myDatabase")
self.assertEqual(settings_dict["HOST"], "cluster0.example.mongodb.net")
self.assertEqual(settings_dict["OPTIONS"], {})

def test_db_name_overrides_default_auth_db(self):
settings_dict = parse_uri(
"mongodb://cluster0.example.mongodb.net/default_auth_db", db_name="myDatabase"
)
self.assertEqual(settings_dict["ENGINE"], "django_mongodb_backend")
self.assertEqual(settings_dict["NAME"], "myDatabase")
self.assertEqual(settings_dict["HOST"], "cluster0.example.mongodb.net")
self.assertEqual(settings_dict["OPTIONS"], {"authSource": "default_auth_db"})

def test_no_database(self):
msg = "You must provide the db_name parameter."
with self.assertRaisesMessage(ImproperlyConfigured, msg):
parse_uri("mongodb://cluster0.example.mongodb.net")

def test_srv_uri_with_options(self):
uri = "mongodb+srv://my_user:[email protected]/my_database?retryWrites=true&w=majority"
Expand All @@ -30,35 +48,46 @@ def test_srv_uri_with_options(self):
self.assertEqual(settings_dict["PASSWORD"], "my_password")
self.assertIsNone(settings_dict["PORT"])
self.assertEqual(
settings_dict["OPTIONS"], {"retryWrites": True, "w": "majority", "tls": True}
settings_dict["OPTIONS"],
{"authSource": "my_database", "retryWrites": True, "w": "majority", "tls": True},
)

def test_localhost(self):
settings_dict = parse_uri("mongodb://localhost")
settings_dict = parse_uri("mongodb://localhost/db")
self.assertEqual(settings_dict["HOST"], "localhost")
self.assertEqual(settings_dict["PORT"], 27017)

def test_localhost_with_port(self):
settings_dict = parse_uri("mongodb://localhost:27018")
settings_dict = parse_uri("mongodb://localhost:27018/db")
self.assertEqual(settings_dict["HOST"], "localhost")
self.assertEqual(settings_dict["PORT"], 27018)

def test_hosts_with_ports(self):
settings_dict = parse_uri("mongodb://localhost:27017,localhost:27018")
settings_dict = parse_uri("mongodb://localhost:27017,localhost:27018/db")
self.assertEqual(settings_dict["HOST"], "localhost:27017,localhost:27018")
self.assertEqual(settings_dict["PORT"], None)

def test_hosts_without_ports(self):
settings_dict = parse_uri("mongodb://host1.net,host2.net")
settings_dict = parse_uri("mongodb://host1.net,host2.net/db")
self.assertEqual(settings_dict["HOST"], "host1.net:27017,host2.net:27017")
self.assertEqual(settings_dict["PORT"], None)

def test_auth_source_in_query_string(self):
settings_dict = parse_uri("mongodb://localhost/?authSource=auth", db_name="db")
self.assertEqual(settings_dict["NAME"], "db")
self.assertEqual(settings_dict["OPTIONS"], {"authSource": "auth"})

def test_auth_source_in_query_string_overrides_defaultauthdb(self):
settings_dict = parse_uri("mongodb://localhost/db?authSource=auth")
self.assertEqual(settings_dict["NAME"], "db")
self.assertEqual(settings_dict["OPTIONS"], {"authSource": "auth"})

def test_conn_max_age(self):
settings_dict = parse_uri("mongodb://localhost", conn_max_age=600)
settings_dict = parse_uri("mongodb://localhost/db", conn_max_age=600)
self.assertEqual(settings_dict["CONN_MAX_AGE"], 600)

def test_test_kwarg(self):
settings_dict = parse_uri("mongodb://localhost", test={"NAME": "test_db"})
settings_dict = parse_uri("mongodb://localhost/db", test={"NAME": "test_db"})
self.assertEqual(settings_dict["TEST"], {"NAME": "test_db"})

def test_invalid_credentials(self):
Expand Down

0 comments on commit 28426f7

Please sign in to comment.