From 42e1fcf243ac60596f5fa508b9b7b8fbb5dba6d0 Mon Sep 17 00:00:00 2001 From: MahYA Date: Tue, 25 Nov 2025 11:21:04 -0500 Subject: [PATCH 1/7] Update dependencies for Django 4.x/5.x and PyMongo 4.x support - Update sqlparse from ==0.2.4 to >=0.4.4 (security fix) - Remove upper version bounds on pymongo (was <=3.11.4) - Remove upper version bounds on django (was <=3.1.12) - Update Python requirement to >=3.8 - Add classifiers for Python 3.8-3.12 and Django 3.2-5.1 This allows djongo to work with modern Django and PyMongo versions. Co-Authored-By: MahYA --- pyproject.toml | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2775db3f..f537b34c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,9 +6,9 @@ requires = ["setuptools"] dynamic = ["version", "optional-dependencies"] name = "djongo" dependencies = [ - 'sqlparse==0.2.4', - 'pymongo>=3.7.0,<=3.11.4', - 'django>=2.1,<=3.1.12', + 'sqlparse>=0.4.4', + 'pymongo>=3.7.0', + 'django>=2.1', 'pytz>=2018.5' ] authors = [ @@ -16,12 +16,22 @@ authors = [ ] license= {text = "AGPL"} keywords = ["Django", "Djongo", "MongoDB", "driver", "connector"] -requires-python = ">=3.6" +requires-python = ">=3.8" classifiers = [ - 'Development Status :: 3 - Alpha', + 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Programming Language :: Python :: 3.6', + 'License :: OSI Approved :: GNU Affero General Public License v3', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', + 'Framework :: Django :: 3.2', + 'Framework :: Django :: 4.0', + 'Framework :: Django :: 4.1', + 'Framework :: Django :: 4.2', + 'Framework :: Django :: 5.0', + 'Framework :: Django :: 5.1', ] description = "Djongo: The Django MongoDB connector" readme = "README.md" From f3b161c6aa3bcc570c7d64f707c70fff649b9113 Mon Sep 17 00:00:00 2001 From: MahYA Date: Tue, 25 Nov 2025 11:21:16 -0500 Subject: [PATCH 2/7] Fix PyMongo 4.x compatibility in storage.py Replace deprecated collection_names() with list_collection_names() which is available in PyMongo 3.7+ and required for PyMongo 4.x. Co-Authored-By: MahYA --- djongo/storage.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/djongo/storage.py b/djongo/storage.py index b8a5d59c..481bda3c 100644 --- a/djongo/storage.py +++ b/djongo/storage.py @@ -16,8 +16,8 @@ def _get_subcollections(collection): """ Returns all sub-collections of `collection`. """ - # XXX: Use the MongoDB API for this once it exists. - for name in collection.database.collection_names(): + # Use list_collection_names() which is available in PyMongo 3.7+ + for name in collection.database.list_collection_names(): cleaned = name[:name.rfind('.')] if cleaned != collection.name and cleaned.startswith(collection.name): yield cleaned From 7f9df2e0f70ddeb1ca06fa55184355a42196558a Mon Sep 17 00:00:00 2001 From: MahYA Date: Tue, 25 Nov 2025 11:21:31 -0500 Subject: [PATCH 3/7] Fix Django 4.x/5.x compatibility in operations and features operations.py: - Update sql_flush() signature for Django 4.1+ compatibility - Add **kwargs to absorb new parameters like 'sequences' features.py: - Add supports_json_field for Django 3.1+ - Add Django 4.0+ feature flags (expression_defaults, check_constraints, etc.) - Add Django 4.1+ feature flags (comments support) Co-Authored-By: MahYA --- djongo/features.py | 14 ++++++++++++++ djongo/operations.py | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/djongo/features.py b/djongo/features.py index acfee1e3..0a38f995 100644 --- a/djongo/features.py +++ b/djongo/features.py @@ -12,3 +12,17 @@ class DatabaseFeatures(BaseDatabaseFeatures): test_db_allows_multiple_connections = False supports_unspecified_pk = True + # Django 3.1+ features + supports_json_field = True + + # Django 4.0+ features + supports_expression_defaults = False + supports_table_check_constraints = False + supports_column_check_constraints = False + can_return_columns_from_insert = False + can_return_rows_from_bulk_insert = False + + # Django 4.1+ features + supports_comments = False + supports_comments_inline = False + diff --git a/djongo/operations.py b/djongo/operations.py index 3a9abfb3..96f1264a 100644 --- a/djongo/operations.py +++ b/djongo/operations.py @@ -96,8 +96,9 @@ def get_db_converters(self, expression): converters.append(self.convert_datetimefield_value) return converters - def sql_flush(self, style, tables, reset_sequences, allow_cascade=False): + def sql_flush(self, style, tables, *, reset_sequences=False, allow_cascade=False, **kwargs): # TODO: Need to implement this fully + # Note: **kwargs added for Django 4.1+ compatibility (sequences parameter) return [f'ALTER TABLE "{table}" FLUSH' for table in tables] From 886f543618fb420c0238627665328707c1286053 Mon Sep 17 00:00:00 2001 From: MahYA Date: Tue, 25 Nov 2025 11:21:42 -0500 Subject: [PATCH 4/7] Bump version to 1.4.0 New version includes: - Django 4.x/5.x compatibility - PyMongo 4.x compatibility - Security fix for sqlparse dependency Co-Authored-By: MahYA --- djongo/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/djongo/__init__.py b/djongo/__init__.py index f350239f..85a24b43 100644 --- a/djongo/__init__.py +++ b/djongo/__init__.py @@ -1,2 +1,2 @@ -__version__ = '1.3.7' +__version__ = '1.4.0' From 1d6c98060d027871afac5c6b1ff54a486b06ac87 Mon Sep 17 00:00:00 2001 From: MahYA Date: Tue, 25 Nov 2025 11:58:34 -0500 Subject: [PATCH 5/7] Fix sqlparse 0.5.x compatibility sqlparse 0.5.x changed how certain SQL keywords are tokenized: - 'ORDER BY' is now a single token instead of separate 'ORDER' and 'BY' - 'GROUP BY' is now a single token instead of separate 'GROUP' and 'BY' - 'VALUES (...)' is now wrapped in a Values token Changes: - query.py: Import Values token, update SelectQuery.parse() to handle both 'ORDER' and 'ORDER BY' keywords, add _process_values_parenthesis helper method - converters.py: Update OrderConverter and GroupbyConverter to handle both old and new sqlparse token formats Co-Authored-By: MahYA --- djongo/sql2mongo/converters.py | 15 +++++++------- djongo/sql2mongo/query.py | 37 +++++++++++++++++++++++++--------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/djongo/sql2mongo/converters.py b/djongo/sql2mongo/converters.py index 08230a82..eff685dc 100644 --- a/djongo/sql2mongo/converters.py +++ b/djongo/sql2mongo/converters.py @@ -276,10 +276,10 @@ def __init__(self, *args): def parse(self): tok = self.statement.next() - if not tok.match(tokens.Keyword, 'BY'): - raise SQLDecodeError - - tok = self.statement.next() + # In sqlparse >= 0.5, 'ORDER BY' is a single token, so there's no separate 'BY' + # In sqlparse < 0.5, 'ORDER' and 'BY' are separate tokens + if tok.match(tokens.Keyword, 'BY'): + tok = self.statement.next() self.columns.extend(SQLToken.tokens2sql(tok, self.query)) def to_mongo(self): @@ -443,9 +443,10 @@ def __init__(self, *args): def parse(self): tok = self.statement.next() - if not tok.match(tokens.Keyword, 'BY'): - raise SQLDecodeError - tok = self.statement.next() + # In sqlparse >= 0.5, 'GROUP BY' is a single token, so there's no separate 'BY' + # In sqlparse < 0.5, 'GROUP' and 'BY' are separate tokens + if tok.match(tokens.Keyword, 'BY'): + tok = self.statement.next() self.sql_tokens.extend(SQLToken.tokens2sql(tok, self.query)) def to_mongo(self): diff --git a/djongo/sql2mongo/query.py b/djongo/sql2mongo/query.py index fefb52ca..76966e03 100644 --- a/djongo/sql2mongo/query.py +++ b/djongo/sql2mongo/query.py @@ -20,6 +20,12 @@ Where, Statement) +# Try to import Values for sqlparse >= 0.4.0 +try: + from sqlparse.sql import Values +except ImportError: + Values = None + from ..exceptions import SQLDecodeError, MigrationError, print_warn from .functions import SQLFunc from .sql_tokens import (SQLToken, SQLStatement, SQLIdentifier, @@ -128,7 +134,8 @@ def parse(self): elif tok.match(tokens.Keyword, 'LIMIT'): self.limit = LimitConverter(self, statement) - elif tok.match(tokens.Keyword, 'ORDER'): + elif tok.match(tokens.Keyword, 'ORDER') or tok.match(tokens.Keyword, 'ORDER BY'): + # Handle both 'ORDER' (sqlparse < 0.5) and 'ORDER BY' (sqlparse >= 0.5) self.order = OrderConverter(self, statement) elif tok.match(tokens.Keyword, 'OFFSET'): @@ -142,7 +149,8 @@ def parse(self): converter = OuterJoinConverter(self, statement) self.joins.append(converter) - elif tok.match(tokens.Keyword, 'GROUP'): + elif tok.match(tokens.Keyword, 'GROUP') or tok.match(tokens.Keyword, 'GROUP BY'): + # Handle both 'GROUP' (sqlparse < 0.5) and 'GROUP BY' (sqlparse >= 0.5) self.groupby = GroupbyConverter(self, statement) elif tok.match(tokens.Keyword, 'HAVING'): @@ -356,17 +364,26 @@ def _columns(self, statement: SQLStatement): def _fill_values(self, statement: SQLStatement): for tok in statement: if isinstance(tok, Parenthesis): - placeholder = SQLToken.token2sql(tok, self) - values = [] - for index in placeholder: - if isinstance(index, int): - values.append(self.params[index]) - else: - values.append(index) - self._values.append(values) + self._process_values_parenthesis(tok) + elif Values is not None and isinstance(tok, Values): + # sqlparse >= 0.4.0 wraps VALUES (...) in a Values token + for subtok in tok.tokens: + if isinstance(subtok, Parenthesis): + self._process_values_parenthesis(subtok) elif not tok.match(tokens.Keyword, 'VALUES'): raise SQLDecodeError + def _process_values_parenthesis(self, tok): + """Process a Parenthesis token containing values.""" + placeholder = SQLToken.token2sql(tok, self) + values = [] + for index in placeholder: + if isinstance(index, int): + values.append(self.params[index]) + else: + values.append(index) + self._values.append(values) + def execute(self): docs = [] num = len(self._values) From cdccf5ffc98f6388581f57cde2e8c818c9354e4d Mon Sep 17 00:00:00 2001 From: MahYA Date: Tue, 25 Nov 2025 11:58:48 -0500 Subject: [PATCH 6/7] Fix package discovery in pyproject.toml Add explicit package configuration to prevent setuptools from auto-discovering tmp/ and docs/ as packages, which caused installation failures. Co-Authored-By: MahYA --- pyproject.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index f537b34c..f0770492 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,5 +40,9 @@ Homepage = "https://www.djongomapper.com/" Documentation = "https://www.djongomapper.com/docs/" Repository = "https://github.com/doableware/djongo.git" +[tool.setuptools.packages.find] +include = ["djongo*"] +exclude = ["tmp*", "docs*", "tests*"] + [tool.setuptools.dynamic] version = {attr = "djongo.__version__"} \ No newline at end of file From 5d06eddbeceebc7ea536b69b891629de18d06cc9 Mon Sep 17 00:00:00 2001 From: MahYA Date: Tue, 25 Nov 2025 11:58:58 -0500 Subject: [PATCH 7/7] Add tmp/ to .gitignore Co-Authored-By: MahYA --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d24777ab..675fec69 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,4 @@ Gemfile.lock /docs/.jekyll-metadata /docs/djongocs/assets/* -*.map \ No newline at end of file +*.maptmp/