diff options
| author | Ananthu C V <weepingclown@disroot.org> | 2024-03-12 00:29:40 +0530 |
|---|---|---|
| committer | git-ubuntu importer <ubuntu-devel-discuss@lists.ubuntu.com> | 2024-03-22 04:35:23 +0000 |
| commit | 78ab29bd8d914f4c96246eaa0cc836644117d3be (patch) | |
| tree | 85bdea8757fe2585fba606b6551eeeb453a2215c | |
| parent | 82cf83cbd298561bde168ef6a521c0e923730359 (diff) | |
0.28.2-1 (patches unapplied)import/0.28.2-1ubuntu/oracular-proposedubuntu/oracular-develubuntu/oracular
Imported using git-ubuntu import.
Notes
Notes:
* Team upload
* New upstream version 0.28.2
* Drop upstream merged patch
| -rw-r--r-- | PKG-INFO | 6 | ||||
| -rw-r--r-- | README.rst | 2 | ||||
| -rw-r--r-- | debian/changelog | 8 | ||||
| -rw-r--r-- | debian/patches/0002-add-missing-doc-link.patch | 14 | ||||
| -rw-r--r-- | debian/patches/series | 1 | ||||
| -rw-r--r-- | docs/changelog.rst | 25 | ||||
| -rw-r--r-- | docs/guide/logging-monitoring.rst | 2 | ||||
| -rw-r--r-- | docs/guide/querying.rst | 20 | ||||
| -rw-r--r-- | mongoengine.egg-info/PKG-INFO | 6 | ||||
| -rw-r--r-- | mongoengine/__init__.py | 2 | ||||
| -rw-r--r-- | mongoengine/base/document.py | 2 | ||||
| -rw-r--r-- | mongoengine/base/fields.py | 6 | ||||
| -rw-r--r-- | mongoengine/connection.py | 35 | ||||
| -rw-r--r-- | mongoengine/context_managers.py | 33 | ||||
| -rw-r--r-- | mongoengine/fields.py | 16 | ||||
| -rw-r--r-- | mongoengine/mongodb_support.py | 3 | ||||
| -rw-r--r-- | mongoengine/pymongo_support.py | 20 | ||||
| -rw-r--r-- | mongoengine/queryset/base.py | 63 | ||||
| -rw-r--r-- | mongoengine/queryset/transform.py | 13 | ||||
| -rw-r--r-- | setup.py | 2 |
20 files changed, 201 insertions, 78 deletions
@@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: mongoengine -Version: 0.27.0 +Version: 0.28.2 Summary: MongoEngine is a Python Object-Document Mapper for working with MongoDB. Home-page: http://mongoengine.org/ Author: Harry Marr @@ -16,8 +16,6 @@ Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 @@ -62,7 +60,7 @@ an `API reference <https://mongoengine-odm.readthedocs.io/apireference.html>`_. Supported MongoDB Versions ========================== -MongoEngine is currently tested against MongoDB v3.6, v4.0, v4.4 and v5.0. Future versions +MongoEngine is currently tested against MongoDB v3.6, v4.0, v4.4, v5.0, v6.0 and v7.0. Future versions should be supported as well, but aren't actively tested at the moment. Make sure to open an issue or submit a pull request if you experience any problems with a more recent MongoDB versions. @@ -31,7 +31,7 @@ an `API reference <https://mongoengine-odm.readthedocs.io/apireference.html>`_. Supported MongoDB Versions ========================== -MongoEngine is currently tested against MongoDB v3.6, v4.0, v4.4 and v5.0. Future versions +MongoEngine is currently tested against MongoDB v3.6, v4.0, v4.4, v5.0, v6.0 and v7.0. Future versions should be supported as well, but aren't actively tested at the moment. Make sure to open an issue or submit a pull request if you experience any problems with a more recent MongoDB versions. diff --git a/debian/changelog b/debian/changelog index 8923282..b4536a7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +python-mongoengine (0.28.2-1) unstable; urgency=medium + + * Team upload + * New upstream version 0.28.2 + * Drop upstream merged patch + + -- Ananthu C V <weepingclown@disroot.org> Tue, 12 Mar 2024 00:29:40 +0530 + python-mongoengine (0.27.0-1) unstable; urgency=medium * Team upload diff --git a/debian/patches/0002-add-missing-doc-link.patch b/debian/patches/0002-add-missing-doc-link.patch deleted file mode 100644 index 5a926bb..0000000 --- a/debian/patches/0002-add-missing-doc-link.patch +++ /dev/null @@ -1,14 +0,0 @@ -Description: add a missing link in the doc -Author: Ananthu C V <weepingclown@disroot.org> -Forwarded: https://github.com/MongoEngine/mongoengine/pull/2792 -Last-Update: 2023-12-30 ---- a/docs/guide/querying.rst -+++ b/docs/guide/querying.rst -@@ -587,6 +587,7 @@ - * ``add_to_set`` -- add value to a list only if its not in the list already - * ``rename`` -- rename the key name - -+.. _need to add upsert=True: http://docs.mongodb.org/manual/reference/operator/update/setOnInsert - .. _depending on the value: http://docs.mongodb.org/manual/reference/operator/update/pop/ - - The syntax for atomic updates is similar to the querying syntax, but the diff --git a/debian/patches/series b/debian/patches/series index 2519548..7500041 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1 @@ 0001-drop-rtd-extension.patch -0002-add-missing-doc-link.patch diff --git a/docs/changelog.rst b/docs/changelog.rst index b0e54cd..81a0ce6 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -8,6 +8,31 @@ Development =========== - (Fill this out as you fix issues and develop your features). +Changes in 0.28.2 +================= +- Fix typing import incompatible with Pymongo 3.7 #2802 + +Changes in 0.28.1 +================= +- Fix bug related with recent updates to no_dereference context manager #2799 + +Changes in 0.28.0 +================= +- Fix for uuidRepresentation not read when provided in URI #2741 +- Add option to user array_filters https://www.mongodb.com/docs/manual/reference/operator/update/positional-filtered/ #2769 +- Fix combination of __raw__ and mongoengine syntax #2773 +- Add tests against MongoDB 6.0 and MongoDB 7.0 in the pipeline +- Fix validate() not being called when inheritance is used in EmbeddedDocument and validate is overriden #2784 +- Add support for readPreferenceTags in connection parameters #2644 +- Use estimated_documents_count OR documents_count when count is called, based on the query #2529 +- Fix no_dereference context manager which wasn't turning off auto-dereferencing correctly in some cases #2788 +- BREAKING CHANGE: no_dereference context manager no longer returns the class in __enter__ #2788 + as it was useless and making it look like it was returning a different class although it was the same. + Thus, it must be called like `with no_dereference(User):` and no longer `with no_dereference(User) as ...:` +- Added __raw__ to :meth:`~mongoengine.Queryset.order_by()` to allow to provide raw pymongo 'sort' argument and get around some of the limitations #2783 +- Add `text_score` argument on :meth:`~mongoengine.Document.search_text()` to allow text_score computation to be turned off + as it interfere with natural returned documents order #2759 + Changes in 0.27.0 ================= - Update uuidRepresentation warnings with "unspecified" as the future default (instead of 'standard' previously advertised) #2739 diff --git a/docs/guide/logging-monitoring.rst b/docs/guide/logging-monitoring.rst index 9f523b7..5aedd15 100644 --- a/docs/guide/logging-monitoring.rst +++ b/docs/guide/logging-monitoring.rst @@ -2,7 +2,7 @@ Logging/Monitoring ================== -It is possible to use `pymongo.monitoring <https://api.mongodb.com/python/current/api/pymongo/monitoring.html>`_ to monitor +It is possible to use `pymongo.monitoring <https://pymongo.readthedocs.io/en/stable/api/pymongo/monitoring.html>`_ to monitor the driver events (e.g: queries, connections, etc). This can be handy if you want to monitor the queries issued by MongoEngine to the driver. diff --git a/docs/guide/querying.rst b/docs/guide/querying.rst index b9afb60..d5ac70b 100644 --- a/docs/guide/querying.rst +++ b/docs/guide/querying.rst @@ -252,6 +252,23 @@ and provide the pipeline as a list .. versionadded:: 0.23.2 +Update with Array Operator +-------------------------------- +It is possible to update specific value in array by use array_filters (arrayFilters) operator. +This is done by using ``__raw__`` keyword argument to the update method and provide the arrayFilters as a list. + +`Update with Array Operator <https://www.mongodb.com/docs/manual/reference/operator/update/positional-filtered->`_ +:: + + # assuming an initial 'tags' field == ['test1', 'test2', 'test3'] + Page.objects().update(__raw__={'$set': {"tags.$[element]": 'test11111'}}, + array_filters=[{"element": {'$eq': 'test2'}}], + + # updated 'tags' field == ['test1', 'test11111', 'test3'] + + ) + + Sorting/Ordering results ======================== It is possible to order the results by 1 or more keys using :meth:`~mongoengine.queryset.QuerySet.order_by`. @@ -522,7 +539,7 @@ data. To turn off dereferencing of the results of a query use You can also turn off all dereferencing for a fixed period by using the :class:`~mongoengine.context_managers.no_dereference` context manager:: - with no_dereference(Post) as Post: + with no_dereference(Post): post = Post.objects.first() assert(isinstance(post.author, DBRef)) @@ -587,6 +604,7 @@ There are several different "modifiers" that you may use with these methods: * ``add_to_set`` -- add value to a list only if its not in the list already * ``rename`` -- rename the key name +.. _need to add upsert=True: http://docs.mongodb.org/manual/reference/operator/update/setOnInsert .. _depending on the value: http://docs.mongodb.org/manual/reference/operator/update/pop/ The syntax for atomic updates is similar to the querying syntax, but the diff --git a/mongoengine.egg-info/PKG-INFO b/mongoengine.egg-info/PKG-INFO index 483bf98..b83bf81 100644 --- a/mongoengine.egg-info/PKG-INFO +++ b/mongoengine.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: mongoengine -Version: 0.27.0 +Version: 0.28.2 Summary: MongoEngine is a Python Object-Document Mapper for working with MongoDB. Home-page: http://mongoengine.org/ Author: Harry Marr @@ -16,8 +16,6 @@ Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 @@ -62,7 +60,7 @@ an `API reference <https://mongoengine-odm.readthedocs.io/apireference.html>`_. Supported MongoDB Versions ========================== -MongoEngine is currently tested against MongoDB v3.6, v4.0, v4.4 and v5.0. Future versions +MongoEngine is currently tested against MongoDB v3.6, v4.0, v4.4, v5.0, v6.0 and v7.0. Future versions should be supported as well, but aren't actively tested at the moment. Make sure to open an issue or submit a pull request if you experience any problems with a more recent MongoDB versions. diff --git a/mongoengine/__init__.py b/mongoengine/__init__.py index a42755b..799dad6 100644 --- a/mongoengine/__init__.py +++ b/mongoengine/__init__.py @@ -29,7 +29,7 @@ __all__ = ( ) -VERSION = (0, 27, 0) +VERSION = (0, 28, 2) def get_version(): diff --git a/mongoengine/base/document.py b/mongoengine/base/document.py index e5311c5..194b24e 100644 --- a/mongoengine/base/document.py +++ b/mongoengine/base/document.py @@ -322,7 +322,7 @@ class BaseDocument: if "_text_score" not in self._data: raise InvalidDocumentError( - "This document is not originally built from a text query" + "This document is not originally built from a text query (or text_score was not set on search_text() call)" ) return self._data["_text_score"] diff --git a/mongoengine/base/fields.py b/mongoengine/base/fields.py index 85a10ff..037e916 100644 --- a/mongoengine/base/fields.py +++ b/mongoengine/base/fields.py @@ -59,11 +59,11 @@ class BaseField: unique with (Creates an index). :param primary_key: Mark this field as the primary key ((Creates an index)). Defaults to False. :param validation: (optional) A callable to validate the value of the - field. The callable takes the value as parameter and should raise + field. The callable takes the value as parameter and should raise a ValidationError if validation fails :param choices: (optional) The valid choices - :param null: (optional) If the field value can be null when a default exist. If not set, the default value - will be used in case a field with a default value is set to None. Defaults to False. + :param null: (optional) If the field value can be null when a default exists. If not set, the default value + will be used in case a field with a default value is set to None. Defaults to False. :param sparse: (optional) `sparse=True` combined with `unique=True` and `required=False` means that uniqueness won't be enforced for `None` values (Creates an index). Defaults to False. :param **kwargs: (optional) Arbitrary indirection-free metadata for diff --git a/mongoengine/connection.py b/mongoengine/connection.py index 7852c64..42a7943 100644 --- a/mongoengine/connection.py +++ b/mongoengine/connection.py @@ -1,8 +1,16 @@ import warnings from pymongo import MongoClient, ReadPreference, uri_parser +from pymongo.common import _UUID_REPRESENTATIONS from pymongo.database import _check_name +# DriverInfo was added in PyMongo 3.7. +try: + from pymongo.driver_info import DriverInfo +except ImportError: + DriverInfo = None + +import mongoengine from mongoengine.pymongo_support import PYMONGO_VERSION __all__ = [ @@ -124,7 +132,9 @@ def _get_connection_settings( if uri_dict.get(param): conn_settings[param] = uri_dict[param] - uri_options = uri_dict["options"] + uri_options = uri_dict[ + "options" + ] # uri_options is a _CaseInsensitiveDictionary if "replicaset" in uri_options: conn_settings["replicaSet"] = uri_options["replicaset"] if "authsource" in uri_options: @@ -153,12 +163,27 @@ def _get_connection_settings( preference.name.lower() == read_pf_mode or preference.mode == read_pf_mode ): - conn_settings["read_preference"] = preference + ReadPrefClass = preference.__class__ break + + if "readpreferencetags" in uri_options: + conn_settings["read_preference"] = ReadPrefClass( + tag_sets=uri_options["readpreferencetags"] + ) + else: + conn_settings["read_preference"] = ReadPrefClass() + if "authmechanismproperties" in uri_options: conn_settings["authmechanismproperties"] = uri_options[ "authmechanismproperties" ] + if "uuidrepresentation" in uri_options: + REV_UUID_REPRESENTATIONS = { + v: k for k, v in _UUID_REPRESENTATIONS.items() + } + conn_settings["uuidrepresentation"] = REV_UUID_REPRESENTATIONS[ + uri_options["uuidrepresentation"] + ] else: resolved_hosts.append(entity) conn_settings["host"] = resolved_hosts @@ -170,7 +195,7 @@ def _get_connection_settings( keys = { key.lower() for key in kwargs.keys() } # pymongo options are case insensitive - if "uuidrepresentation" not in keys: + if "uuidrepresentation" not in keys and "uuidrepresentation" not in conn_settings: warnings.warn( "No uuidRepresentation is specified! Falling back to " "'pythonLegacy' which is the default for pymongo 3.x. " @@ -320,6 +345,10 @@ def get_connection(alias=DEFAULT_CONNECTION_NAME, reconnect=False): # alias and remove the database name and authentication info (we don't # care about them at this point). conn_settings = _clean_settings(raw_conn_settings) + if DriverInfo is not None: + conn_settings.setdefault( + "driver", DriverInfo("MongoEngine", mongoengine.__version__) + ) # Determine if we should use PyMongo's or mongomock's MongoClient. if "mongo_client_class" in conn_settings: diff --git a/mongoengine/context_managers.py b/mongoengine/context_managers.py index eb9c996..f16753e 100644 --- a/mongoengine/context_managers.py +++ b/mongoengine/context_managers.py @@ -1,3 +1,4 @@ +import threading from contextlib import contextmanager from pymongo.read_concern import ReadConcern @@ -15,9 +16,33 @@ __all__ = ( "query_counter", "set_write_concern", "set_read_write_concern", + "no_dereferencing_active_for_class", ) +class MyThreadLocals(threading.local): + def __init__(self): + self.no_dereferencing_class = {} + + +thread_locals = MyThreadLocals() + + +def no_dereferencing_active_for_class(cls): + return cls in thread_locals.no_dereferencing_class + + +def _register_no_dereferencing_for_class(cls): + thread_locals.no_dereferencing_class.setdefault(cls, 0) + thread_locals.no_dereferencing_class[cls] += 1 + + +def _unregister_no_dereferencing_for_class(cls): + thread_locals.no_dereferencing_class[cls] -= 1 + if thread_locals.no_dereferencing_class[cls] == 0: + thread_locals.no_dereferencing_class.pop(cls) + + class switch_db: """switch_db alias context manager. @@ -107,7 +132,7 @@ class no_dereference: Turns off all dereferencing in Documents for the duration of the context manager:: - with no_dereference(Group) as Group: + with no_dereference(Group): Group.objects.find() """ @@ -130,15 +155,17 @@ class no_dereference: def __enter__(self): """Change the objects default and _auto_dereference values.""" + _register_no_dereferencing_for_class(self.cls) + for field in self.deref_fields: self.cls._fields[field]._auto_dereference = False - return self.cls def __exit__(self, t, value, traceback): """Reset the default and _auto_dereference values.""" + _unregister_no_dereferencing_for_class(self.cls) + for field in self.deref_fields: self.cls._fields[field]._auto_dereference = True - return self.cls class no_sub_classes: diff --git a/mongoengine/fields.py b/mongoengine/fields.py index df155e6..40469bf 100644 --- a/mongoengine/fields.py +++ b/mongoengine/fields.py @@ -47,6 +47,8 @@ from mongoengine.queryset.transform import STRING_OPERATORS try: from PIL import Image, ImageOps + + LANCZOS = Image.LANCZOS if hasattr(Image, "LANCZOS") else Image.ANTIALIAS except ImportError: Image = None ImageOps = None @@ -759,7 +761,7 @@ class EmbeddedDocumentField(BaseField): "Invalid embedded document instance provided to an " "EmbeddedDocumentField" ) - self.document_type.validate(value, clean) + value.validate(clean=clean) def lookup_member(self, member_name): doc_and_subclasses = [self.document_type] + self.document_type.__subclasses__() @@ -1946,23 +1948,19 @@ class ImageGridFsProxy(GridFSProxy): size = field.size if size["force"]: - img = ImageOps.fit( - img, (size["width"], size["height"]), Image.ANTIALIAS - ) + img = ImageOps.fit(img, (size["width"], size["height"]), LANCZOS) else: - img.thumbnail((size["width"], size["height"]), Image.ANTIALIAS) + img.thumbnail((size["width"], size["height"]), LANCZOS) thumbnail = None if field.thumbnail_size: size = field.thumbnail_size if size["force"]: - thumbnail = ImageOps.fit( - img, (size["width"], size["height"]), Image.ANTIALIAS - ) + thumbnail = ImageOps.fit(img, (size["width"], size["height"]), LANCZOS) else: thumbnail = img.copy() - thumbnail.thumbnail((size["width"], size["height"]), Image.ANTIALIAS) + thumbnail.thumbnail((size["width"], size["height"]), LANCZOS) if thumbnail: thumb_id = self._put_thumbnail(thumbnail, img_format, progressive) diff --git a/mongoengine/mongodb_support.py b/mongoengine/mongodb_support.py index 00b87f4..23c538d 100644 --- a/mongoengine/mongodb_support.py +++ b/mongoengine/mongodb_support.py @@ -9,6 +9,9 @@ MONGODB_34 = (3, 4) MONGODB_36 = (3, 6) MONGODB_42 = (4, 2) MONGODB_44 = (4, 4) +MONGODB_50 = (5, 0) +MONGODB_60 = (6, 0) +MONGODB_70 = (7, 0) def get_mongodb_version(): diff --git a/mongoengine/pymongo_support.py b/mongoengine/pymongo_support.py index 5429fc9..7aa5567 100644 --- a/mongoengine/pymongo_support.py +++ b/mongoengine/pymongo_support.py @@ -37,7 +37,12 @@ def count_documents( # count_documents appeared in pymongo 3.7 if PYMONGO_VERSION >= (3, 7): try: - return collection.count_documents(filter=filter, **kwargs) + if not filter and set(kwargs) <= {"max_time_ms"}: + # when no filter is provided, estimated_document_count + # is a lot faster as it uses the collection metadata + return collection.estimated_document_count(**kwargs) + else: + return collection.count_documents(filter=filter, **kwargs) except OperationFailure as err: if PYMONGO_VERSION >= (4,): raise @@ -46,15 +51,10 @@ def count_documents( # with .count but are no longer working with count_documents (i.e $geoNear, $near, and $nearSphere) # fallback to deprecated Cursor.count # Keeping this should be reevaluated the day pymongo removes .count entirely - message = str(err) - if not ( - "not allowed in this context" in message - and ( - "$where" in message - or "$geoNear" in message - or "$near" in message - or "$nearSphere" in message - ) + if ( + "$geoNear, $near, and $nearSphere are not allowed in this context" + not in str(err) + and "$where is not allowed in this context" not in str(err) ): raise diff --git a/mongoengine/queryset/base.py b/mongoengine/queryset/base.py index 75b2af6..3ce3cb3 100644 --- a/mongoengine/queryset/base.py +++ b/mongoengine/queryset/base.py @@ -17,6 +17,7 @@ from mongoengine.base import get_document from mongoengine.common import _import_class from mongoengine.connection import get_db from mongoengine.context_managers import ( + no_dereferencing_active_for_class, set_read_write_concern, set_write_concern, switch_db, @@ -51,9 +52,6 @@ class BaseQuerySet: providing :class:`~mongoengine.Document` objects as the results. """ - __dereference = False - _auto_dereference = True - def __init__(self, document, collection): self._document = document self._collection_obj = collection @@ -73,6 +71,10 @@ class BaseQuerySet: self._none = False self._as_pymongo = False self._search_text = None + self._search_text_score = None + + self.__dereference = False + self.__auto_dereference = True # If inheritance is allowed, only return instances and instances of # subclasses of the class being used @@ -228,7 +230,7 @@ class BaseQuerySet: """An alias of :meth:`~mongoengine.queryset.QuerySet.__call__`""" return self.__call__(*q_objs, **query) - def search_text(self, text, language=None): + def search_text(self, text, language=None, text_score=True): """ Start a text search, using text indexes. Require: MongoDB server version 2.6+. @@ -237,7 +239,9 @@ class BaseQuerySet: for the search and the rules for the stemmer and tokenizer. If not specified, the search uses the default language of the index. For supported languages, see - `Text Search Languages <http://docs.mongodb.org/manual/reference/text-search-languages/#text-search-languages>`. + `Text Search Languages <https://docs.mongodb.org/manual/reference/text-search-languages/#text-search-languages>`. + :param text_score: True to have it return the text_score (available through get_text_score()), False to disable that + Note that unless you order the results, leaving text_score=True may provide randomness in the returned documents """ queryset = self.clone() if queryset._search_text: @@ -251,11 +255,12 @@ class BaseQuerySet: queryset._mongo_query = None queryset._cursor_obj = None queryset._search_text = text + queryset._search_text_score = text_score return queryset def get(self, *q_objs, **query): - """Retrieve the the matching object raising + """Retrieve the matching object raising :class:`~mongoengine.queryset.MultipleObjectsReturned` or `DocumentName.MultipleObjectsReturned` exception if multiple results and :class:`~mongoengine.queryset.DoesNotExist` or @@ -530,6 +535,7 @@ class BaseQuerySet: write_concern=None, read_concern=None, full_result=False, + array_filters=None, **update, ): """Perform an atomic update on the fields matched by the query. @@ -545,6 +551,7 @@ class BaseQuerySet: :param read_concern: Override the read concern for the operation :param full_result: Return the associated ``pymongo.UpdateResult`` rather than just the number updated items + :param array_filters: A list of filters specifying which array elements an update should apply. :param update: Django-style update keyword arguments :returns the number of updated documents (unless ``full_result`` is True) @@ -559,7 +566,9 @@ class BaseQuerySet: queryset = self.clone() query = queryset._query - if "__raw__" in update and isinstance(update["__raw__"], list): + if "__raw__" in update and isinstance( + update["__raw__"], list + ): # Case of Update with Aggregation Pipeline update = [ transform.update(queryset._document, **{"__raw__": u}) for u in update["__raw__"] @@ -580,7 +589,9 @@ class BaseQuerySet: update_func = collection.update_one if multi: update_func = collection.update_many - result = update_func(query, update, upsert=upsert) + result = update_func( + query, update, upsert=upsert, array_filters=array_filters + ) if full_result: return result elif result.raw_result: @@ -795,7 +806,7 @@ class BaseQuerySet: return self._clone_into(self.__class__(self._document, self._collection_obj)) def _clone_into(self, new_qs): - """Copy all of the relevant properties of this queryset to + """Copy all the relevant properties of this queryset to a new queryset (which has to be an instance of :class:`~mongoengine.queryset.base.BaseQuerySet`). """ @@ -825,8 +836,8 @@ class BaseQuerySet: "_empty", "_hint", "_collation", - "_auto_dereference", "_search_text", + "_search_text_score", "_max_time_ms", "_comment", "_batch_size", @@ -836,6 +847,8 @@ class BaseQuerySet: val = getattr(self, prop) setattr(new_qs, prop, copy.copy(val)) + new_qs.__auto_dereference = self._BaseQuerySet__auto_dereference + if self._cursor_obj: new_qs._cursor_obj = self._cursor_obj.clone() @@ -1111,7 +1124,7 @@ class BaseQuerySet: ) return queryset - def order_by(self, *keys): + def order_by(self, *keys, __raw__=None): """Order the :class:`~mongoengine.queryset.QuerySet` by the given keys. The order may be specified by prepending each of the keys by a "+" or @@ -1121,11 +1134,19 @@ class BaseQuerySet: :param keys: fields to order the query results by; keys may be prefixed with "+" or a "-" to determine the ordering direction. + :param __raw__: a raw pymongo "sort" argument (provided as a list of (key, direction)) + see 'key_or_list' in `pymongo.cursor.Cursor.sort doc <https://pymongo.readthedocs.io/en/stable/api/pymongo/cursor.html#pymongo.cursor.Cursor.sort>`. + If both keys and __raw__ are provided, an exception is raised """ - queryset = self.clone() + if __raw__ and keys: + raise OperationError("Can not use both keys and __raw__ with order_by() ") + queryset = self.clone() old_ordering = queryset._ordering - new_ordering = queryset._get_order_by(keys) + if __raw__: + new_ordering = __raw__ + else: + new_ordering = queryset._get_order_by(keys) if queryset._cursor_obj: # If a cursor object has already been created, apply the sort to it @@ -1296,10 +1317,10 @@ class BaseQuerySet: return [self._document._from_son(data) for data in son_data] def aggregate(self, pipeline, *suppl_pipeline, **kwargs): - """Perform a aggregate function based in your queryset params + """Perform an aggregate function based on your queryset params - :param pipeline: list of aggregation commands,\ - see: http://docs.mongodb.org/manual/core/aggregation-pipeline/ + :param pipeline: list of aggregation commands, + see: https://www.mongodb.com/docs/manual/core/aggregation-pipeline/ :param suppl_pipeline: unpacked list of pipeline (added to support deprecation of the old interface) parameter will be removed shortly :param kwargs: (optional) kwargs dictionary to be passed to pymongo's aggregate call @@ -1657,7 +1678,8 @@ class BaseQuerySet: if fields_name not in cursor_args: cursor_args[fields_name] = {} - cursor_args[fields_name]["_text_score"] = {"$meta": "textScore"} + if self._search_text_score: + cursor_args[fields_name]["_text_score"] = {"$meta": "textScore"} return cursor_args @@ -1741,10 +1763,15 @@ class BaseQuerySet: self.__dereference = _import_class("DeReference")() return self.__dereference + @property + def _auto_dereference(self): + should_deref = not no_dereferencing_active_for_class(self._document) + return should_deref and self.__auto_dereference + def no_dereference(self): """Turn off any dereferencing for the results of this queryset.""" queryset = self.clone() - queryset._auto_dereference = False + queryset.__auto_dereference = False return queryset # Helper Functions diff --git a/mongoengine/queryset/transform.py b/mongoengine/queryset/transform.py index a95a846..195bc0b 100644 --- a/mongoengine/queryset/transform.py +++ b/mongoengine/queryset/transform.py @@ -62,6 +62,15 @@ MATCH_OPERATORS = ( ) +def handle_raw_query(value, mongo_query): + """Combine a raw query with an existing one""" + for op, v in value.items(): + if op not in mongo_query: + mongo_query[op] = v + elif op in mongo_query and isinstance(mongo_query[op], dict): + mongo_query[op].update(v) + + # TODO make this less complex def query(_doc_cls=None, **kwargs): """Transform a query from Django-style format to Mongo format.""" @@ -69,7 +78,7 @@ def query(_doc_cls=None, **kwargs): merge_query = defaultdict(list) for key, value in sorted(kwargs.items()): if key == "__raw__": - mongo_query.update(value) + handle_raw_query(value, mongo_query) continue parts = key.rsplit("__") @@ -234,7 +243,7 @@ def update(_doc_cls=None, **update): for key, value in update.items(): if key == "__raw__": - mongo_update.update(value) + handle_raw_query(value, mongo_update) continue parts = key.split("__") @@ -98,8 +98,6 @@ CLASSIFIERS = [ "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", |
