Skip to content

Commit 455d2f3

Browse files
authored
Merge branch 'main' into mdb-8-auth-ssl-tests
2 parents 199e734 + 19ef748 commit 455d2f3

File tree

19 files changed

+248
-32
lines changed

19 files changed

+248
-32
lines changed

.github/workflows/release-python.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ jobs:
7676
with:
7777
name: all-dist-${{ github.run_id }}
7878
path: dist/
79+
- name: Publish package distributions to TestPyPI
80+
uses: pypa/gh-action-pypi-publish@release/v1
81+
with:
82+
repository-url: https://test.pypi.org/legacy/
83+
skip-existing: true
7984
- name: Publish package distributions to PyPI
8085
if: startsWith(inputs.dry_run, 'false')
8186
uses: pypa/gh-action-pypi-publish@release/v1
@@ -108,5 +113,4 @@ jobs:
108113
silk_asset_group: ${{ env.SILK_ASSET_GROUP }}
109114
evergreen_project: ${{ env.EVERGREEN_PROJECT }}
110115
token: ${{ github.token }}
111-
repository_url: https://test.pypi.org/legacy/
112116
dry_run: ${{ inputs.dry_run }}

django_mongodb_backend/fields/embedded_model.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,18 @@ def __init__(self, embedded_model, *args, **kwargs):
1818
super().__init__(*args, **kwargs)
1919

2020
def check(self, **kwargs):
21+
from ..models import EmbeddedModel
22+
2123
errors = super().check(**kwargs)
24+
if not issubclass(self.embedded_model, EmbeddedModel):
25+
return [
26+
checks.Error(
27+
"Embedded models must be a subclass of "
28+
"django_mongodb_backend.models.EmbeddedModel.",
29+
obj=self,
30+
id="django_mongodb_backend.embedded_model.E002",
31+
)
32+
]
2233
for field in self.embedded_model._meta.fields:
2334
if field.remote_field:
2435
errors.append(
@@ -27,7 +38,7 @@ def check(self, **kwargs):
2738
f"({self.embedded_model().__class__.__name__}.{field.name} "
2839
f"is a {field.__class__.__name__}).",
2940
obj=self,
30-
id="django_mongodb.embedded_model.E001",
41+
id="django_mongodb_backend.embedded_model.E001",
3142
)
3243
)
3344
return errors

django_mongodb_backend/managers.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,37 @@
1+
from django.db import NotSupportedError
12
from django.db.models.manager import BaseManager
23

34
from .queryset import MongoQuerySet
45

56

67
class MongoManager(BaseManager.from_queryset(MongoQuerySet)):
78
pass
9+
10+
11+
class EmbeddedModelManager(BaseManager):
12+
"""
13+
Prevent all queryset operations on embedded models since they don't have
14+
their own collection.
15+
16+
Raise a helpful error message for some basic QuerySet methods. Subclassing
17+
BaseManager means that other methods raise, e.g. AttributeError:
18+
'EmbeddedModelManager' object has no attribute 'update_or_create'".
19+
"""
20+
21+
def all(self):
22+
raise NotSupportedError("EmbeddedModels cannot be queried.")
23+
24+
def get(self, *args, **kwargs):
25+
raise NotSupportedError("EmbeddedModels cannot be queried.")
26+
27+
def filter(self, *args, **kwargs):
28+
raise NotSupportedError("EmbeddedModels cannot be queried.")
29+
30+
def create(self, **kwargs):
31+
raise NotSupportedError("EmbeddedModels cannot be created.")
32+
33+
def update(self, *args, **kwargs):
34+
raise NotSupportedError("EmbeddedModels cannot be updated.")
35+
36+
def delete(self):
37+
raise NotSupportedError("EmbeddedModels cannot be deleted.")

django_mongodb_backend/models.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from django.db import NotSupportedError, models
2+
3+
from .managers import EmbeddedModelManager
4+
5+
6+
class EmbeddedModel(models.Model):
7+
objects = EmbeddedModelManager()
8+
9+
class Meta:
10+
abstract = True
11+
12+
def delete(self, *args, **kwargs):
13+
raise NotSupportedError("EmbeddedModels cannot be deleted.")
14+
15+
def save(self, *args, **kwargs):
16+
raise NotSupportedError("EmbeddedModels cannot be saved.")

django_mongodb_backend/schema.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,24 @@
1010
from .utils import OperationCollector
1111

1212

13+
def ignore_embedded_models(func):
14+
"""
15+
Make a SchemaEditor method a no-op if model is an EmbeddedModel (unless
16+
parent_model isn't None, in which case this is a valid recursive operation
17+
such as adding an index on an embedded model's field).
18+
"""
19+
20+
def wrapper(self, model, *args, **kwargs):
21+
parent_model = kwargs.get("parent_model")
22+
from .models import EmbeddedModel
23+
24+
if issubclass(model, EmbeddedModel) and parent_model is None:
25+
return
26+
func(self, model, *args, **kwargs)
27+
28+
return wrapper
29+
30+
1331
class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
1432
def get_collection(self, name):
1533
if self.collect_sql:
@@ -22,6 +40,7 @@ def get_database(self):
2240
return self.connection.get_database()
2341

2442
@wrap_database_errors
43+
@ignore_embedded_models
2544
def create_model(self, model):
2645
self.get_database().create_collection(model._meta.db_table)
2746
self._create_model_indexes(model)
@@ -75,13 +94,15 @@ def _create_model_indexes(self, model, column_prefix="", parent_model=None):
7594
for index in model._meta.indexes:
7695
self.add_index(model, index, column_prefix=column_prefix, parent_model=parent_model)
7796

97+
@ignore_embedded_models
7898
def delete_model(self, model):
7999
# Delete implicit M2m tables.
80100
for field in model._meta.local_many_to_many:
81101
if field.remote_field.through._meta.auto_created:
82102
self.delete_model(field.remote_field.through)
83103
self.get_collection(model._meta.db_table).drop()
84104

105+
@ignore_embedded_models
85106
def add_field(self, model, field):
86107
# Create implicit M2M tables.
87108
if field.many_to_many and field.remote_field.through._meta.auto_created:
@@ -103,6 +124,7 @@ def add_field(self, model, field):
103124
elif self._field_should_have_unique(field):
104125
self._add_field_unique(model, field)
105126

127+
@ignore_embedded_models
106128
def _alter_field(
107129
self,
108130
model,
@@ -149,6 +171,7 @@ def _alter_field(
149171
if not old_field_unique and new_field_unique:
150172
self._add_field_unique(model, new_field)
151173

174+
@ignore_embedded_models
152175
def remove_field(self, model, field):
153176
# Remove implicit M2M tables.
154177
if field.many_to_many and field.remote_field.through._meta.auto_created:
@@ -210,6 +233,7 @@ def _remove_model_indexes(self, model, column_prefix="", parent_model=None):
210233
for index in model._meta.indexes:
211234
self.remove_index(parent_model or model, index)
212235

236+
@ignore_embedded_models
213237
def alter_index_together(self, model, old_index_together, new_index_together, column_prefix=""):
214238
olds = {tuple(fields) for fields in old_index_together}
215239
news = {tuple(fields) for fields in new_index_together}
@@ -222,6 +246,7 @@ def alter_index_together(self, model, old_index_together, new_index_together, co
222246
for field_names in news.difference(olds):
223247
self._add_composed_index(model, field_names, column_prefix=column_prefix)
224248

249+
@ignore_embedded_models
225250
def alter_unique_together(
226251
self, model, old_unique_together, new_unique_together, column_prefix="", parent_model=None
227252
):
@@ -249,6 +274,7 @@ def alter_unique_together(
249274
model, constraint, parent_model=parent_model, column_prefix=column_prefix
250275
)
251276

277+
@ignore_embedded_models
252278
def add_index(
253279
self, model, index, *, field=None, unique=False, column_prefix="", parent_model=None
254280
):
@@ -302,6 +328,7 @@ def _add_field_index(self, model, field, *, column_prefix=""):
302328
index.name = self._create_index_name(model._meta.db_table, [column_prefix + field.column])
303329
self.add_index(model, index, field=field, column_prefix=column_prefix)
304330

331+
@ignore_embedded_models
305332
def remove_index(self, model, index):
306333
if index.contains_expressions:
307334
return
@@ -355,6 +382,7 @@ def _remove_field_index(self, model, field, column_prefix=""):
355382
)
356383
collection.drop_index(index_names[0])
357384

385+
@ignore_embedded_models
358386
def add_constraint(self, model, constraint, field=None, column_prefix="", parent_model=None):
359387
if isinstance(constraint, UniqueConstraint) and self._unique_supported(
360388
condition=constraint.condition,
@@ -384,6 +412,7 @@ def _add_field_unique(self, model, field, column_prefix=""):
384412
constraint = UniqueConstraint(fields=[field.name], name=name)
385413
self.add_constraint(model, constraint, field=field, column_prefix=column_prefix)
386414

415+
@ignore_embedded_models
387416
def remove_constraint(self, model, constraint):
388417
if isinstance(constraint, UniqueConstraint) and self._unique_supported(
389418
condition=constraint.condition,
@@ -417,6 +446,7 @@ def _remove_field_unique(self, model, field, column_prefix=""):
417446
)
418447
self.get_collection(model._meta.db_table).drop_index(constraint_names[0])
419448

449+
@ignore_embedded_models
420450
def alter_db_table(self, model, old_db_table, new_db_table):
421451
if old_db_table == new_db_table:
422452
return

docs/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
# You can set these variables from the command line, and also
55
# from the environment for the first two.
6-
SPHINXOPTS ?=
6+
SPHINXOPTS ?= -n
77
SPHINXBUILD ?= sphinx-build
88
SOURCEDIR = source
99
BUILDDIR = build

docs/make.bat

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ if "%SPHINXBUILD%" == "" (
99
)
1010
set SOURCEDIR=source
1111
set BUILDDIR=build
12+
set SPHINXOPTS=-n
1213

1314
%SPHINXBUILD% >NUL 2>NUL
1415
if errorlevel 9009 (

docs/source/embedded-models.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
Embedded models
22
===============
33

4-
Use :class:`~django_mongdob.fields.EmbeddedModelField` to structure your data
5-
using `embedded documents
4+
Use :class:`~django_mongodb_backend.fields.EmbeddedModelField` to structure
5+
your data using `embedded documents
66
<https://www.mongodb.com/docs/manual/data-modeling/#embedded-data>`_.
77

88
The basics
@@ -11,13 +11,14 @@ The basics
1111
Let's consider this example::
1212

1313
from django_mongodb_backend.fields import EmbeddedModelField
14+
from django_mongodb_backend.models import EmbeddedModel
1415

1516
class Customer(models.Model):
1617
name = models.CharField(...)
1718
address = EmbeddedModelField("Address")
1819
...
1920

20-
class Address(models.Model):
21+
class Address(EmbeddedModel):
2122
...
2223
city = models.CharField(...)
2324

docs/source/fields.rst

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,11 @@ Stores a model of type ``embedded_model``.
222222

223223
This is a required argument.
224224

225-
Specifies the model class to embed. It can be either a concrete model
226-
class or a :ref:`lazy reference <lazy-relationships>` to a model class.
225+
Specifies the model class to embed. It must be a subclass of
226+
:class:`django_mongodb_backend.models.EmbeddedModel`.
227+
228+
It can be either a concrete model class or a :ref:`lazy reference
229+
<lazy-relationships>` to a model class.
227230

228231
The embedded model cannot have relational fields
229232
(:class:`~django.db.models.ForeignKey`,
@@ -234,11 +237,12 @@ Stores a model of type ``embedded_model``.
234237

235238
from django.db import models
236239
from django_mongodb_backend.fields import EmbeddedModelField
240+
from django_mongodb_backend.models import EmbeddedModel
237241

238-
class Address(models.Model):
242+
class Address(EmbeddedModel):
239243
...
240244

241-
class Author(models.Model):
245+
class Author(EmbeddedModel):
242246
address = EmbeddedModelField(Address)
243247

244248
class Book(models.Model):

docs/source/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ django-mongodb-backend 5.0.x documentation
88
fields
99
querysets
1010
forms
11+
models
1112
embedded-models
1213

1314
Indices and tables

0 commit comments

Comments
 (0)