diff -pruN 1.5.1-3/.github/ISSUE_TEMPLATE/bug_report.md 2.0.0-1/.github/ISSUE_TEMPLATE/bug_report.md
--- 1.5.1-3/.github/ISSUE_TEMPLATE/bug_report.md	1970-01-01 00:00:00.000000000 +0000
+++ 2.0.0-1/.github/ISSUE_TEMPLATE/bug_report.md	2025-01-12 12:07:21.000000000 +0000
@@ -0,0 +1,33 @@
+---
+name: Bug report
+about: Create a report to help us improve
+
+---
+
+#### Description
+*A clear and concise description of what the bug is.*
+
+#### To Reproduce
+*Share how the bug happened:*
+
+##### Model code
+```python
+# Include your models here
+```
+
+##### The issue
+*Add a short description along with your code*
+
+```python
+# Include the code that provoked the bug, including as full a stack-trace as possible
+```
+
+#### Environment
+*Describe the platform where the issue occurred, for easier analysis*
+
+- *Python version*:
+- *LDAP server*:
+- *Operating system*:
+
+#### Notes
+*Add any notes you feel relevant here :)*
diff -pruN 1.5.1-3/.github/ISSUE_TEMPLATE/improvement-suggestion.md 2.0.0-1/.github/ISSUE_TEMPLATE/improvement-suggestion.md
--- 1.5.1-3/.github/ISSUE_TEMPLATE/improvement-suggestion.md	1970-01-01 00:00:00.000000000 +0000
+++ 2.0.0-1/.github/ISSUE_TEMPLATE/improvement-suggestion.md	2025-01-12 12:07:21.000000000 +0000
@@ -0,0 +1,14 @@
+---
+name: Improvement suggestion
+about: Suggest an idea for this project
+
+---
+
+#### The problem
+*Please describe the problem you're encountering (e.g "It's very complex to do [...]")*
+
+#### Proposed solution
+*Please provide some wild idea you think could solve this issue. It's much easier to work from an existing suggestion :)*
+
+#### Extra notes
+*Any notes you feel interesting to include: alternatives you've considered, reasons to include the change, anything!*
diff -pruN 1.5.1-3/.gitignore 2.0.0-1/.gitignore
--- 1.5.1-3/.gitignore	1970-01-01 00:00:00.000000000 +0000
+++ 2.0.0-1/.gitignore	2025-01-12 12:07:21.000000000 +0000
@@ -0,0 +1,16 @@
+# Temporary files
+.*.swp
+*.pyc
+*.pyo
+
+# Build-related files
+docs/_build/
+.coverage
+.tox
+*.egg-info
+*.egg
+.eggs/
+build/
+dist/
+htmlcov/
+MANIFEST
diff -pruN 1.5.1-3/.travis.yml 2.0.0-1/.travis.yml
--- 1.5.1-3/.travis.yml	1970-01-01 00:00:00.000000000 +0000
+++ 2.0.0-1/.travis.yml	2025-01-12 12:07:21.000000000 +0000
@@ -0,0 +1,45 @@
+language: python
+
+cache: pip
+
+script:
+  - tox
+
+addons:
+  apt:
+    packages:
+      - slapd
+      - ldap-utils
+
+install:
+  - pip install tox
+
+matrix:
+  include:
+    - python: "3.6"
+      env: TOXENV=py36-django22
+    - python: "3.7"
+      env: TOXENV=py37-django22
+    - python: "3.8"
+      env: TOXENV=py38-django22
+    - python: "3.8"
+      env: TOXENV=py38-django30
+    - python: "3.6"
+      env: TOXENV=py36-django31
+    - python: "3.7"
+      env: TOXENV=py37-django31
+    - python: "3.8"
+      env: TOXENV=py38-django31
+    - python: "3.7"
+      env: TOXENV=py37-django32
+    - python: "3.8"
+      env: TOXENV=py38-django32
+
+
+    # Linting
+    - python: "3.8"
+      env: TOXENV=lint
+
+notifications:
+  email: false
+  irc: "irc.freenode.org#xelnext"
diff -pruN 1.5.1-3/ChangeLog 2.0.0-1/ChangeLog
--- 1.5.1-3/ChangeLog	2020-10-12 15:56:49.000000000 +0000
+++ 2.0.0-1/ChangeLog	2025-01-12 12:07:21.000000000 +0000
@@ -1,6 +1,18 @@
 ChangeLog
 =========
 
+2.0.0 (2025-01-12)
+------------------
+
+*New:*
+
+- Support Django 4 and Django 5
+
+*Breaking:*
+
+- Removed support for Django 3
+
+
 1.5.1 (2020-10-12)
 ------------------
 
diff -pruN 1.5.1-3/PKG-INFO 2.0.0-1/PKG-INFO
--- 1.5.1-3/PKG-INFO	2020-10-12 15:56:49.000000000 +0000
+++ 2.0.0-1/PKG-INFO	1970-01-01 00:00:00.000000000 +0000
@@ -1,264 +0,0 @@
-Metadata-Version: 2.1
-Name: django-ldapdb
-Version: 1.5.1
-Summary: A LDAP database backend for Django
-Home-page: https://github.com/django-ldapdb/django-ldapdb
-Author: Jeremy Lainé
-Author-email: jeremy.laine@m4x.org
-Maintainer: Raphaël Barrois
-Maintainer-email: raphael.barrois+django-ldapdb@polytechnique.org
-License: BSD
-Description: django-ldapdb
-        =============
-        
-        .. image:: https://secure.travis-ci.org/django-ldapdb/django-ldapdb.png?branch=master
-            :target: http://travis-ci.org/django-ldapdb/django-ldapdb/
-        
-        .. image:: https://img.shields.io/pypi/v/django-ldapdb.svg
-            :target: https://pypi.python.org/pypi/django-ldapdb/
-            :alt: Latest Version
-        
-        .. image:: https://img.shields.io/pypi/pyversions/django-ldapdb.svg
-            :target: https://pypi.python.org/pypi/django-ldapdb/
-            :alt: Supported Python versions
-        
-        .. image:: https://img.shields.io/pypi/wheel/django-ldapdb.svg
-            :target: https://pypi.python.org/pypi/django-ldapdb/
-            :alt: Wheel status
-        
-        .. image:: https://img.shields.io/pypi/l/django-ldapdb.svg
-            :target: https://pypi.python.org/pypi/django-ldapdb/
-            :alt: License
-        
-        
-        ``django-ldapdb`` is an LDAP database backend for Django, allowing to manipulate
-        LDAP entries through Django models.
-        
-        It supports most of the same APIs as a Django model:
-        
-        * ``MyModel.objects.create()``
-        * ``MyModel.objects.filter(x=1, y__contains=2)``
-        * Full admin support and browsing
-        
-        
-        ``django-ldapdb`` supports every upstream-supported Django version, based on
-        the `Django support policy <https://www.djangoproject.com/download/#supported-versions>`_.
-        
-        For the current version, the following versions are supported:
-        
-        - Django 2.2 (LTS), under Python 3.6 - 3.8 (Python 3.5 has reached its end of life);
-        - Django 3.0, under Python 3.6 - 3.8;
-        - Django 3.1, under Python 3.6 - 3.8.
-        
-        
-        Installing django-ldapdb
-        ------------------------
-        
-        Linux
-        ~~~~~
-        
-        Use pip: ``pip install django-ldapdb``
-        
-        You might also need the usual ``LDAP`` packages from your distribution, usually named ``openldap`` or ``ldap-utils``.
-        
-        
-        Windows
-        ~~~~~~~
-        
-        ``django-ldapdb`` depends on the `python-ldap <https://pypi.python.org/pypi/python-ldap>` project.
-        Either follow `its Windows installation guide <https://www.python-ldap.org/en/latest/installing.html>`_,
-        or install a pre-built version from https://www.lfd.uci.edu/~gohlke/pythonlibs/#python-ldap
-        (choose the ``.whl`` file matching your Python/Windows combination, and install it with ``pip install python-ldap-3...whl``).
-        
-        You may then install ``django-ldapdb`` with
-        
-        ``pip install django-ldapdb``
-        
-        
-        Using django-ldapdb
-        -------------------
-        
-        Add the following to your ``settings.py``:
-        
-        .. code-block:: python
-        
-            DATABASES = {
-                'ldap': {
-                    'ENGINE': 'ldapdb.backends.ldap',
-                    'NAME': 'ldap://ldap.nodomain.org/',
-                    'USER': 'cn=admin,dc=nodomain,dc=org',
-                    'PASSWORD': 'some_secret_password',
-                 },
-                'default': {
-                    'ENGINE': 'django.db.backends.sqlite3',
-                    'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
-                 },
-            }
-            DATABASE_ROUTERS = ['ldapdb.router.Router']
-        
-        
-        
-        If you want to access posixGroup entries in your application, you can add
-        something like this to your ``models.py``:
-        
-        
-        .. code-block:: python
-        
-            from ldapdb.models.fields import CharField, IntegerField, ListField
-            import ldapdb.models
-        
-            class LdapGroup(ldapdb.models.Model):
-                """
-                Class for representing an LDAP group entry.
-                """
-                # LDAP meta-data
-                base_dn = "ou=groups,dc=nodomain,dc=org"
-                object_classes = ['posixGroup']
-        
-                # posixGroup attributes
-                gid = IntegerField(db_column='gidNumber', unique=True)
-                name = CharField(db_column='cn', max_length=200, primary_key=True)
-                members = ListField(db_column='memberUid')
-        
-                def __str__(self):
-                    return self.name
-        
-                def __unicode__(self):
-                    return self.name
-        
-        and add this to your ``admin.py``:
-        
-        .. code-block:: python
-        
-            from django.contrib import admin
-            from . import models
-        
-            class LDAPGroupAdmin(admin.ModelAdmin):
-                exclude = ['dn', 'objectClass']
-                list_display = ['gid', 'name']
-        
-            admin.site.register(models.LDAPGroup, LDAPGroupAdmin)
-        
-        
-        **Important note:**
-            You **must** declare an attribute to be used as the primary key.
-            This attribute will play a special role, as it will be used to build
-            the Relative Distinguished Name of the entry.
-            
-            For instance in the example above, a group whose cn is ``foo``
-            will have the DN ``cn=foo,ou=groups,dc=nodomain,dc=org``.
-        
-        
-        Supported fields
-        ----------------
-        
-        djanglo-ldapdb provides the following fields, all imported from ``ldapdb.models.fields``:
-        
-        Similar to Django:
-        
-            * ``IntegerField``
-            * ``FloatField``
-            * ``BooleanField``
-            * ``CharField``
-            * ``ImageField``
-            * ``DateTimeField``
-        
-        Specific to a LDAP server:
-            * ``ListField`` (holds a list of text values)
-            * ``TimestampField`` (Stores a datetime as a posix timestamp, typically for posixAccount)
-        
-        Legacy:
-            * ``DateField`` (Stores a date in an arbitrary format. A LDAP server has no notion of ``Date``).
-        
-        
-        Tuning django-ldapdb
-        --------------------
-        
-        It is possible to adjust django-ldapdb's behavior by defining a few parameters in the ``DATABASE`` section:
-        
-        ``PAGE_SIZE`` (default: ``1000``)
-            Define the maximum size of a results page to be returned by the server
-        
-        ``QUERY_TIMEOUT`` (default: no limit)
-            Define the maximum time in seconds we'll wait to get a reply from the server (on a per-query basis).
-        
-            .. note:: This setting applies on individual requests; if a high-level operation requires many
-                      queries (for instance a paginated search yielding thousands of entries),
-                      the timeout will be used on each individual request;
-                      the overall processing time might be much higher.
-        
-        
-        Developing with a LDAP server
-        -----------------------------
-        
-        When developing against a LDAP server, having access to a development LDAP server often proves
-        useful.
-        
-        django-ldapdb uses the `volatildap project <https://pypi.org/project/volatildap>`_ for this purpose:
-        
-        - A LDAP server is instantiated for each TestClass;
-        - Its content is reset at the start of each test function;
-        - It can be customized to embark any schemas required by the application;
-        - Starting with volatildap 1.4.0, the volatildap server can be controlled remotely, avoiding the need
-          to install a LDAP server on the host.
-        
-        Applications using django-ldapdb may use the following code snippet when setting up their tests:
-        
-        .. code-block:: python
-        
-            # This snippet is released in the Public Domain
-        
-            from django.conf import settings
-            from django.test import TestCase
-        
-            import volatildap
-        
-            class LdapEnabledTestCase(TestCase):
-                @classmethod
-                def setUpClass(cls):
-                    super().setUpClass()
-                    cls.ldap = volatildap.LdapServer(
-                        # Load some initial data
-                        initial={'ou=people': {
-                            'ou': ['people'],
-                            'objectClass': ['organizationalUnit'],
-                        }},
-                        # Enable more LDAP schemas
-                        schemas=['core.schema', 'cosine.schema', 'inetorgperson.schema', 'nis.schema'],
-                    )
-                    # The volatildap server uses specific defaults, and listens on an arbitrary port.
-                    # Copy the server-side values to Django settings
-                    settings.DATABASES['ldap']['USER'] = cls.ldap.rootdn
-                    settings.DATABASES['ldap']['PASSWORD'] = cls.ldap.rootpw
-                    settings.DATABASES['ldap']['NAME'] = cls.ldap.uri
-        
-                def setUp(self):
-                    super().setUp()
-                    # Starting an already-started volatildap server performs a data reset
-                    self.ldap.start()
-        
-                @classmethod
-                def tearDownClass(cls):
-                    # Free up resources on teardown.
-                    cls.ldap.stop()
-                    super().tearDownClass()
-        
-Keywords: django,ldap,database,ldapdb
-Platform: UNKNOWN
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Environment :: Web Environment
-Classifier: Framework :: Django :: 2.2
-Classifier: Framework :: Django :: 3.0
-Classifier: Framework :: Django :: 3.1
-Classifier: Intended Audience :: Developers
-Classifier: Intended Audience :: System Administrators
-Classifier: License :: OSI Approved :: BSD License
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Topic :: Internet :: WWW/HTTP
-Classifier: Topic :: System :: Systems Administration :: Authentication/Directory :: LDAP
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Requires-Python: >=3.6
-Provides-Extra: dev
diff -pruN 1.5.1-3/README.rst 2.0.0-1/README.rst
--- 1.5.1-3/README.rst	2020-10-12 15:56:49.000000000 +0000
+++ 2.0.0-1/README.rst	2025-01-12 12:07:21.000000000 +0000
@@ -36,9 +36,8 @@ the `Django support policy <https://www.
 
 For the current version, the following versions are supported:
 
-- Django 2.2 (LTS), under Python 3.6 - 3.8 (Python 3.5 has reached its end of life);
-- Django 3.0, under Python 3.6 - 3.8;
-- Django 3.1, under Python 3.6 - 3.8.
+- Django 4.2 (LTS), under Python 3.8 - 3.12;
+- Django 5.0 or 5.1, under Python 3.10 - 3.13
 
 
 Installing django-ldapdb
diff -pruN 1.5.1-3/debian/changelog 2.0.0-1/debian/changelog
--- 1.5.1-3/debian/changelog	2021-11-05 16:54:09.000000000 +0000
+++ 2.0.0-1/debian/changelog	2025-11-08 08:07:45.000000000 +0000
@@ -1,3 +1,34 @@
+django-ldapdb (2.0.0-1) unstable; urgency=medium
+
+  * Team upload.
+  * [c364b27] d/watch: Convert to version 5
+  * [334d269] d/gbp.conf: Add some more defaults
+  * [2490b2e] New upstream version 2.0.0
+  * [ec76326] Rebuild patch queue from patch-queue branch
+    Added patch:
+    setup.cfg-Adjust-the-version.patch
+    Removed patches (included upstream):
+    0001-Use-_base_manager-instead-of-objects-when-modifying-.patch
+    0002-router-disallow-migrations-on-ldap-connection-and-mo.patch
+    0003-Use-get_attname-instead-of-attname-attribute.patch
+    0004-tests-add-missing-contribute_to_class-to-fully-insta.patch
+    0005-Update-regex-to-be-compatible-with-django-2-to-Djang.patch
+  * [0984008] debian: Run wrap-and-sort
+    No code changes beside the reordering.
+  * [e74e7fb] autopkgtest: Remove the testing call fully
+    Upstream is depending on the package volatildap to run any testing.
+    This package was removed in 2023 in Debian as it's not in any active
+    upstream development anymore.
+    The library itself hasn't any dependency on volatildap.
+    (Closes: #1119677)
+  * [70caab6] d/control: Bump Standards-Version to 4.7.2
+    No further changes needed.
+  * [0a32e3f] d/control: Remove Rules-Requires-Root
+    The setting of Rules-Requires-Root: no is now default.
+  * [409418a] d/control: Add Testsuite: autopkgtest-pkg-python
+
+ -- Carsten Schoenert <c.schoenert@t-online.de>  Sat, 08 Nov 2025 10:07:45 +0200
+
 django-ldapdb (1.5.1-3) unstable; urgency=medium
 
   * Team upload.
diff -pruN 1.5.1-3/debian/control 2.0.0-1/debian/control
--- 1.5.1-3/debian/control	2021-11-05 16:54:09.000000000 +0000
+++ 2.0.0-1/debian/control	2025-11-08 08:07:45.000000000 +0000
@@ -1,23 +1,25 @@
 Source: django-ldapdb
 Maintainer: Debian Python Team <team+python@tracker.debian.org>
-Uploaders: Pierre-Elliott Bécue <peb@debian.org>
+Uploaders:
+ Pierre-Elliott Bécue <peb@debian.org>,
 Homepage: https://github.com/django-ldapdb/django-ldapdb
 Section: python
 Priority: optional
-Build-Depends: debhelper-compat (= 13),
-               dh-python,
-               python3-all,
-               python3-setuptools,
-               python3-django,
-               python3-ldap
-Standards-Version: 4.6.0
+Build-Depends:
+ debhelper-compat (= 13),
+ dh-sequence-python3,
+ python3-all,
+ python3-setuptools,
+Standards-Version: 4.7.2
 Vcs-Git: https://salsa.debian.org/python-team/packages/django-ldapdb.git
 Vcs-Browser: https://salsa.debian.org/python-team/packages/django-ldapdb
-Rules-Requires-Root: no
+Testsuite: autopkgtest-pkg-python
 
 Package: python3-django-ldapdb
 Architecture: all
-Depends: ${misc:Depends}, ${python3:Depends}
+Depends:
+ ${misc:Depends},
+ ${python3:Depends},
 Description: Python3 LDAP database backend for Django
  django-ldapdb is an LDAP database backend for Django, allowing one to
  manipulate LDAP entries through Django models.
diff -pruN 1.5.1-3/debian/gbp.conf 2.0.0-1/debian/gbp.conf
--- 1.5.1-3/debian/gbp.conf	2021-09-26 15:53:03.000000000 +0000
+++ 2.0.0-1/debian/gbp.conf	2025-11-08 07:42:46.000000000 +0000
@@ -1,3 +1,11 @@
 [DEFAULT]
-debian-branch=debian/master
-pristine-tar=True
+compression = gz
+debian-branch = debian/master
+pristine-tar = True
+upstream-branch = upstream
+
+[pq]
+patch-numbers = False
+
+[dch]
+id-length = 7
diff -pruN 1.5.1-3/debian/patches/0001-Use-_base_manager-instead-of-objects-when-modifying-.patch 2.0.0-1/debian/patches/0001-Use-_base_manager-instead-of-objects-when-modifying-.patch
--- 1.5.1-3/debian/patches/0001-Use-_base_manager-instead-of-objects-when-modifying-.patch	2021-11-05 16:50:18.000000000 +0000
+++ 2.0.0-1/debian/patches/0001-Use-_base_manager-instead-of-objects-when-modifying-.patch	1970-01-01 00:00:00.000000000 +0000
@@ -1,127 +0,0 @@
-From: Bryan Davis <bd808@wikimedia.org>
-Date: Wed, 17 Jul 2019 21:00:54 -0600
-Subject: Use _base_manager instead of objects when modifying model
-
-Guard against issues with a non-empty default QuerySet returned by
-a Model's Manager instance by calling the Model's _base_manager when
-doing lookups by dn. LDAP lookups by dn must be done by setting the dn
-as the base of the LDAP query.
-
-The current method for determining if a dn lookup is being requested
-relies on inspecting the generated django.db.models.sql.query.Query and
-looking for a 'dn' target column in the first where clause statement. If
-a Model uses a custom Manager to append a where clause statement to all
-QuerySets, this logic is broken. Using _base_manager instead of objects
-as the Manager for constructing explicit dn lookups avoids this problem.
-This behavior also matches the Django documentation and internals for
-related object access, so it is likely to continue to work for the
-foreseeable future.
-
-Fixes #196
-
-Forwarded: not-needed
----
- examples/models.py    | 13 +++++++++++++
- examples/tests.py     | 43 ++++++++++++++++++++++++++++++++++++++++++-
- ldapdb/models/base.py |  2 +-
- 3 files changed, 56 insertions(+), 2 deletions(-)
-
-diff --git a/examples/models.py b/examples/models.py
-index a1800fe..d241989 100644
---- a/examples/models.py
-+++ b/examples/models.py
-@@ -2,6 +2,8 @@
- # This software is distributed under the two-clause BSD license.
- # Copyright (c) The django-ldapdb project
- 
-+from django.db.models import Manager
-+
- import ldapdb.models
- from ldapdb.models import fields
- 
-@@ -98,3 +100,14 @@ class AbstractGroup(ldapdb.models.Model):
- 
- class ConcreteGroup(AbstractGroup):
-     base_dn = "ou=groups,dc=example,dc=org"
-+
-+
-+class FooNamePrefixManager(Manager):
-+    def get_queryset(self):
-+        return super(FooNamePrefixManager, self).get_queryset().filter(
-+            name__startswith='foo')
-+
-+
-+class FooGroup(AbstractGroup):
-+    base_dn = "ou=groups,dc=example,dc=org"
-+    objects = FooNamePrefixManager()
-diff --git a/examples/tests.py b/examples/tests.py
-index 5ad2d84..5d6e442 100644
---- a/examples/tests.py
-+++ b/examples/tests.py
-@@ -18,7 +18,8 @@ from django.db.models import Count, Q
- from django.test import TestCase
- from django.utils import timezone
- 
--from examples.models import ConcreteGroup, LdapGroup, LdapMultiPKRoom, LdapUser
-+from examples.models import (ConcreteGroup, FooGroup, LdapGroup,
-+                             LdapMultiPKRoom, LdapUser)
- from ldapdb.backends.ldap.compiler import SQLCompiler, query_as_ldap
- 
- groups = ('ou=groups,dc=example,dc=org', {
-@@ -890,3 +891,43 @@ class AdminTestCase(BaseTestCase):
-         response = self.client.post('/admin/examples/ldapuser/foouser/delete/',
-                                     {'yes': 'post'})
-         self.assertRedirects(response, '/admin/examples/ldapuser/')
-+
-+
-+class FooGroupTestCase(BaseTestCase):
-+    directory = dict([groups, foogroup, bargroup, wizgroup, people, foouser])
-+
-+    def as_ldap_query(self, qs):
-+        connection = connections['ldap']
-+        compiler = SQLCompiler(
-+            query=qs.query,
-+            connection=connection,
-+            using=None,
-+        )
-+        return query_as_ldap(qs.query, compiler, connection)
-+
-+    def test_count_all(self):
-+        qs = FooGroup.objects.all()
-+        lq = self.as_ldap_query(qs)
-+        self.assertEqual(lq.base, groups[0])
-+        self.assertEqual(lq.filterstr, '(&(objectClass=posixGroup)(cn=foo*))')
-+        self.assertEqual(qs.count(), 1)
-+
-+    def test_base_manager_dn(self):
-+        dn = foogroup[0]
-+        qs = FooGroup._base_manager.using(None).filter(dn=dn)
-+        lq = self.as_ldap_query(qs)
-+        self.assertEqual(lq.base, dn)
-+        self.assertEqual(lq.filterstr, '(&(objectClass=posixGroup))')
-+        self.assertEqual(qs.count(), 1)
-+
-+    def test_update_group(self):
-+        g = FooGroup.objects.get(name='foogroup')
-+        g.gid = 1002
-+        g.usernames = ['foouser2', u'baruseeer2']
-+        g.save()
-+
-+        # check group was updated
-+        new = FooGroup.objects.get(name='foogroup')
-+        self.assertEqual(new.name, 'foogroup')
-+        self.assertEqual(new.gid, 1002)
-+        self.assertCountEqual(new.usernames, ['foouser2', u'baruseeer2'])
-diff --git a/ldapdb/models/base.py b/ldapdb/models/base.py
-index 6ac2827..e4d9e15 100644
---- a/ldapdb/models/base.py
-+++ b/ldapdb/models/base.py
-@@ -89,7 +89,7 @@ class Model(django.db.models.base.Model):
-         if create:
-             old = None
-         else:
--            old = cls.objects.using(using).get(dn=self._saved_dn)
-+            old = cls._base_manager.using(using).get(dn=self._saved_dn)
-         changes = {
-             field.db_column: (
-                 None if old is None else get_field_value(field, old),
diff -pruN 1.5.1-3/debian/patches/0002-router-disallow-migrations-on-ldap-connection-and-mo.patch 2.0.0-1/debian/patches/0002-router-disallow-migrations-on-ldap-connection-and-mo.patch
--- 1.5.1-3/debian/patches/0002-router-disallow-migrations-on-ldap-connection-and-mo.patch	2021-11-05 16:54:09.000000000 +0000
+++ 2.0.0-1/debian/patches/0002-router-disallow-migrations-on-ldap-connection-and-mo.patch	1970-01-01 00:00:00.000000000 +0000
@@ -1,41 +0,0 @@
-From: dzen <benoit.calvez@polyconseil.fr>
-Date: Tue, 13 Oct 2020 10:07:38 +0200
-Subject: router: disallow migrations on ldap connection and models
-
-Forwarded: not-needed
----
- ldapdb/router.py | 13 ++++++++++++-
- 1 file changed, 12 insertions(+), 1 deletion(-)
-
-diff --git a/ldapdb/router.py b/ldapdb/router.py
-index 60ff211..fddb881 100644
---- a/ldapdb/router.py
-+++ b/ldapdb/router.py
-@@ -2,6 +2,10 @@
- # This software is distributed under the two-clause BSD license.
- # Copyright (c) The django-ldapdb project
- 
-+from django.apps import apps
-+
-+from ldapdb.models import Model
-+
- 
- def is_ldap_model(model):
-     # FIXME: there is probably a better check than testing 'base_dn'
-@@ -27,8 +31,15 @@ class Router(object):
-                 break
- 
-     def allow_migrate(self, db, app_label, model_name=None, **hints):
--        if 'model' in hints and is_ldap_model(hints['model']):
-+        # disallow any migration operation on ldap engine
-+        if db == self.ldap_alias:
-             return False
-+
-+        # avoid any migration operation on ldap models
-+        if model_name:
-+            model = apps.get_model(app_label, model_name)
-+            if issubclass(model, Model):
-+                return False
-         return None
- 
-     def db_for_read(self, model, **hints):
diff -pruN 1.5.1-3/debian/patches/0003-Use-get_attname-instead-of-attname-attribute.patch 2.0.0-1/debian/patches/0003-Use-get_attname-instead-of-attname-attribute.patch
--- 1.5.1-3/debian/patches/0003-Use-get_attname-instead-of-attname-attribute.patch	2021-11-05 16:54:09.000000000 +0000
+++ 2.0.0-1/debian/patches/0003-Use-get_attname-instead-of-attname-attribute.patch	1970-01-01 00:00:00.000000000 +0000
@@ -1,45 +0,0 @@
-From: dzen <benoit.calvez@polyconseil.fr>
-Date: Tue, 13 Apr 2021 16:46:32 +0200
-Subject: Use get_attname instead of attname attribute
-
-Forwarded: not-needed
----
- ldapdb/backends/ldap/compiler.py | 4 ++--
- ldapdb/models/base.py            | 2 +-
- 2 files changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/ldapdb/backends/ldap/compiler.py b/ldapdb/backends/ldap/compiler.py
-index 4ce9f94..1d9e771 100644
---- a/ldapdb/backends/ldap/compiler.py
-+++ b/ldapdb/backends/ldap/compiler.py
-@@ -231,7 +231,7 @@ class SQLCompiler(compiler.SQLCompiler):
-                 if isinstance(e[0], aggregates.Count):
-                     value = 0
-                     input_field = e[0].get_source_expressions()[0].field
--                    if input_field.attname == 'dn':
-+                    if input_field.get_attname() == 'dn':
-                         value = 1
-                     elif hasattr(input_field, 'from_ldap'):
-                         result = input_field.from_ldap(
-@@ -243,7 +243,7 @@ class SQLCompiler(compiler.SQLCompiler):
-                                 value = len(result)
-                     row.append(value)
-                 else:
--                    if e[0].field.attname == 'dn':
-+                    if e[0].field.get_attname() == 'dn':
-                         row.append(dn)
-                     elif hasattr(e[0].field, 'from_ldap'):
-                         row.append(e[0].field.from_ldap(
-diff --git a/ldapdb/models/base.py b/ldapdb/models/base.py
-index e4d9e15..18d3d1e 100644
---- a/ldapdb/models/base.py
-+++ b/ldapdb/models/base.py
-@@ -83,7 +83,7 @@ class Model(django.db.models.base.Model):
-             ]
- 
-         def get_field_value(field, instance):
--            python_value = getattr(instance, field.attname)
-+            python_value = getattr(instance, field.get_attname())
-             return field.get_db_prep_save(python_value, connection=connection)
- 
-         if create:
diff -pruN 1.5.1-3/debian/patches/0004-tests-add-missing-contribute_to_class-to-fully-insta.patch 2.0.0-1/debian/patches/0004-tests-add-missing-contribute_to_class-to-fully-insta.patch
--- 1.5.1-3/debian/patches/0004-tests-add-missing-contribute_to_class-to-fully-insta.patch	2021-11-05 16:54:09.000000000 +0000
+++ 2.0.0-1/debian/patches/0004-tests-add-missing-contribute_to_class-to-fully-insta.patch	1970-01-01 00:00:00.000000000 +0000
@@ -1,22 +0,0 @@
-From: dzen <benoit.calvez@polyconseil.fr>
-Date: Tue, 13 Apr 2021 16:47:00 +0200
-Subject: tests: add missing contribute_to_class to fully instantiate the
- field
-
-Forwarded: not-needed
----
- ldapdb/tests.py | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/ldapdb/tests.py b/ldapdb/tests.py
-index f2da2d4..2aca0a0 100644
---- a/ldapdb/tests.py
-+++ b/ldapdb/tests.py
-@@ -82,6 +82,7 @@ class WhereTestCase(TestCase):
-     def _build_lookup(self, field_name, lookup, value, field=fields.CharField):
-         fake_field = field()
-         fake_field.set_attributes_from_name(field_name)
-+        fake_field.contribute_to_class(FakeModel, "fake")
-         lhs = expressions.Col('faketable', fake_field, fake_field)
-         lookup = lhs.get_lookup(lookup)
-         return lookup(lhs, value)
diff -pruN 1.5.1-3/debian/patches/0005-Update-regex-to-be-compatible-with-django-2-to-Djang.patch 2.0.0-1/debian/patches/0005-Update-regex-to-be-compatible-with-django-2-to-Djang.patch
--- 1.5.1-3/debian/patches/0005-Update-regex-to-be-compatible-with-django-2-to-Djang.patch	2021-11-05 16:54:09.000000000 +0000
+++ 2.0.0-1/debian/patches/0005-Update-regex-to-be-compatible-with-django-2-to-Djang.patch	1970-01-01 00:00:00.000000000 +0000
@@ -1,81 +0,0 @@
-From: dzen <benoit.calvez@polyconseil.fr>
-Date: Tue, 13 Apr 2021 16:47:44 +0200
-Subject: Update regex to be compatible with django 2 to Django 3.2
-
-Forwarded: not-needed
----
- ldapdb/backends/ldap/compiler.py | 16 +++++++++-------
- ldapdb/tests.py                  | 29 +++++++++++++++++++++++++++++
- 2 files changed, 38 insertions(+), 7 deletions(-)
-
-diff --git a/ldapdb/backends/ldap/compiler.py b/ldapdb/backends/ldap/compiler.py
-index 1d9e771..970b081 100644
---- a/ldapdb/backends/ldap/compiler.py
-+++ b/ldapdb/backends/ldap/compiler.py
-@@ -15,7 +15,8 @@ from ldapdb import escape_ldap_filter
- from ldapdb.models.fields import ListField
- 
- _ORDER_BY_LIMIT_OFFSET_RE = re.compile(
--    r'(?:\bORDER BY\b\s+(.+?))?\s*(?:\bLIMIT\b\s+(-?\d+))?\s*(?:\bOFFSET\b\s+(\d+))?$')
-+    r"(?:\bORDER BY\b\s+([\w\.]+)\s(?P<order>\bASC\b)|(\bDESC\b))\s{1,2}(?:\bLIMIT\b\s+(?P<limit>-?\d+))?[\)\s]?(?:\bOFFSET\b\s+(?P<offset>(\d+)))?"  # noqa: E501
-+)
- 
- 
- class LdapDBError(Exception):
-@@ -146,12 +147,13 @@ class SQLCompiler(compiler.SQLCompiler):
-                 if hasattr(self.query, 'subquery') and self.query.subquery:
-                     sql = self.query.subquery
-                 m = _ORDER_BY_LIMIT_OFFSET_RE.search(sql)
--                limit = m.group(2)
--                offset = m.group(3)
--                if limit and int(limit) >= 0:
--                    output.append(int(limit))
--                elif offset:
--                    output.append(len(vals) - int(offset))
-+                if m:
-+                    limit = m.group('limit')
-+                    offset = m.group('offset')
-+                    if limit and int(limit) >= 0:
-+                        output.append(int(limit))
-+                    elif offset:
-+                        output.append(len(vals) - int(offset))
-                 else:
-                     output.append(len(vals))
-             else:
-diff --git a/ldapdb/tests.py b/ldapdb/tests.py
-index 2aca0a0..8929126 100644
---- a/ldapdb/tests.py
-+++ b/ldapdb/tests.py
-@@ -246,3 +246,32 @@ class WhereTestCase(TestCase):
-         where.add(self._build_lookup("cn", 'exact', "foo", field=fields.CharField), AND)
-         where.add(self._build_lookup("givenName", 'exact', "bar", field=fields.CharField), OR)
-         self.assertEqual(self._where_as_ldap(where), "(|(cn=foo)(givenName=bar))")
-+
-+
-+class CompilerRegexTestCase(TestCase):
-+
-+    def _run_regex(self, sql):
-+        match = ldapdb_compiler._ORDER_BY_LIMIT_OFFSET_RE.search(sql)
-+        self.assertIsNotNone(match)
-+        return match
-+
-+    def test_regex(self):
-+        sql = "SELECT examples_ldapgroup.cn AS Col1 FROM examples_ldapgroup ORDER BY examples_ldapgroup.gidNumber ASC LIMIT 2"  # noqa: E501
-+        match = self._run_regex(sql)
-+        self.assertEqual(match.group('limit'), '2')
-+        self.assertEqual(match.group('offset'), None)
-+
-+        sql = "SELECT COUNT(*) FROM (SELECT examples_ldapgroup.cn AS Col1 FROM examples_ldapgroup ORDER BY examples_ldapgroup.gidNumber ASC LIMIT 2) subquery"  # noqa: E501
-+        match = self._run_regex(sql)
-+        self.assertEqual(match.group('limit'), '2')
-+
-+        sql = "SELECT COUNT(*) FROM (SELECT examples_ldapgroup.cn AS Col1 FROM examples_ldapgroup ORDER BY examples_ldapgroup.gidNumber ASC LIMIT -1 OFFSET 1) subquery"  # noqa: E501
-+        match = self._run_regex(sql)
-+        self.assertEqual(match.group('limit'), '-1')
-+        self.assertEqual(match.group('offset'), '1')
-+
-+    def test_regex_django22(self):
-+        sql = "SELECT examples_ldapgroup.cn AS Col1 FROM examples_ldapgroup ORDER BY examples_ldapgroup.gidNumber ASC  LIMIT 2"  # noqa: E501
-+        match = self._run_regex(sql)
-+        self.assertEqual(match.group('limit'), '2')
-+        self.assertEqual(match.group('offset'), None)
diff -pruN 1.5.1-3/debian/patches/series 2.0.0-1/debian/patches/series
--- 1.5.1-3/debian/patches/series	2021-11-05 16:50:18.000000000 +0000
+++ 2.0.0-1/debian/patches/series	2025-11-08 07:47:13.000000000 +0000
@@ -1,5 +1 @@
-0001-Use-_base_manager-instead-of-objects-when-modifying-.patch
-0002-router-disallow-migrations-on-ldap-connection-and-mo.patch
-0003-Use-get_attname-instead-of-attname-attribute.patch
-0004-tests-add-missing-contribute_to_class-to-fully-insta.patch
-0005-Update-regex-to-be-compatible-with-django-2-to-Djang.patch
+setup.cfg-Adjust-the-version.patch
diff -pruN 1.5.1-3/debian/patches/setup.cfg-Adjust-the-version.patch 2.0.0-1/debian/patches/setup.cfg-Adjust-the-version.patch
--- 1.5.1-3/debian/patches/setup.cfg-Adjust-the-version.patch	1970-01-01 00:00:00.000000000 +0000
+++ 2.0.0-1/debian/patches/setup.cfg-Adjust-the-version.patch	2025-11-08 07:47:13.000000000 +0000
@@ -0,0 +1,20 @@
+From: Carsten Schoenert <c.schoenert@t-online.de>
+Date: Sat, 8 Nov 2025 09:31:07 +0200
+Subject: setup.cfg: Adjust the version
+
+---
+ setup.cfg | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/setup.cfg b/setup.cfg
+index 00f22bd..015dbeb 100644
+--- a/setup.cfg
++++ b/setup.cfg
+@@ -1,6 +1,6 @@
+ [metadata]
+ name = django-ldapdb
+-version = 1.5.2.dev0
++version = 2.0.0
+ description = A LDAP database backend for Django
+ long_description = file: README.rst
+ keywords = django, ldap, database, ldapdb
diff -pruN 1.5.1-3/debian/rules 2.0.0-1/debian/rules
--- 1.5.1-3/debian/rules	2021-09-26 15:53:03.000000000 +0000
+++ 2.0.0-1/debian/rules	2025-11-08 08:07:45.000000000 +0000
@@ -1,9 +1,7 @@
 #!/usr/bin/make -f
 
 export PYBUILD_NAME=django-ldapdb
-# Done via autopkgtest, see d/tests/control. These tests require a properly
-# running slapd server to work. The build tests are not fit to do such a thing.
 export PYBUILD_DISABLE=test
 
 %:
-	dh $@ --with python3 --buildsystem=pybuild
+	dh $@ --buildsystem=pybuild
diff -pruN 1.5.1-3/debian/tests/control 2.0.0-1/debian/tests/control
--- 1.5.1-3/debian/tests/control	2021-09-26 15:53:03.000000000 +0000
+++ 2.0.0-1/debian/tests/control	1970-01-01 00:00:00.000000000 +0000
@@ -1,11 +0,0 @@
-Test-Command: python3 manage_dev.py test
-Depends: @,
-         check-manifest,
-         ldapscripts,
-         python3-isort,
-         python3-factory-boy,
-         python3-flake8,
-         python3-setuptools,
-         python3-volatildap,
-         slapd,
-Restrictions: allow-stderr
diff -pruN 1.5.1-3/debian/watch 2.0.0-1/debian/watch
--- 1.5.1-3/debian/watch	2021-09-26 15:53:03.000000000 +0000
+++ 2.0.0-1/debian/watch	2025-11-08 07:42:46.000000000 +0000
@@ -1,3 +1,9 @@
-version=4
-opts=uversionmangle=s/(rc|a|b|c)/~$1/ \
-https://pypi.debian.net/@PACKAGE@/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@
+Version: 5
+
+Source: https://github.com/django-ldapdb/django-ldapdb.git
+Matching-Pattern: refs/tags/@ANY_VERSION@
+Compression: gz
+Dversion-Mangle: s/\+ds(\.?\d+)?$//
+Uversion-Mangle: s/(\d)[_\.\-\+]?((alpha|beta|post|pre|dev|RC|rc)\.?\d*)$/$1~$2/
+Mode: git
+Pgpmode: none
diff -pruN 1.5.1-3/django_ldapdb.egg-info/PKG-INFO 2.0.0-1/django_ldapdb.egg-info/PKG-INFO
--- 1.5.1-3/django_ldapdb.egg-info/PKG-INFO	2020-10-12 15:56:49.000000000 +0000
+++ 2.0.0-1/django_ldapdb.egg-info/PKG-INFO	1970-01-01 00:00:00.000000000 +0000
@@ -1,264 +0,0 @@
-Metadata-Version: 2.1
-Name: django-ldapdb
-Version: 1.5.1
-Summary: A LDAP database backend for Django
-Home-page: https://github.com/django-ldapdb/django-ldapdb
-Author: Jeremy Lainé
-Author-email: jeremy.laine@m4x.org
-Maintainer: Raphaël Barrois
-Maintainer-email: raphael.barrois+django-ldapdb@polytechnique.org
-License: BSD
-Description: django-ldapdb
-        =============
-        
-        .. image:: https://secure.travis-ci.org/django-ldapdb/django-ldapdb.png?branch=master
-            :target: http://travis-ci.org/django-ldapdb/django-ldapdb/
-        
-        .. image:: https://img.shields.io/pypi/v/django-ldapdb.svg
-            :target: https://pypi.python.org/pypi/django-ldapdb/
-            :alt: Latest Version
-        
-        .. image:: https://img.shields.io/pypi/pyversions/django-ldapdb.svg
-            :target: https://pypi.python.org/pypi/django-ldapdb/
-            :alt: Supported Python versions
-        
-        .. image:: https://img.shields.io/pypi/wheel/django-ldapdb.svg
-            :target: https://pypi.python.org/pypi/django-ldapdb/
-            :alt: Wheel status
-        
-        .. image:: https://img.shields.io/pypi/l/django-ldapdb.svg
-            :target: https://pypi.python.org/pypi/django-ldapdb/
-            :alt: License
-        
-        
-        ``django-ldapdb`` is an LDAP database backend for Django, allowing to manipulate
-        LDAP entries through Django models.
-        
-        It supports most of the same APIs as a Django model:
-        
-        * ``MyModel.objects.create()``
-        * ``MyModel.objects.filter(x=1, y__contains=2)``
-        * Full admin support and browsing
-        
-        
-        ``django-ldapdb`` supports every upstream-supported Django version, based on
-        the `Django support policy <https://www.djangoproject.com/download/#supported-versions>`_.
-        
-        For the current version, the following versions are supported:
-        
-        - Django 2.2 (LTS), under Python 3.6 - 3.8 (Python 3.5 has reached its end of life);
-        - Django 3.0, under Python 3.6 - 3.8;
-        - Django 3.1, under Python 3.6 - 3.8.
-        
-        
-        Installing django-ldapdb
-        ------------------------
-        
-        Linux
-        ~~~~~
-        
-        Use pip: ``pip install django-ldapdb``
-        
-        You might also need the usual ``LDAP`` packages from your distribution, usually named ``openldap`` or ``ldap-utils``.
-        
-        
-        Windows
-        ~~~~~~~
-        
-        ``django-ldapdb`` depends on the `python-ldap <https://pypi.python.org/pypi/python-ldap>` project.
-        Either follow `its Windows installation guide <https://www.python-ldap.org/en/latest/installing.html>`_,
-        or install a pre-built version from https://www.lfd.uci.edu/~gohlke/pythonlibs/#python-ldap
-        (choose the ``.whl`` file matching your Python/Windows combination, and install it with ``pip install python-ldap-3...whl``).
-        
-        You may then install ``django-ldapdb`` with
-        
-        ``pip install django-ldapdb``
-        
-        
-        Using django-ldapdb
-        -------------------
-        
-        Add the following to your ``settings.py``:
-        
-        .. code-block:: python
-        
-            DATABASES = {
-                'ldap': {
-                    'ENGINE': 'ldapdb.backends.ldap',
-                    'NAME': 'ldap://ldap.nodomain.org/',
-                    'USER': 'cn=admin,dc=nodomain,dc=org',
-                    'PASSWORD': 'some_secret_password',
-                 },
-                'default': {
-                    'ENGINE': 'django.db.backends.sqlite3',
-                    'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
-                 },
-            }
-            DATABASE_ROUTERS = ['ldapdb.router.Router']
-        
-        
-        
-        If you want to access posixGroup entries in your application, you can add
-        something like this to your ``models.py``:
-        
-        
-        .. code-block:: python
-        
-            from ldapdb.models.fields import CharField, IntegerField, ListField
-            import ldapdb.models
-        
-            class LdapGroup(ldapdb.models.Model):
-                """
-                Class for representing an LDAP group entry.
-                """
-                # LDAP meta-data
-                base_dn = "ou=groups,dc=nodomain,dc=org"
-                object_classes = ['posixGroup']
-        
-                # posixGroup attributes
-                gid = IntegerField(db_column='gidNumber', unique=True)
-                name = CharField(db_column='cn', max_length=200, primary_key=True)
-                members = ListField(db_column='memberUid')
-        
-                def __str__(self):
-                    return self.name
-        
-                def __unicode__(self):
-                    return self.name
-        
-        and add this to your ``admin.py``:
-        
-        .. code-block:: python
-        
-            from django.contrib import admin
-            from . import models
-        
-            class LDAPGroupAdmin(admin.ModelAdmin):
-                exclude = ['dn', 'objectClass']
-                list_display = ['gid', 'name']
-        
-            admin.site.register(models.LDAPGroup, LDAPGroupAdmin)
-        
-        
-        **Important note:**
-            You **must** declare an attribute to be used as the primary key.
-            This attribute will play a special role, as it will be used to build
-            the Relative Distinguished Name of the entry.
-            
-            For instance in the example above, a group whose cn is ``foo``
-            will have the DN ``cn=foo,ou=groups,dc=nodomain,dc=org``.
-        
-        
-        Supported fields
-        ----------------
-        
-        djanglo-ldapdb provides the following fields, all imported from ``ldapdb.models.fields``:
-        
-        Similar to Django:
-        
-            * ``IntegerField``
-            * ``FloatField``
-            * ``BooleanField``
-            * ``CharField``
-            * ``ImageField``
-            * ``DateTimeField``
-        
-        Specific to a LDAP server:
-            * ``ListField`` (holds a list of text values)
-            * ``TimestampField`` (Stores a datetime as a posix timestamp, typically for posixAccount)
-        
-        Legacy:
-            * ``DateField`` (Stores a date in an arbitrary format. A LDAP server has no notion of ``Date``).
-        
-        
-        Tuning django-ldapdb
-        --------------------
-        
-        It is possible to adjust django-ldapdb's behavior by defining a few parameters in the ``DATABASE`` section:
-        
-        ``PAGE_SIZE`` (default: ``1000``)
-            Define the maximum size of a results page to be returned by the server
-        
-        ``QUERY_TIMEOUT`` (default: no limit)
-            Define the maximum time in seconds we'll wait to get a reply from the server (on a per-query basis).
-        
-            .. note:: This setting applies on individual requests; if a high-level operation requires many
-                      queries (for instance a paginated search yielding thousands of entries),
-                      the timeout will be used on each individual request;
-                      the overall processing time might be much higher.
-        
-        
-        Developing with a LDAP server
-        -----------------------------
-        
-        When developing against a LDAP server, having access to a development LDAP server often proves
-        useful.
-        
-        django-ldapdb uses the `volatildap project <https://pypi.org/project/volatildap>`_ for this purpose:
-        
-        - A LDAP server is instantiated for each TestClass;
-        - Its content is reset at the start of each test function;
-        - It can be customized to embark any schemas required by the application;
-        - Starting with volatildap 1.4.0, the volatildap server can be controlled remotely, avoiding the need
-          to install a LDAP server on the host.
-        
-        Applications using django-ldapdb may use the following code snippet when setting up their tests:
-        
-        .. code-block:: python
-        
-            # This snippet is released in the Public Domain
-        
-            from django.conf import settings
-            from django.test import TestCase
-        
-            import volatildap
-        
-            class LdapEnabledTestCase(TestCase):
-                @classmethod
-                def setUpClass(cls):
-                    super().setUpClass()
-                    cls.ldap = volatildap.LdapServer(
-                        # Load some initial data
-                        initial={'ou=people': {
-                            'ou': ['people'],
-                            'objectClass': ['organizationalUnit'],
-                        }},
-                        # Enable more LDAP schemas
-                        schemas=['core.schema', 'cosine.schema', 'inetorgperson.schema', 'nis.schema'],
-                    )
-                    # The volatildap server uses specific defaults, and listens on an arbitrary port.
-                    # Copy the server-side values to Django settings
-                    settings.DATABASES['ldap']['USER'] = cls.ldap.rootdn
-                    settings.DATABASES['ldap']['PASSWORD'] = cls.ldap.rootpw
-                    settings.DATABASES['ldap']['NAME'] = cls.ldap.uri
-        
-                def setUp(self):
-                    super().setUp()
-                    # Starting an already-started volatildap server performs a data reset
-                    self.ldap.start()
-        
-                @classmethod
-                def tearDownClass(cls):
-                    # Free up resources on teardown.
-                    cls.ldap.stop()
-                    super().tearDownClass()
-        
-Keywords: django,ldap,database,ldapdb
-Platform: UNKNOWN
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Environment :: Web Environment
-Classifier: Framework :: Django :: 2.2
-Classifier: Framework :: Django :: 3.0
-Classifier: Framework :: Django :: 3.1
-Classifier: Intended Audience :: Developers
-Classifier: Intended Audience :: System Administrators
-Classifier: License :: OSI Approved :: BSD License
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Topic :: Internet :: WWW/HTTP
-Classifier: Topic :: System :: Systems Administration :: Authentication/Directory :: LDAP
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Requires-Python: >=3.6
-Provides-Extra: dev
diff -pruN 1.5.1-3/django_ldapdb.egg-info/SOURCES.txt 2.0.0-1/django_ldapdb.egg-info/SOURCES.txt
--- 1.5.1-3/django_ldapdb.egg-info/SOURCES.txt	2020-10-12 15:56:49.000000000 +0000
+++ 2.0.0-1/django_ldapdb.egg-info/SOURCES.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1,36 +0,0 @@
-AUTHORS
-CODE_OF_CONDUCT.md
-CONTRIBUTING.rst
-ChangeLog
-LICENSE
-MANIFEST.in
-Makefile
-README.rst
-manage_dev.py
-setup.cfg
-setup.py
-tox.ini
-django_ldapdb.egg-info/PKG-INFO
-django_ldapdb.egg-info/SOURCES.txt
-django_ldapdb.egg-info/dependency_links.txt
-django_ldapdb.egg-info/not-zip-safe
-django_ldapdb.egg-info/requires.txt
-django_ldapdb.egg-info/top_level.txt
-examples/__init__.py
-examples/admin.py
-examples/models.py
-examples/settings.py
-examples/tests.py
-examples/urls.py
-examples/fixtures/test_users.json
-ldapdb/__init__.py
-ldapdb/router.py
-ldapdb/tests.py
-ldapdb/version.py
-ldapdb/backends/__init__.py
-ldapdb/backends/ldap/__init__.py
-ldapdb/backends/ldap/base.py
-ldapdb/backends/ldap/compiler.py
-ldapdb/models/__init__.py
-ldapdb/models/base.py
-ldapdb/models/fields.py
\ No newline at end of file
diff -pruN 1.5.1-3/django_ldapdb.egg-info/dependency_links.txt 2.0.0-1/django_ldapdb.egg-info/dependency_links.txt
--- 1.5.1-3/django_ldapdb.egg-info/dependency_links.txt	2020-10-12 15:56:49.000000000 +0000
+++ 2.0.0-1/django_ldapdb.egg-info/dependency_links.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-
diff -pruN 1.5.1-3/django_ldapdb.egg-info/not-zip-safe 2.0.0-1/django_ldapdb.egg-info/not-zip-safe
--- 1.5.1-3/django_ldapdb.egg-info/not-zip-safe	2020-10-12 15:56:49.000000000 +0000
+++ 2.0.0-1/django_ldapdb.egg-info/not-zip-safe	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-
diff -pruN 1.5.1-3/django_ldapdb.egg-info/requires.txt 2.0.0-1/django_ldapdb.egg-info/requires.txt
--- 1.5.1-3/django_ldapdb.egg-info/requires.txt	2020-10-12 15:56:49.000000000 +0000
+++ 2.0.0-1/django_ldapdb.egg-info/requires.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1,12 +0,0 @@
-Django>=2.2
-python-ldap>=3.0
-
-[dev]
-check-manifest
-flake8
-isort>=5.0.0
-tox
-factory_boy
-volatildap>=1.1.0
-wheel
-zest.releaser[recommended]
diff -pruN 1.5.1-3/django_ldapdb.egg-info/top_level.txt 2.0.0-1/django_ldapdb.egg-info/top_level.txt
--- 1.5.1-3/django_ldapdb.egg-info/top_level.txt	2020-10-12 15:56:49.000000000 +0000
+++ 2.0.0-1/django_ldapdb.egg-info/top_level.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-ldapdb
diff -pruN 1.5.1-3/examples/models.py 2.0.0-1/examples/models.py
--- 1.5.1-3/examples/models.py	2020-10-12 15:56:49.000000000 +0000
+++ 2.0.0-1/examples/models.py	2025-01-12 12:07:21.000000000 +0000
@@ -2,6 +2,8 @@
 # This software is distributed under the two-clause BSD license.
 # Copyright (c) The django-ldapdb project
 
+from django.db.models import Manager
+
 import ldapdb.models
 from ldapdb.models import fields
 
@@ -98,3 +100,14 @@ class AbstractGroup(ldapdb.models.Model)
 
 class ConcreteGroup(AbstractGroup):
     base_dn = "ou=groups,dc=example,dc=org"
+
+
+class FooNamePrefixManager(Manager):
+    def get_queryset(self):
+        return super(FooNamePrefixManager, self).get_queryset().filter(
+            name__startswith='foo')
+
+
+class FooGroup(AbstractGroup):
+    base_dn = "ou=groups,dc=example,dc=org"
+    objects = FooNamePrefixManager()
diff -pruN 1.5.1-3/examples/settings.py 2.0.0-1/examples/settings.py
--- 1.5.1-3/examples/settings.py	2020-10-12 15:56:49.000000000 +0000
+++ 2.0.0-1/examples/settings.py	2025-01-12 12:07:21.000000000 +0000
@@ -45,10 +45,6 @@ LANGUAGE_CODE = 'en-us'
 # to load the internationalization machinery.
 USE_I18N = True
 
-# If you set this to False, Django will not format dates, numbers and
-# calendars according to the current locale
-USE_L10N = True
-
 USE_TZ = True
 
 # Absolute filesystem path to the directory that will hold user-uploaded files.
diff -pruN 1.5.1-3/examples/tests.py 2.0.0-1/examples/tests.py
--- 1.5.1-3/examples/tests.py	2020-10-12 15:56:49.000000000 +0000
+++ 2.0.0-1/examples/tests.py	2025-01-12 12:07:21.000000000 +0000
@@ -18,7 +18,8 @@ from django.db.models import Count, Q
 from django.test import TestCase
 from django.utils import timezone
 
-from examples.models import ConcreteGroup, LdapGroup, LdapMultiPKRoom, LdapUser
+from examples.models import (ConcreteGroup, FooGroup, LdapGroup,
+                             LdapMultiPKRoom, LdapUser)
 from ldapdb.backends.ldap.compiler import SQLCompiler, query_as_ldap
 
 groups = ('ou=groups,dc=example,dc=org', {
@@ -890,3 +891,43 @@ class AdminTestCase(BaseTestCase):
         response = self.client.post('/admin/examples/ldapuser/foouser/delete/',
                                     {'yes': 'post'})
         self.assertRedirects(response, '/admin/examples/ldapuser/')
+
+
+class FooGroupTestCase(BaseTestCase):
+    directory = dict([groups, foogroup, bargroup, wizgroup, people, foouser])
+
+    def as_ldap_query(self, qs):
+        connection = connections['ldap']
+        compiler = SQLCompiler(
+            query=qs.query,
+            connection=connection,
+            using=None,
+        )
+        return query_as_ldap(qs.query, compiler, connection)
+
+    def test_count_all(self):
+        qs = FooGroup.objects.all()
+        lq = self.as_ldap_query(qs)
+        self.assertEqual(lq.base, groups[0])
+        self.assertEqual(lq.filterstr, '(&(objectClass=posixGroup)(cn=foo*))')
+        self.assertEqual(qs.count(), 1)
+
+    def test_base_manager_dn(self):
+        dn = foogroup[0]
+        qs = FooGroup._base_manager.using(None).filter(dn=dn)
+        lq = self.as_ldap_query(qs)
+        self.assertEqual(lq.base, dn)
+        self.assertEqual(lq.filterstr, '(&(objectClass=posixGroup))')
+        self.assertEqual(qs.count(), 1)
+
+    def test_update_group(self):
+        g = FooGroup.objects.get(name='foogroup')
+        g.gid = 1002
+        g.usernames = ['foouser2', u'baruseeer2']
+        g.save()
+
+        # check group was updated
+        new = FooGroup.objects.get(name='foogroup')
+        self.assertEqual(new.name, 'foogroup')
+        self.assertEqual(new.gid, 1002)
+        self.assertCountEqual(new.usernames, ['foouser2', u'baruseeer2'])
diff -pruN 1.5.1-3/ldapdb/backends/ldap/compiler.py 2.0.0-1/ldapdb/backends/ldap/compiler.py
--- 1.5.1-3/ldapdb/backends/ldap/compiler.py	2020-10-12 15:56:49.000000000 +0000
+++ 2.0.0-1/ldapdb/backends/ldap/compiler.py	2025-01-12 12:07:21.000000000 +0000
@@ -15,7 +15,8 @@ from ldapdb import escape_ldap_filter
 from ldapdb.models.fields import ListField
 
 _ORDER_BY_LIMIT_OFFSET_RE = re.compile(
-    r'(?:\bORDER BY\b\s+(.+?))?\s*(?:\bLIMIT\b\s+(-?\d+))?\s*(?:\bOFFSET\b\s+(\d+))?$')
+    r"(?:\bORDER BY\b\s+([\w\.]+)\s(?P<order>\bASC\b)|(\bDESC\b))\s{1,2}(?:\bLIMIT\b\s+(?P<limit>-?\d+))?[\)\s]?(?:\bOFFSET\b\s+(?P<offset>(\d+)))?"  # noqa: E501
+)
 
 
 class LdapDBError(Exception):
@@ -146,12 +147,13 @@ class SQLCompiler(compiler.SQLCompiler):
                 if hasattr(self.query, 'subquery') and self.query.subquery:
                     sql = self.query.subquery
                 m = _ORDER_BY_LIMIT_OFFSET_RE.search(sql)
-                limit = m.group(2)
-                offset = m.group(3)
-                if limit and int(limit) >= 0:
-                    output.append(int(limit))
-                elif offset:
-                    output.append(len(vals) - int(offset))
+                if m:
+                    limit = m.group('limit')
+                    offset = m.group('offset')
+                    if limit and int(limit) >= 0:
+                        output.append(int(limit))
+                    elif offset:
+                        output.append(len(vals) - int(offset))
                 else:
                     output.append(len(vals))
             else:
@@ -231,7 +233,7 @@ class SQLCompiler(compiler.SQLCompiler):
                 if isinstance(e[0], aggregates.Count):
                     value = 0
                     input_field = e[0].get_source_expressions()[0].field
-                    if input_field.attname == 'dn':
+                    if input_field.get_attname() == 'dn':
                         value = 1
                     elif hasattr(input_field, 'from_ldap'):
                         result = input_field.from_ldap(
@@ -243,7 +245,7 @@ class SQLCompiler(compiler.SQLCompiler):
                                 value = len(result)
                     row.append(value)
                 else:
-                    if e[0].field.attname == 'dn':
+                    if e[0].field.get_attname() == 'dn':
                         row.append(dn)
                     elif hasattr(e[0].field, 'from_ldap'):
                         row.append(e[0].field.from_ldap(
diff -pruN 1.5.1-3/ldapdb/models/base.py 2.0.0-1/ldapdb/models/base.py
--- 1.5.1-3/ldapdb/models/base.py	2020-10-12 15:56:49.000000000 +0000
+++ 2.0.0-1/ldapdb/models/base.py	2025-01-12 12:07:21.000000000 +0000
@@ -83,13 +83,13 @@ class Model(django.db.models.base.Model)
             ]
 
         def get_field_value(field, instance):
-            python_value = getattr(instance, field.attname)
+            python_value = getattr(instance, field.get_attname())
             return field.get_db_prep_save(python_value, connection=connection)
 
         if create:
             old = None
         else:
-            old = cls.objects.using(using).get(dn=self._saved_dn)
+            old = cls._base_manager.using(using).get(dn=self._saved_dn)
         changes = {
             field.db_column: (
                 None if old is None else get_field_value(field, old),
diff -pruN 1.5.1-3/ldapdb/models/fields.py 2.0.0-1/ldapdb/models/fields.py
--- 1.5.1-3/ldapdb/models/fields.py	2020-10-12 15:56:49.000000000 +0000
+++ 2.0.0-1/ldapdb/models/fields.py	2025-01-12 12:07:21.000000000 +0000
@@ -321,7 +321,7 @@ def datetime_from_ldap(value):
         groups['microsecond'] = groups['microsecond'].ljust(6, '0')[:6]
     tzinfo = groups.pop('tzinfo')
     if tzinfo == 'Z':
-        tzinfo = timezone.utc
+        tzinfo = datetime.timezone.utc
     else:
         offset_mins = int(tzinfo[-2:]) if len(tzinfo) == 5 else 0
         offset = 60 * int(tzinfo[1:3]) + offset_mins
@@ -354,7 +354,7 @@ class DateTimeField(LdapFieldMixin, fiel
             raise ValueError(
                 'DateTimeField can be only set to a datetime.datetime instance; got {}'.format(repr(value)))
 
-        value = timezone.utc.normalize(value)
+        value = value.astimezone(datetime.timezone.utc)
         return value.strftime(LDAP_DATE_FORMAT)
 
 
@@ -364,15 +364,15 @@ DateTimeField.register_lookup(GteLookup)
 DateTimeField.register_lookup(InLookup)
 
 
-EPOCH = timezone.utc.localize(datetime.datetime.utcfromtimestamp(0))
+EPOCH = datetime.datetime.fromtimestamp(0, datetime.timezone.utc)
 
 
 def datetime_from_timestamp(ts):
-    return timezone.utc.localize(datetime.datetime.utcfromtimestamp(ts))
+    return datetime.datetime.fromtimestamp(ts, datetime.timezone.utc)
 
 
 def timestamp_from_datetime(dt):
-    return int((timezone.utc.normalize(dt) - EPOCH).total_seconds())
+    return int((dt.astimezone(datetime.timezone.utc) - EPOCH).total_seconds())
 
 
 class TimestampField(LdapFieldMixin, fields.DateTimeField):
diff -pruN 1.5.1-3/ldapdb/router.py 2.0.0-1/ldapdb/router.py
--- 1.5.1-3/ldapdb/router.py	2020-10-12 15:56:49.000000000 +0000
+++ 2.0.0-1/ldapdb/router.py	2025-01-12 12:07:21.000000000 +0000
@@ -2,6 +2,10 @@
 # This software is distributed under the two-clause BSD license.
 # Copyright (c) The django-ldapdb project
 
+from django.apps import apps
+
+from ldapdb.models import Model
+
 
 def is_ldap_model(model):
     # FIXME: there is probably a better check than testing 'base_dn'
@@ -27,8 +31,15 @@ class Router(object):
                 break
 
     def allow_migrate(self, db, app_label, model_name=None, **hints):
-        if 'model' in hints and is_ldap_model(hints['model']):
+        # disallow any migration operation on ldap engine
+        if db == self.ldap_alias:
             return False
+
+        # avoid any migration operation on ldap models
+        if model_name:
+            model = apps.get_model(app_label, model_name)
+            if issubclass(model, Model):
+                return False
         return None
 
     def db_for_read(self, model, **hints):
diff -pruN 1.5.1-3/ldapdb/tests.py 2.0.0-1/ldapdb/tests.py
--- 1.5.1-3/ldapdb/tests.py	2020-10-12 15:56:49.000000000 +0000
+++ 2.0.0-1/ldapdb/tests.py	2025-01-12 12:07:21.000000000 +0000
@@ -16,7 +16,7 @@ from ldapdb import escape_ldap_filter, m
 from ldapdb.backends.ldap import compiler as ldapdb_compiler
 from ldapdb.models import fields
 
-UTC = timezone.utc
+UTC = datetime.timezone.utc
 UTC_PLUS_ONE = timezone.get_fixed_timezone(60)
 UTC_MINUS_2_HALF = timezone.get_fixed_timezone(-150)
 
@@ -82,6 +82,7 @@ class WhereTestCase(TestCase):
     def _build_lookup(self, field_name, lookup, value, field=fields.CharField):
         fake_field = field()
         fake_field.set_attributes_from_name(field_name)
+        fake_field.contribute_to_class(FakeModel, "fake")
         lhs = expressions.Col('faketable', fake_field, fake_field)
         lookup = lhs.get_lookup(lookup)
         return lookup(lhs, value)
@@ -245,3 +246,32 @@ class WhereTestCase(TestCase):
         where.add(self._build_lookup("cn", 'exact', "foo", field=fields.CharField), AND)
         where.add(self._build_lookup("givenName", 'exact', "bar", field=fields.CharField), OR)
         self.assertEqual(self._where_as_ldap(where), "(|(cn=foo)(givenName=bar))")
+
+
+class CompilerRegexTestCase(TestCase):
+
+    def _run_regex(self, sql):
+        match = ldapdb_compiler._ORDER_BY_LIMIT_OFFSET_RE.search(sql)
+        self.assertIsNotNone(match)
+        return match
+
+    def test_regex(self):
+        sql = "SELECT examples_ldapgroup.cn AS Col1 FROM examples_ldapgroup ORDER BY examples_ldapgroup.gidNumber ASC LIMIT 2"  # noqa: E501
+        match = self._run_regex(sql)
+        self.assertEqual(match.group('limit'), '2')
+        self.assertEqual(match.group('offset'), None)
+
+        sql = "SELECT COUNT(*) FROM (SELECT examples_ldapgroup.cn AS Col1 FROM examples_ldapgroup ORDER BY examples_ldapgroup.gidNumber ASC LIMIT 2) subquery"  # noqa: E501
+        match = self._run_regex(sql)
+        self.assertEqual(match.group('limit'), '2')
+
+        sql = "SELECT COUNT(*) FROM (SELECT examples_ldapgroup.cn AS Col1 FROM examples_ldapgroup ORDER BY examples_ldapgroup.gidNumber ASC LIMIT -1 OFFSET 1) subquery"  # noqa: E501
+        match = self._run_regex(sql)
+        self.assertEqual(match.group('limit'), '-1')
+        self.assertEqual(match.group('offset'), '1')
+
+    def test_regex_django22(self):
+        sql = "SELECT examples_ldapgroup.cn AS Col1 FROM examples_ldapgroup ORDER BY examples_ldapgroup.gidNumber ASC  LIMIT 2"  # noqa: E501
+        match = self._run_regex(sql)
+        self.assertEqual(match.group('limit'), '2')
+        self.assertEqual(match.group('offset'), None)
diff -pruN 1.5.1-3/setup.cfg 2.0.0-1/setup.cfg
--- 1.5.1-3/setup.cfg	2020-10-12 15:56:49.000000000 +0000
+++ 2.0.0-1/setup.cfg	2025-01-12 12:07:21.000000000 +0000
@@ -1,6 +1,6 @@
 [metadata]
 name = django-ldapdb
-version = 1.5.1
+version = 1.5.2.dev0
 description = A LDAP database backend for Django
 long_description = file: README.rst
 keywords = django, ldap, database, ldapdb
@@ -10,52 +10,58 @@ author_email = jeremy.laine@m4x.org
 maintainer = Raphaël Barrois
 maintainer_email = raphael.barrois+django-ldapdb@polytechnique.org
 license = BSD
-classifiers = 
-	Development Status :: 5 - Production/Stable
-	Environment :: Web Environment
-	Framework :: Django :: 2.2
-	Framework :: Django :: 3.0
-	Framework :: Django :: 3.1
-	Intended Audience :: Developers
-	Intended Audience :: System Administrators
-	License :: OSI Approved :: BSD License
-	Programming Language :: Python
-	Programming Language :: Python :: 3.6
-	Programming Language :: Python :: 3.7
-	Programming Language :: Python :: 3.8
-	Topic :: Internet :: WWW/HTTP
-	Topic :: System :: Systems Administration :: Authentication/Directory :: LDAP
-	Topic :: Software Development :: Libraries :: Python Modules
+classifiers =
+    Development Status :: 5 - Production/Stable
+    Environment :: Web Environment
+    Framework :: Django :: 4.2
+    Framework :: Django :: 5.0
+    Framework :: Django :: 5.1
+    Intended Audience :: Developers
+    Intended Audience :: System Administrators
+    License :: OSI Approved :: BSD License
+    Programming Language :: Python
+    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
+    Topic :: Internet :: WWW/HTTP
+    Topic :: System :: Systems Administration :: Authentication/Directory :: LDAP
+    Topic :: Software Development :: Libraries :: Python Modules
 
 [options]
 zip_safe = false
 packages = find:
 include_package_data = true
-python_requires = >=3.6
-install_requires = 
-	Django>=2.2
-	python-ldap>=3.0
+python_requires = >=3.8
+install_requires =
+    Django>=4.2
+    python-ldap>=3.0
 setup_requires = setuptools
 
 [options.packages.find]
-include = 
-	ldapdb
+include =
+    ldapdb
 
 [options.extras_require]
-dev = 
-	check-manifest
-	flake8
-	isort>=5.0.0
-	tox
-	factory_boy
-	volatildap>=1.1.0
-	wheel
-	zest.releaser[recommended]
+dev =
+# Quality
+    check-manifest
+    flake8
+    isort>=5.0.0
+    tox
+# Testing tools
+    factory_boy
+    volatildap>=1.1.0
+# Releasing
+    wheel
+    zest.releaser[recommended]
 
 [bdist_wheel]
 universal = true
 
 [zest.releaser]
+; semver-style versions
 version-levels = 3
 
 [distutils]
@@ -63,9 +69,6 @@ index-servers = pypi
 
 [flake8]
 max-line-length = 120
-ignore = W503
-
-[egg_info]
-tag_build = 
-tag_date = 0
 
+# W503: 'and' on start of line
+ignore = W503
diff -pruN 1.5.1-3/tox.ini 2.0.0-1/tox.ini
--- 1.5.1-3/tox.ini	2020-10-12 15:56:49.000000000 +0000
+++ 2.0.0-1/tox.ini	2025-01-12 12:07:21.000000000 +0000
@@ -1,14 +1,14 @@
 [tox]
-envlist = py{36,37,38}-django{22,30,31}, lint
+envlist = py{38,39,310,311,312}-django42, py{310,311,312}-django{50,51}, lint
 
 [testenv]
 extras = dev
 deps =
-    django22: Django>=2.2,<2.3
-    django30: Django>=3.0,<3.1
-    django31: Django>=3.1,<3.2
+    django42: Django>=4.2,<5
+    django50: Django>=5.0,<5.1
+    django51: Django>=5.1,<5.2
 
-whitelist_externals = make
+allowlist_externals = make
 commands = make test
 
 [testenv:lint]
