We're pleased to announce the release of mssql-django 1.7.2, a patch release that ships three targeted bug fixes for the Django backend for Microsoft SQL Server and Azure SQL. This release focuses on correctness: timezone-aware datetimes, QuerySet.explain() on Django 4.0+, and exception handling in a test utility.
Install or upgrade from PyPI:
pip install --upgrade mssql-django
What's new in 1.7.2
Correct timezone handling for DATETIMEOFFSET and Now() under USE_TZ=True
Two long-standing timezone issues are fixed in this release:
- handle_datetimeoffset now parses the timezone offset from SQL Server's binary DATETIMEOFFSET representation. Previously, values read from DATETIMEOFFSET columns could be returned without their offset, leading to naive datetimes or values converted using the wrong zone. The backend now returns properly timezone-aware datetime objects.
- Now() emits SYSDATETIMEOFFSET() when USE_TZ=True. When Django is configured with USE_TZ=True, the expression Now() previously compiled to SYSDATETIME(), which returns the SQL Server host's local time without offset information. On non-UTC hosts this produced timestamps that were silently shifted. With this fix, Now() compiles to SYSDATETIMEOFFSET() under USE_TZ=True and continues to compile to SYSDATETIME() when USE_TZ=False, matching Django's expectations.
The release adds regression tests covering UTC, +05:30 (IST), -05:00 (EST), -09:30 (Marquesas), and +05:45 (Nepal) offsets, plus a new NowSQLTemplateTests that pins the SQL template emitted in each USE_TZ mode.
QuerySet.explain() no longer raises AttributeError on Django 4.0+
In Django 4.0 the internal API for EXPLAIN plans changed: query.explain_format and query.explain_options were replaced by a single query.explain_info object. The mssql-django compiler still read the old attributes, which raised AttributeError whenever an application called .explain() on a queryset.
The compiler now reads the correct attribute based on the running Django version, so .explain() works again on Django 4.0, 4.1, 4.2, 5.0, 5.1, 5.2, and 6.0. A new ExplainRegressionTests suite locks in the behavior.
Test utility no longer swallows exceptions in finally
A return statement inside a finally block in the JSONField support probe (_check_jsonfield_supported_sqlite()) was silently swallowing exceptions, including KeyboardInterrupt and other BaseException subclasses. The return has been removed so exceptions propagate as Python intends.
Compatibility
mssql-django 1.7.2 supports:
- Django: 3.2, 4.0, 4.1, 4.2, 5.0, 5.1, 5.2, 6.0
- Python: 3.8 through 3.14
- SQL Server: 2017, 2019, 2022, 2025; Azure SQL Database; Azure SQL Managed Instance
- ODBC Driver: 17 or 18 for SQL Server (driver 18 is the default since 1.7, with automatic fallback to 17 when 18 is not installed)
No configuration changes are required to pick up the fixes in 1.7.2. Upgrade in place:
pip install --upgrade mssql-django
Upgrading from 1.7.1
1.7.2 is a drop-in replacement for 1.7.1. If your application:
- reads from DATETIMEOFFSET columns,
- uses django.db.models.functions.Now() with USE_TZ=True, or
- calls QuerySet.explain() on Django 4.0+,
you will see corrected behavior after upgrading. Applications that previously worked around the timezone offset issue (for example by manually attaching tzinfo to values read from DATETIMEOFFSET columns) should review those workarounds; values returned by the ORM are now timezone-aware by default.
Thank you
Thanks to everyone who reported the underlying issues, contributed reproductions and test cases. Bug reports and pull requests are always welcome on GitHub.