Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-django-guardian for 
openSUSE:Factory checked in at 2026-08-28 19:55:07
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-django-guardian (Old)
 and      /work/SRC/openSUSE:Factory/.python-django-guardian.new.1265 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-django-guardian"

Fri Aug 28 19:55:07 2026 rev:25 rq:1374381 version:3.3.4

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-django-guardian/python-django-guardian.changes
    2026-05-04 12:57:58.752498363 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-django-guardian.new.1265/python-django-guardian.changes
  2026-08-28 19:58:05.837449648 +0200
@@ -1,0 +2,15 @@
+Fri Aug 28 06:03:24 UTC 2026 - Andreas Schneider <[email protected]>
+
+- update to version 3.3.4:
+  documentation is refactored, ai rules are added
+- update to version 3.3.3:
+  * Update configuration.md
+  * Fix generic object_pk bigint cast regression in shortcuts
+- update to version 3.3.2:
+  * Add note box regarding Meta inheritance
+  * Fixed user and group inconsistency with get perms
+  * Documentation: fix readme link to docs, add paperless-ngx to usage
+  * Move common code from shortcuts into dedicated methods
+  * Remove a query in prefetch_perms()
+
+-------------------------------------------------------------------

Old:
----
  django_guardian-3.3.1.tar.gz

New:
----
  django_guardian-3.3.4.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-django-guardian.spec ++++++
--- /var/tmp/diff_new_pack.cqbX8S/_old  2026-08-28 19:58:06.808483597 +0200
+++ /var/tmp/diff_new_pack.cqbX8S/_new  2026-08-28 19:58:06.810483667 +0200
@@ -19,7 +19,7 @@
 %{?sle15_python_module_pythons}
 %define pypi_package_name django-guardian
 Name:           python-%{pypi_package_name}
-Version:        3.3.1
+Version:        3.3.4
 Release:        0
 Summary:        Implementation of per object permissions for Django
 License:        BSD-2-Clause
@@ -34,7 +34,10 @@
 BuildRequires:  %{python_module wheel}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
+# SECTION test requirements
 Requires:       python-Django >= 3.2
+# /SECTION
+BuildRequires:  fdupes
 Requires:       python-typing-extensions >= 4.12.0
 BuildArch:      noarch
 %python_subpackages

++++++ django_guardian-3.3.1.tar.gz -> django_guardian-3.3.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django_guardian-3.3.1/PKG-INFO 
new/django_guardian-3.3.4/PKG-INFO
--- old/django_guardian-3.3.1/PKG-INFO  2026-03-30 11:44:43.758969800 +0200
+++ new/django_guardian-3.3.4/PKG-INFO  2026-08-27 02:04:41.423302400 +0200
@@ -1,16 +1,15 @@
 Metadata-Version: 2.4
 Name: django-guardian
-Version: 3.3.1
+Version: 3.3.4
 Summary: Per object permissions for Django
-Author: Chris Maggiuli, Bona Fide IT GmbH, Columbia University, SIS 
Development and Application Services
-Author-email: Lukasz Balcerzak <[email protected]>, Cesar Canassa 
<[email protected]>, Vincent Driessen <[email protected]>, John Hensley 
<[email protected]>, Ramanan Sivaranjan <[email protected]>, 
Woosuk Suh <[email protected]>, Bojan Mihelac <[email protected]>, Rafael 
Ponieman <[email protected]>, Daniel Sokolowski <[email protected]>, 
Ali Lozano <[email protected]>, BJ Dierkes <[email protected]>, Rach 
Belaid <[email protected]>, Michael Crosby <[email protected]>, 
Greg Hinch <[email protected]>, Aram Dulyan <[email protected]>, Florian Hahn 
<[email protected]>, Piotr Kilczuk <[email protected]>, Reavis Sutphin-Gray 
<[email protected]>, Adrián López <[email protected]>, Jameel 
Al-Aziz <[email protected]>, "John P. Neumann" <[email protected]>, Andreas 
Madsack <[email protected]>, Ivan Kharlamov <[email protected]>, Miguel 
de Val-Borro <[email protected]>, Jan Nakladal <[email protected]>, 
 Yonel Ceruto <[email protected]>, Luke Faraone <[email protected]>, John 
Wegis <[email protected]>, Florentin Sardan 
<[email protected]>, Geoff Greer <[email protected]>, Hans Larsen 
<[email protected]>, "Fabio C. Barrionuevo da Luz" <[email protected]>, Tomasz Wsuł 
<[email protected]>, Xavier Ordoquy <[email protected]>, Joshua Bonnett 
<[email protected]>, Jernej Kos <[email protected]>, Bruno Ribeiro da Silva 
<[email protected]>, Cezar Jenkins <[email protected]>, Warren Volz 
<[email protected]>, Omer Katz <[email protected]>, Vishal Lal 
<[email protected]>, Steven DeMartini <[email protected]>, zauddelig 
<[email protected]>, Remco Wendt <[email protected]>, Kevin London 
<[email protected]>, Kouhei Maeda <[email protected]>, Samuel Sutch 
<[email protected]>, Morgan Aubert <[email protected]>, Brian May 
<[email protected]>, Troy Grosfield <[email protected]>, 
Michael Drescher <[email protected]>, Verena Jaspersen <verena.
 [email protected]>, Bertrand Svetchine <[email protected]>, Frank 
Wickström <[email protected]>, George Karakostas <[email protected]>, 
Adam Dobrawy <[email protected]>, Jeff Hackshaw <[email protected]>, 
Chase Bennett <[email protected]>, Jonny Arnold <[email protected]>, Davis 
Raymond Muro <[email protected]>, Richard de Wit <[email protected]>, 
Pedro Rojas Gavidia <[email protected]>, Rainshaw Gao 
<[email protected]>, Tom Clark <[email protected]>, Meredith Hoo 
<[email protected]>, Cornelius Hoffmann <[email protected]>, Sezer BOZKIR 
<[email protected]>
-Maintainer: Michael K., Chris Maggiuli, Bona Fide IT GmbH
-Maintainer-email: Tom Clark <[email protected]>, Brian May 
<[email protected]>, Lukasz Balcerzak <[email protected]>, 
Adam Dobrawy <[email protected]>, David Graham <[email protected]>, 
Sezer BOZKIR <[email protected]>
+Author: Chris Maggiuli, Bona Fide IT GmbH, Columbia University, SIS 
Development and Application Services, Michael K., Chris Maggiuli, Bona Fide IT 
GmbH
+Author-email: Lukasz Balcerzak <[email protected]>, Cesar Canassa 
<[email protected]>, Vincent Driessen <[email protected]>, John Hensley 
<[email protected]>, Ramanan Sivaranjan <[email protected]>, 
Woosuk Suh <[email protected]>, Bojan Mihelac <[email protected]>, Rafael 
Ponieman <[email protected]>, Daniel Sokolowski <[email protected]>, 
Ali Lozano <[email protected]>, BJ Dierkes <[email protected]>, Rach 
Belaid <[email protected]>, Michael Crosby <[email protected]>, 
Greg Hinch <[email protected]>, Aram Dulyan <[email protected]>, Florian Hahn 
<[email protected]>, Piotr Kilczuk <[email protected]>, Reavis Sutphin-Gray 
<[email protected]>, Adrián López <[email protected]>, Jameel 
Al-Aziz <[email protected]>, "John P. Neumann" <[email protected]>, Andreas 
Madsack <[email protected]>, Ivan Kharlamov <[email protected]>, Miguel 
de Val-Borro <[email protected]>, Jan Nakladal <[email protected]>, 
 Yonel Ceruto <[email protected]>, Luke Faraone <[email protected]>, John 
Wegis <[email protected]>, Florentin Sardan 
<[email protected]>, Geoff Greer <[email protected]>, Hans Larsen 
<[email protected]>, "Fabio C. Barrionuevo da Luz" <[email protected]>, Tomasz Wsuł 
<[email protected]>, Xavier Ordoquy <[email protected]>, Joshua Bonnett 
<[email protected]>, Jernej Kos <[email protected]>, Bruno Ribeiro da Silva 
<[email protected]>, Cezar Jenkins <[email protected]>, Warren Volz 
<[email protected]>, Omer Katz <[email protected]>, Vishal Lal 
<[email protected]>, Steven DeMartini <[email protected]>, zauddelig 
<[email protected]>, Remco Wendt <[email protected]>, Kevin London 
<[email protected]>, Kouhei Maeda <[email protected]>, Samuel Sutch 
<[email protected]>, Morgan Aubert <[email protected]>, Brian May 
<[email protected]>, Troy Grosfield <[email protected]>, 
Michael Drescher <[email protected]>, Verena Jaspersen <verena.
 [email protected]>, Bertrand Svetchine <[email protected]>, Frank 
Wickström <[email protected]>, George Karakostas <[email protected]>, 
Adam Dobrawy <[email protected]>, Jeff Hackshaw <[email protected]>, 
Chase Bennett <[email protected]>, Jonny Arnold <[email protected]>, Davis 
Raymond Muro <[email protected]>, Richard de Wit <[email protected]>, 
Pedro Rojas Gavidia <[email protected]>, Rainshaw Gao 
<[email protected]>, Tom Clark <[email protected]>, David Graham 
<[email protected]>, Meredith Hoo <[email protected]>, Cornelius 
Hoffmann <[email protected]>, Sezer BOZKIR <[email protected]>, Paul Martin 
<[email protected]>, marko1olo <[email protected]>
+Maintainer-email: Sezer BOZKIR <[email protected]>, David Graham 
<[email protected]>, Tom Clark <[email protected]>
 License: BSD-2-Clause
 Project-URL: Homepage, https://github.com/django-guardian/django-guardian
 Project-URL: Documentation, https://django-guardian.readthedocs.io/
 Project-URL: Repository, https://github.com/django-guardian/django-guardian
-Project-URL: Issues, https://github.com/me/spam/issues
+Project-URL: Issues, https://github.com/django-guardian/django-guardian/issues
 Project-URL: Changelog, 
https://github.com/django-guardian/django-guardian/releases
 Keywords: django,permissions,authorization,object,row,level
 Classifier: Development Status :: 5 - Production/Stable
@@ -56,7 +55,13 @@
 
 Online documentation is available at 
[https://django-guardian.readthedocs.io/](https://django-guardian.readthedocs.io/).
 
-**See real-world usage**: Check out [Who Uses 
Guardian](https://django-guardian.readthedocs.io/en/latest/who-uses-guardian/) 
to see how thousands of projects worldwide use django-guardian in production.
+**See real-world usage**: Check out [Who Uses 
Guardian](https://django-guardian.readthedocs.io/en/stable/who-uses-guardian/) 
to see how thousands of projects worldwide use django-guardian in production.
+
+## Contributing
+
+Please read 
[`CONTRIBUTING.md`](https://github.com/django-guardian/django-guardian/blob/main/CONTRIBUTING.md)
 before opening a pull request. It documents the repository's issue-first 
workflow, branch targeting rules, local `uv` setup, required test and lint 
commands, documentation expectations, and AI/LLM contribution policy.
+
+If you need to report a security issue, do **not** open a public issue. Follow 
[`SECURITY.md`](https://github.com/django-guardian/django-guardian/blob/main/SECURITY.md)
 and use the repository's [private vulnerability reporting 
flow](https://github.com/django-guardian/django-guardian/security).
 
 
 ## Installation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django_guardian-3.3.1/README.md 
new/django_guardian-3.3.4/README.md
--- old/django_guardian-3.3.1/README.md 2026-03-30 11:44:38.000000000 +0200
+++ new/django_guardian-3.3.4/README.md 2026-08-27 02:04:37.286000300 +0200
@@ -13,7 +13,13 @@
 
 Online documentation is available at 
[https://django-guardian.readthedocs.io/](https://django-guardian.readthedocs.io/).
 
-**See real-world usage**: Check out [Who Uses 
Guardian](https://django-guardian.readthedocs.io/en/latest/who-uses-guardian/) 
to see how thousands of projects worldwide use django-guardian in production.
+**See real-world usage**: Check out [Who Uses 
Guardian](https://django-guardian.readthedocs.io/en/stable/who-uses-guardian/) 
to see how thousands of projects worldwide use django-guardian in production.
+
+## Contributing
+
+Please read 
[`CONTRIBUTING.md`](https://github.com/django-guardian/django-guardian/blob/main/CONTRIBUTING.md)
 before opening a pull request. It documents the repository's issue-first 
workflow, branch targeting rules, local `uv` setup, required test and lint 
commands, documentation expectations, and AI/LLM contribution policy.
+
+If you need to report a security issue, do **not** open a public issue. Follow 
[`SECURITY.md`](https://github.com/django-guardian/django-guardian/blob/main/SECURITY.md)
 and use the repository's [private vulnerability reporting 
flow](https://github.com/django-guardian/django-guardian/security).
 
 
 ## Installation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django_guardian-3.3.1/django_guardian.egg-info/PKG-INFO 
new/django_guardian-3.3.4/django_guardian.egg-info/PKG-INFO
--- old/django_guardian-3.3.1/django_guardian.egg-info/PKG-INFO 2026-03-30 
11:44:43.000000000 +0200
+++ new/django_guardian-3.3.4/django_guardian.egg-info/PKG-INFO 2026-08-27 
02:04:41.379073900 +0200
@@ -1,16 +1,15 @@
 Metadata-Version: 2.4
 Name: django-guardian
-Version: 3.3.1
+Version: 3.3.4
 Summary: Per object permissions for Django
-Author: Chris Maggiuli, Bona Fide IT GmbH, Columbia University, SIS 
Development and Application Services
-Author-email: Lukasz Balcerzak <[email protected]>, Cesar Canassa 
<[email protected]>, Vincent Driessen <[email protected]>, John Hensley 
<[email protected]>, Ramanan Sivaranjan <[email protected]>, 
Woosuk Suh <[email protected]>, Bojan Mihelac <[email protected]>, Rafael 
Ponieman <[email protected]>, Daniel Sokolowski <[email protected]>, 
Ali Lozano <[email protected]>, BJ Dierkes <[email protected]>, Rach 
Belaid <[email protected]>, Michael Crosby <[email protected]>, 
Greg Hinch <[email protected]>, Aram Dulyan <[email protected]>, Florian Hahn 
<[email protected]>, Piotr Kilczuk <[email protected]>, Reavis Sutphin-Gray 
<[email protected]>, Adrián López <[email protected]>, Jameel 
Al-Aziz <[email protected]>, "John P. Neumann" <[email protected]>, Andreas 
Madsack <[email protected]>, Ivan Kharlamov <[email protected]>, Miguel 
de Val-Borro <[email protected]>, Jan Nakladal <[email protected]>, 
 Yonel Ceruto <[email protected]>, Luke Faraone <[email protected]>, John 
Wegis <[email protected]>, Florentin Sardan 
<[email protected]>, Geoff Greer <[email protected]>, Hans Larsen 
<[email protected]>, "Fabio C. Barrionuevo da Luz" <[email protected]>, Tomasz Wsuł 
<[email protected]>, Xavier Ordoquy <[email protected]>, Joshua Bonnett 
<[email protected]>, Jernej Kos <[email protected]>, Bruno Ribeiro da Silva 
<[email protected]>, Cezar Jenkins <[email protected]>, Warren Volz 
<[email protected]>, Omer Katz <[email protected]>, Vishal Lal 
<[email protected]>, Steven DeMartini <[email protected]>, zauddelig 
<[email protected]>, Remco Wendt <[email protected]>, Kevin London 
<[email protected]>, Kouhei Maeda <[email protected]>, Samuel Sutch 
<[email protected]>, Morgan Aubert <[email protected]>, Brian May 
<[email protected]>, Troy Grosfield <[email protected]>, 
Michael Drescher <[email protected]>, Verena Jaspersen <verena.
 [email protected]>, Bertrand Svetchine <[email protected]>, Frank 
Wickström <[email protected]>, George Karakostas <[email protected]>, 
Adam Dobrawy <[email protected]>, Jeff Hackshaw <[email protected]>, 
Chase Bennett <[email protected]>, Jonny Arnold <[email protected]>, Davis 
Raymond Muro <[email protected]>, Richard de Wit <[email protected]>, 
Pedro Rojas Gavidia <[email protected]>, Rainshaw Gao 
<[email protected]>, Tom Clark <[email protected]>, Meredith Hoo 
<[email protected]>, Cornelius Hoffmann <[email protected]>, Sezer BOZKIR 
<[email protected]>
-Maintainer: Michael K., Chris Maggiuli, Bona Fide IT GmbH
-Maintainer-email: Tom Clark <[email protected]>, Brian May 
<[email protected]>, Lukasz Balcerzak <[email protected]>, 
Adam Dobrawy <[email protected]>, David Graham <[email protected]>, 
Sezer BOZKIR <[email protected]>
+Author: Chris Maggiuli, Bona Fide IT GmbH, Columbia University, SIS 
Development and Application Services, Michael K., Chris Maggiuli, Bona Fide IT 
GmbH
+Author-email: Lukasz Balcerzak <[email protected]>, Cesar Canassa 
<[email protected]>, Vincent Driessen <[email protected]>, John Hensley 
<[email protected]>, Ramanan Sivaranjan <[email protected]>, 
Woosuk Suh <[email protected]>, Bojan Mihelac <[email protected]>, Rafael 
Ponieman <[email protected]>, Daniel Sokolowski <[email protected]>, 
Ali Lozano <[email protected]>, BJ Dierkes <[email protected]>, Rach 
Belaid <[email protected]>, Michael Crosby <[email protected]>, 
Greg Hinch <[email protected]>, Aram Dulyan <[email protected]>, Florian Hahn 
<[email protected]>, Piotr Kilczuk <[email protected]>, Reavis Sutphin-Gray 
<[email protected]>, Adrián López <[email protected]>, Jameel 
Al-Aziz <[email protected]>, "John P. Neumann" <[email protected]>, Andreas 
Madsack <[email protected]>, Ivan Kharlamov <[email protected]>, Miguel 
de Val-Borro <[email protected]>, Jan Nakladal <[email protected]>, 
 Yonel Ceruto <[email protected]>, Luke Faraone <[email protected]>, John 
Wegis <[email protected]>, Florentin Sardan 
<[email protected]>, Geoff Greer <[email protected]>, Hans Larsen 
<[email protected]>, "Fabio C. Barrionuevo da Luz" <[email protected]>, Tomasz Wsuł 
<[email protected]>, Xavier Ordoquy <[email protected]>, Joshua Bonnett 
<[email protected]>, Jernej Kos <[email protected]>, Bruno Ribeiro da Silva 
<[email protected]>, Cezar Jenkins <[email protected]>, Warren Volz 
<[email protected]>, Omer Katz <[email protected]>, Vishal Lal 
<[email protected]>, Steven DeMartini <[email protected]>, zauddelig 
<[email protected]>, Remco Wendt <[email protected]>, Kevin London 
<[email protected]>, Kouhei Maeda <[email protected]>, Samuel Sutch 
<[email protected]>, Morgan Aubert <[email protected]>, Brian May 
<[email protected]>, Troy Grosfield <[email protected]>, 
Michael Drescher <[email protected]>, Verena Jaspersen <verena.
 [email protected]>, Bertrand Svetchine <[email protected]>, Frank 
Wickström <[email protected]>, George Karakostas <[email protected]>, 
Adam Dobrawy <[email protected]>, Jeff Hackshaw <[email protected]>, 
Chase Bennett <[email protected]>, Jonny Arnold <[email protected]>, Davis 
Raymond Muro <[email protected]>, Richard de Wit <[email protected]>, 
Pedro Rojas Gavidia <[email protected]>, Rainshaw Gao 
<[email protected]>, Tom Clark <[email protected]>, David Graham 
<[email protected]>, Meredith Hoo <[email protected]>, Cornelius 
Hoffmann <[email protected]>, Sezer BOZKIR <[email protected]>, Paul Martin 
<[email protected]>, marko1olo <[email protected]>
+Maintainer-email: Sezer BOZKIR <[email protected]>, David Graham 
<[email protected]>, Tom Clark <[email protected]>
 License: BSD-2-Clause
 Project-URL: Homepage, https://github.com/django-guardian/django-guardian
 Project-URL: Documentation, https://django-guardian.readthedocs.io/
 Project-URL: Repository, https://github.com/django-guardian/django-guardian
-Project-URL: Issues, https://github.com/me/spam/issues
+Project-URL: Issues, https://github.com/django-guardian/django-guardian/issues
 Project-URL: Changelog, 
https://github.com/django-guardian/django-guardian/releases
 Keywords: django,permissions,authorization,object,row,level
 Classifier: Development Status :: 5 - Production/Stable
@@ -56,7 +55,13 @@
 
 Online documentation is available at 
[https://django-guardian.readthedocs.io/](https://django-guardian.readthedocs.io/).
 
-**See real-world usage**: Check out [Who Uses 
Guardian](https://django-guardian.readthedocs.io/en/latest/who-uses-guardian/) 
to see how thousands of projects worldwide use django-guardian in production.
+**See real-world usage**: Check out [Who Uses 
Guardian](https://django-guardian.readthedocs.io/en/stable/who-uses-guardian/) 
to see how thousands of projects worldwide use django-guardian in production.
+
+## Contributing
+
+Please read 
[`CONTRIBUTING.md`](https://github.com/django-guardian/django-guardian/blob/main/CONTRIBUTING.md)
 before opening a pull request. It documents the repository's issue-first 
workflow, branch targeting rules, local `uv` setup, required test and lint 
commands, documentation expectations, and AI/LLM contribution policy.
+
+If you need to report a security issue, do **not** open a public issue. Follow 
[`SECURITY.md`](https://github.com/django-guardian/django-guardian/blob/main/SECURITY.md)
 and use the repository's [private vulnerability reporting 
flow](https://github.com/django-guardian/django-guardian/security).
 
 
 ## Installation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django_guardian-3.3.1/guardian/core.py 
new/django_guardian-3.3.4/guardian/core.py
--- old/django_guardian-3.3.1/guardian/core.py  2026-03-30 11:44:38.000000000 
+0200
+++ new/django_guardian-3.3.4/guardian/core.py  2026-08-27 02:04:37.298163400 
+0200
@@ -122,7 +122,7 @@
 
         return user_filters
 
-    def get_user_perms(self, obj: Model) -> QuerySet[Permission]:
+    def get_user_perms(self, obj: Model) -> QuerySet[str]:
         if self.user and not self.user.is_active:
             return Permission.objects.none().values_list("codename", flat=True)
 
@@ -131,11 +131,11 @@
         perms_qs = Permission.objects.filter(content_type=ctype)
         user_filters = self.get_user_filters(obj)
         user_perms_qs = perms_qs.filter(**user_filters)
-        user_perms: QuerySet[Permission] = 
user_perms_qs.values_list("codename", flat=True)
+        user_perms: QuerySet[str] = user_perms_qs.values_list("codename", 
flat=True)
 
         return user_perms
 
-    def get_group_perms(self, obj: Model) -> QuerySet[Permission]:
+    def get_group_perms(self, obj: Model) -> QuerySet[str]:
         if self.user and not self.user.is_active:
             return Permission.objects.none().values_list("codename", flat=True)
 
@@ -144,7 +144,7 @@
         perms_qs = Permission.objects.filter(content_type=ctype)
         group_filters = self.get_group_filters(obj)
         group_perms_qs = perms_qs.filter(**group_filters)
-        group_perms: QuerySet[Permission] = 
group_perms_qs.values_list("codename", flat=True)
+        group_perms: QuerySet[str] = group_perms_qs.values_list("codename", 
flat=True)
 
         return group_perms
 
@@ -245,8 +245,8 @@
             perms = 
group_model.objects.filter(**group_filters).select_related("permission")
 
         # initialize entry in '_obj_perms_cache' for all prefetched objects
-        for obj in objects:
-            key = self.get_local_cache_key(obj)
+        # The ctype is assumed above to be homogenous, so leave `objects` 
unevaluated.
+        for key in ((ctype.id, pk) for pk in pks):
             if key not in self._obj_perms_cache:
                 self._obj_perms_cache[key] = []
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django_guardian-3.3.1/guardian/shortcuts.py 
new/django_guardian-3.3.4/guardian/shortcuts.py
--- old/django_guardian-3.3.1/guardian/shortcuts.py     2026-03-30 
11:44:38.000000000 +0200
+++ new/django_guardian-3.3.4/guardian/shortcuts.py     2026-08-27 
02:04:37.301040400 +0200
@@ -63,6 +63,27 @@
     return t[0]
 
 
+def _ensure_permission(perm: Union[Permission, str]) -> Permission:
+    """Converts string permission to the corresponding django model, if 
required."""
+    if isinstance(perm, str):
+        try:
+            app_label, codename = perm.split(".", 1)
+        except ValueError:
+            raise ValueError(
+                f"For global permissions, first argument must be in format: 
'app_label.codename' (is {perm!r})"
+            )
+        perm = Permission.objects.get(content_type__app_label=app_label, 
codename=codename)
+    return perm
+
+
+def _normalize_perm(perm: Union[Permission, str]) -> Union[Permission, str]:
+    """Normalizes permission codename, if it is a string."""
+    if isinstance(perm, str) and "." in perm:
+        _, perm = perm.split(".", 1)
+
+    return perm
+
+
 def assign_perm(
     perm: Union[str, Permission],
     user_or_group: Any,
@@ -123,15 +144,7 @@
     user, group = get_identity(user_or_group)
     # If obj is None we try to operate on global permissions
     if obj is None:
-        if not isinstance(perm, Permission):
-            try:
-                app_label, codename = perm.split(".", 1)
-            except ValueError:
-                raise ValueError(
-                    "For global permissions, first argument must be in format: 
'app_label.codename' (is %r)" % perm
-                )
-            perm = Permission.objects.get(content_type__app_label=app_label, 
codename=codename)
-
+        perm = _ensure_permission(perm)
         if user:
             user.user_permissions.add(perm)
             return perm
@@ -139,10 +152,7 @@
             group.permissions.add(perm)
             return perm
 
-    if not isinstance(perm, Permission):
-        if "." in perm:
-            app_label, perm = perm.split(".", 1)
-
+    perm = _normalize_perm(perm)
     if isinstance(obj, (QuerySet, list)):
         if isinstance(user_or_group, (QuerySet, list)):
             raise MultipleIdentityAndObjectError("Only bulk operations on 
either users/groups OR objects supported")
@@ -206,14 +216,7 @@
 
     user, group = get_identity(user_or_group)
     if obj is None:
-        if not isinstance(perm, Permission):
-            try:
-                app_label, codename = perm.split(".", 1)
-            except ValueError:
-                raise ValueError(
-                    "For global permissions, first argument must be in format: 
'app_label.codename' (is %r)" % perm
-                )
-            perm = Permission.objects.get(content_type__app_label=app_label, 
codename=codename)
+        perm = _ensure_permission(perm)
         if user:
             user.user_permissions.remove(perm)
             return None
@@ -221,9 +224,7 @@
             group.permissions.remove(perm)
             return None
 
-    if not isinstance(perm, Permission):
-        perm = perm.split(".")[-1]
-
+    perm = _normalize_perm(perm)
     if isinstance(obj, list) and not obj:
         return None
 
@@ -516,6 +517,56 @@
 T = TypeVar("T", bound=Model)
 
 
+def _compute_codenames_and_ctype(
+    perms: Union[str, list[str]],
+) -> tuple[Optional[ContentType], set[str]]:
+    """Extracts ContentType and codenames from given list of permissions."""
+    if isinstance(perms, str):
+        perms = [perms]
+    ctype = None
+    app_label = None
+    codenames = set()
+
+    # Compute codenames and set and ctype if possible
+    for perm in perms:
+        if "." in perm:
+            new_app_label, codename = perm.split(".", 1)
+            if app_label is not None and app_label != new_app_label:
+                raise MixedContentTypeError(f"Given perms must have same app 
label ({app_label} != {new_app_label})")
+            else:
+                app_label = new_app_label
+        else:
+            codename = perm
+        codenames.add(codename)
+        if app_label is not None:
+            new_ctype = _get_ct_cached(app_label, codename)
+            if ctype is not None and ctype != new_ctype:
+                raise MixedContentTypeError(f"ContentType was once computed to 
be {ctype} and another one {new_ctype}")
+            else:
+                ctype = new_ctype
+
+    return ctype, codenames
+
+
+def _compute_queryset(
+    ctype: Optional[ContentType],
+    klass: Union[Type[T], Manager[T], QuerySet[T], None],
+) -> tuple[ContentType, QuerySet[T]]:
+    """Computes QuerySet and ContentType if still missing"""
+    if ctype is None and klass is not None:
+        queryset = _get_queryset(klass)
+        ctype = get_content_type(queryset.model)
+    elif ctype is not None and klass is None:
+        queryset = _get_queryset(ctype.model_class())
+    elif klass is None:
+        raise WrongAppError("Cannot determine content type")
+    else:
+        queryset = _get_queryset(klass)
+        if ctype != get_content_type(queryset.model):
+            raise MixedContentTypeError("Content type for given perms and 
klass differs")
+    return ctype, queryset
+
+
 def get_objects_for_user(
     user: Any,
     perms: Union[str, list[str]],
@@ -622,46 +673,8 @@
         ``Cast("pk", CharField())`` fallback, so models with any PK type are
         supported without extra configuration.
     """
-    if isinstance(perms, str):
-        perms = [perms]
-    ctype = None
-    app_label = None
-    codenames = set()
-
-    # Compute codenames and set and ctype if possible
-    for perm in perms:
-        if "." in perm:
-            new_app_label, codename = perm.split(".", 1)
-            if app_label is not None and app_label != new_app_label:
-                raise MixedContentTypeError(
-                    "Given perms must have same app label ({} != 
{})".format(app_label, new_app_label)
-                )
-            else:
-                app_label = new_app_label
-        else:
-            codename = perm
-        codenames.add(codename)
-        if app_label is not None:
-            new_ctype = new_ctype = _get_ct_cached(app_label, codename)
-            if ctype is not None and ctype != new_ctype:
-                raise MixedContentTypeError(
-                    "ContentType was once computed to be {} and another one 
{}".format(ctype, new_ctype)
-                )
-            else:
-                ctype = new_ctype
-
-    # Compute queryset and ctype if still missing
-    if ctype is None and klass is not None:
-        queryset = _get_queryset(klass)
-        ctype = get_content_type(queryset.model)
-    elif ctype is not None and klass is None:
-        queryset = _get_queryset(ctype.model_class())
-    elif klass is None:
-        raise WrongAppError("Cannot determine content type")
-    else:
-        queryset = _get_queryset(klass)
-        if ctype != get_content_type(queryset.model):
-            raise MixedContentTypeError("Content type for given perms and 
klass differs")
+    ctype, codenames = _compute_codenames_and_ctype(perms)
+    ctype, queryset = _compute_queryset(ctype, klass)
 
     # At this point, we should have both ctype and queryset and they should
     # match which means: ctype.model_class() == queryset.model
@@ -753,37 +766,47 @@
     values = user_obj_perms_queryset
 
     handle_pk_field = _handle_pk_field(queryset)
-    if handle_pk_field is not None:
+    use_str_pk_for_user = handle_pk_field is None or (
+        user_model.objects.is_generic() and _casts_to_bigint(handle_pk_field)
+    )
+    if not use_str_pk_for_user:
         values = values.annotate(obj_pk=handle_pk_field(expression=field_pk))
         field_pk = "obj_pk"
 
     values = values.values_list(field_pk, flat=True)
-    if handle_pk_field is not None:
-        q = Q(pk__in=values)
-    else:
+    str_pk_annotated = False
+    if use_str_pk_for_user:
         queryset = queryset.annotate(str_pk=Cast("pk", CharField()))
+        str_pk_annotated = True
         q = Q(str_pk__in=values)
+    else:
+        q = Q(pk__in=values)
     if use_groups:
         field_pk = group_fields[0]
         values = groups_obj_perms_queryset
-        if handle_pk_field is not None:
+        use_str_pk_for_group = handle_pk_field is None or (
+            group_model.objects.is_generic() and 
_casts_to_bigint(handle_pk_field)
+        )
+        if not use_str_pk_for_group:
             values = 
values.annotate(obj_pk=handle_pk_field(expression=field_pk))
             field_pk = "obj_pk"
         values = values.values_list(field_pk, flat=True)
-        if handle_pk_field is not None:
-            q |= Q(pk__in=values)
-        else:
+        if use_str_pk_for_group:
+            if not str_pk_annotated:
+                queryset = queryset.annotate(str_pk=Cast("pk", CharField()))
             q |= Q(str_pk__in=values)
+        else:
+            q |= Q(pk__in=values)
     return queryset.filter(q)
 
 
 def get_objects_for_group(
     group: Group,
     perms: Union[str, list[str]],
-    klass: Union[Model, Manager, QuerySet, None] = None,
+    klass: Union[Type[T], Manager[T], QuerySet[T], None] = None,
     any_perm: bool = False,
     accept_global_perms: bool = True,
-) -> QuerySet:
+) -> QuerySet[T]:
     """Get objects that a group has *all* the supplied permissions for.
 
     Parameters:
@@ -849,46 +872,8 @@
         ``Cast("pk", CharField())`` fallback, so models with any PK type are
         supported without extra configuration.
     """
-    if isinstance(perms, str):
-        perms = [perms]
-    ctype = None
-    app_label = None
-    codenames = set()
-
-    # Compute the codenames and set ctype if possible
-    for perm in perms:
-        if "." in perm:
-            new_app_label, codename = perm.split(".", 1)
-            if app_label is not None and app_label != new_app_label:
-                raise MixedContentTypeError(
-                    "Given perms must have same app label ({} != 
{})".format(app_label, new_app_label)
-                )
-            else:
-                app_label = new_app_label
-        else:
-            codename = perm
-        codenames.add(codename)
-        if app_label is not None:
-            new_ctype = _get_ct_cached(app_label, codename)
-            if ctype is not None and ctype != new_ctype:
-                raise MixedContentTypeError(
-                    "ContentType was once computed to be {} and another one 
{}".format(ctype, new_ctype)
-                )
-            else:
-                ctype = new_ctype
-
-    # Compute queryset and ctype if still missing
-    if ctype is None and klass is not None:
-        queryset = _get_queryset(klass)
-        ctype = get_content_type(queryset.model)
-    elif ctype is not None and klass is None:
-        queryset = _get_queryset(ctype.model_class())
-    elif klass is None:
-        raise WrongAppError("Cannot determine content type")
-    else:
-        queryset = _get_queryset(klass)
-        if ctype != get_content_type(queryset.model):
-            raise MixedContentTypeError("Content type for given perms and 
klass differs")
+    ctype, codenames = _compute_codenames_and_ctype(perms)
+    ctype, queryset = _compute_queryset(ctype, klass)
 
     # At this point, we should have both ctype and queryset and they should
     # match which means: ctype.model_class() == queryset.model
@@ -935,14 +920,15 @@
     values = groups_obj_perms_queryset
 
     handle_pk_field = _handle_pk_field(queryset)
-    if handle_pk_field is not None:
+    use_str_pk = handle_pk_field is None or (group_model.objects.is_generic() 
and _casts_to_bigint(handle_pk_field))
+    if not use_str_pk:
         values = values.annotate(obj_pk=handle_pk_field(expression=field_pk))
         field_pk = "obj_pk"
     else:
         queryset = queryset.annotate(str_pk=Cast("pk", CharField()))
 
     values = values.values_list(field_pk, flat=True)
-    if handle_pk_field is not None:
+    if not use_str_pk:
         return queryset.filter(pk__in=values)
     else:
         return queryset.filter(str_pk__in=values)
@@ -980,6 +966,14 @@
     return None
 
 
+def _casts_to_bigint(handle_pk_field):
+    return (
+        isinstance(handle_pk_field, partial)
+        and handle_pk_field.func is Cast
+        and isinstance(handle_pk_field.keywords.get("output_field"), 
BigIntegerField)
+    )
+
+
 def filter_perms_queryset_by_objects(perms_queryset, objects):
     if isinstance(objects, QuerySet):
         field = "content_object__pk"
@@ -987,12 +981,18 @@
             field = "object_pk"
             handle_pk_field = _handle_pk_field(objects)
             if handle_pk_field is not None:
-                objects = objects.values(_pk=Cast(handle_pk_field("pk"), 
output_field=CharField()))
-                # Apply the same transformation to the object_pk field for 
consistent comparison (#930)
-                perms_queryset = perms_queryset.annotate(
-                    _transformed_object_pk=Cast(handle_pk_field(field), 
output_field=CharField())
-                )
-                field = "_transformed_object_pk"
+                if _casts_to_bigint(handle_pk_field):
+                    # Keep object_pk untouched to avoid CAST(object_pk AS 
bigint)
+                    # scans on large guardian tables. We only stringify model 
PKs.
+                    objects = objects.values(_pk=Cast("pk", 
output_field=CharField()))
+                    field = "object_pk"
+                else:
+                    objects = objects.values(_pk=Cast(handle_pk_field("pk"), 
output_field=CharField()))
+                    # Apply the same transformation to the object_pk field for 
consistent comparison (#930)
+                    perms_queryset = perms_queryset.annotate(
+                        _transformed_object_pk=Cast(handle_pk_field(field), 
output_field=CharField())
+                    )
+                    field = "_transformed_object_pk"
             else:
                 objects = objects.values("pk")
         else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django_guardian-3.3.1/guardian/testapp/tests/test_core.py 
new/django_guardian-3.3.4/guardian/testapp/tests/test_core.py
--- old/django_guardian-3.3.1/guardian/testapp/tests/test_core.py       
2026-03-30 11:44:38.000000000 +0200
+++ new/django_guardian-3.3.4/guardian/testapp/tests/test_core.py       
2026-08-27 02:04:37.303665900 +0200
@@ -6,7 +6,9 @@
 from django.contrib.auth.management import create_permissions
 from django.contrib.auth.models import AnonymousUser, Group, Permission
 from django.contrib.contenttypes.models import ContentType
+from django.db import connection
 from django.test import TestCase
+from django.test.utils import CaptureQueriesContext
 
 from guardian.conf import settings as guardian_settings
 from guardian.core import ObjectPermissionChecker
@@ -610,3 +612,13 @@
             self.assertGreater(len(connection.queries), query_count)
         finally:
             settings.DEBUG = False
+
+    def test_prefetch_performance(self):
+        checker = ObjectPermissionChecker(self.user)
+        with CaptureQueriesContext(connection) as queries:
+            checker.prefetch_perms(Group.objects.all())
+
+        auth_group_from = "FROM %s" % connection.ops.quote_name("auth_group")
+        # Ignore other queries that JOIN this table.
+        group_selects = [q for q in queries if 
q["sql"].endswith(auth_group_from)]
+        self.assertEqual(len(group_selects), 1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django_guardian-3.3.1/guardian/testapp/tests/test_shortcuts.py 
new/django_guardian-3.3.4/guardian/testapp/tests/test_shortcuts.py
--- old/django_guardian-3.3.1/guardian/testapp/tests/test_shortcuts.py  
2026-03-30 11:44:38.000000000 +0200
+++ new/django_guardian-3.3.4/guardian/testapp/tests/test_shortcuts.py  
2026-08-27 02:04:37.304000600 +0200
@@ -1,3 +1,4 @@
+import re
 from unittest import mock
 import warnings
 
@@ -17,6 +18,7 @@
     WrongAppError,
 )
 from guardian.models import Group, Permission
+import guardian.shortcuts as guardian_shortcuts
 from guardian.shortcuts import (
     _get_ct_cached,
     assign,
@@ -48,6 +50,16 @@
     return ContentType.objects.get_for_model(Group)
 
 
+def assert_query_does_not_cast_object_pk(testcase, query):
+    testcase.assertIsNone(
+        re.search(
+            r"(cast\([^)]*\bobject_pk\b[^)]*\))|"
+            r"(\bobject_pk\b::[a-z_][a-z0-9_]*)",
+            query,
+        )
+    )
+
+
 class ShortcutsTests(ObjectPermissionTestCase):
     def test_get_perms_for_model(self):
         expected_perms_amount = 3 if django.VERSION < (2, 1) else 4
@@ -402,6 +414,16 @@
         perm_obj = Permission.objects.get(codename=codename, 
content_type__app_label=app_label)
         self.assertFalse(perm_obj in self.group.permissions.all())
 
+    def test_remove_perm_with_dots(self):
+        Permission.objects.create(
+            codename="contenttype.reorder",
+            content_type=ContentType.objects.get_for_model(self.ctype),
+        )
+
+        assign_perm("contenttypes.contenttype.reorder", self.user, self.ctype)
+        remove_perm("contenttypes.contenttype.reorder", self.user, self.ctype)
+        
self.assertFalse(self.user.has_perm("contenttypes.contenttype.reorder", 
self.ctype))
+
 
 class MultipleIdentitiesRemoveTest(ObjectPermissionTestCase):
     """
@@ -723,6 +745,50 @@
             {self.user1, admin},
         )
 
+    def test_get_group_perms_consistent_inactive_user(self):
+        """Test that the get_group_perms shortcut returns the same results as 
the
+        get_group_perms method of ObjectPermissionChecker for inactive user in 
a group."""
+
+        self.user1.groups.add(self.group1)
+        assign_perm("change_contenttype", self.group1, self.obj1)
+
+        checker = ObjectPermissionChecker(self.user1)
+
+        get_group_perms_result_active = checker.get_group_perms(self.obj1)
+        shortcuts_get_group_perms_result_active = get_group_perms(self.user1, 
self.obj1)
+
+        self.user1.is_active = False
+        self.user1.save()
+
+        get_group_perms_result_inactive = checker.get_group_perms(self.obj1)
+        shortcuts_get_group_perms_result_inactive = 
get_group_perms(self.user1, self.obj1)
+
+        self.assertTrue(
+            set(get_group_perms_result_active) == 
set(shortcuts_get_group_perms_result_active) == {"change_contenttype"}
+        )
+        self.assertTrue(set(get_group_perms_result_inactive) == 
set(shortcuts_get_group_perms_result_inactive) == set())
+
+    def test_get_perms_consistent_for_inactive_user_in_group(self):
+        """Test that the get_perms shortcut returns the same results as the
+        get_perms method of ObjectPermissionChecker for inactive user in a 
group."""
+
+        self.user1.groups.add(self.group1)
+        assign_perm("change_contenttype", self.group1, self.obj1)
+
+        checker = ObjectPermissionChecker(self.user1)
+
+        get_perms_result_active = checker.get_perms(self.obj1)
+        shortcuts_get_perms_result_active = get_perms(self.user1, self.obj1)
+
+        self.user1.is_active = False
+        self.user1.save()
+
+        get_perms_result_inactive = checker.get_perms(self.obj1)
+        shortcuts_get_perms_result_inactive = get_perms(self.user1, self.obj1)
+
+        self.assertTrue(get_perms_result_active == 
shortcuts_get_perms_result_active == ["change_contenttype"])
+        self.assertTrue(get_perms_result_inactive == 
shortcuts_get_perms_result_inactive == [])
+
     def test_without_group_users(self):
         self.user1.groups.add(self.group1)
         self.user2.groups.add(self.group2)
@@ -1021,6 +1087,28 @@
         objects = get_objects_for_user(self.user, ["auth.change_group"], 
Group.objects.all())
         self.assertEqual([obj.name for obj in objects], [self.group.name])
 
+    def test_generic_subquery_does_not_cast_object_pk(self):
+        assign_perm("auth.change_group", self.user, self.group)
+        other_group = Group.objects.create(name="group2")
+
+        objects = get_objects_for_user(self.user, ["auth.change_group"])
+        self.assertEqual(set(objects), {self.group})
+        self.assertNotIn(other_group, objects)
+
+        query = str(objects.query).lower()
+        assert_query_does_not_cast_object_pk(self, query)
+
+    def test_generic_subquery_does_not_cast_object_pk_for_queryset_klass(self):
+        assign_perm("auth.change_group", self.user, self.group)
+        other_group = Group.objects.create(name="group2")
+
+        objects = get_objects_for_user(self.user, ["auth.change_group"], 
Group.objects.all())
+        self.assertEqual(set(objects), {self.group})
+        self.assertNotIn(other_group, objects)
+
+        query = str(objects.query).lower()
+        assert_query_does_not_cast_object_pk(self, query)
+
     def test_ensure_returns_queryset(self):
         objects = get_objects_for_user(self.user, ["auth.change_group"])
         self.assertTrue(isinstance(objects, QuerySet))
@@ -1505,6 +1593,32 @@
         objects = get_objects_for_group(self.group1, ["change_contenttype"], 
ContentType.objects.all())
         self.assertEqual(list(objects), [self.obj1])
 
+    def test_generic_subquery_does_not_cast_object_pk(self):
+        assign_perm("contenttypes.change_contenttype", self.group1, self.obj1)
+        obj4 = ContentType.objects.create(model="qux", 
app_label="guardian-tests")
+
+        objects = get_objects_for_group(self.group1, 
["contenttypes.change_contenttype"])
+        self.assertEqual(set(objects), {self.obj1})
+        self.assertNotIn(obj4, objects)
+
+        query = str(objects.query).lower()
+        assert_query_does_not_cast_object_pk(self, query)
+
+    def test_generic_subquery_does_not_cast_object_pk_for_queryset_klass(self):
+        assign_perm("contenttypes.change_contenttype", self.group1, self.obj1)
+        obj4 = ContentType.objects.create(model="qux", 
app_label="guardian-tests")
+
+        with mock.patch(
+            "guardian.shortcuts._casts_to_bigint",
+            wraps=guardian_shortcuts._casts_to_bigint,
+        ) as mocked_casts_to_bigint:
+            objects = get_objects_for_group(self.group1, 
["change_contenttype"], ContentType.objects.all())
+            mocked_casts_to_bigint.assert_called()
+            query = str(objects.query).lower()
+        self.assertEqual(set(objects), {self.obj1})
+        self.assertNotIn(obj4, objects)
+        assert_query_does_not_cast_object_pk(self, query)
+
     def test_ensure_returns_queryset(self):
         objects = get_objects_for_group(self.group1, 
["contenttypes.change_contenttype"])
         self.assertTrue(isinstance(objects, QuerySet))
@@ -1813,6 +1927,56 @@
             f"get_perms {all_perms} should be superset of get_group_perms 
{group_perms}",
         )
 
+    def test_get_user_perms_consistent_inactive_user(self):
+        """Test that get_user_perms in ObjectPermissionChecker and the 
get_user_perms shortcut
+        return consistent results for an inactive user."""
+
+        assign_perm("change_contenttype", self.user, self.obj)
+
+        checker = ObjectPermissionChecker(self.user)
+
+        get_user_perms_result_active = checker.get_user_perms(self.obj)
+        shortcuts_get_user_perms_result_active = get_user_perms(self.user, 
self.obj)
+
+        # Make user inactive
+        self.user.is_active = False
+        self.user.save()
+
+        get_user_perms_result_inactive = checker.get_user_perms(self.obj)
+        shortcuts_get_user_perms_result_inactive = get_user_perms(self.user, 
self.obj)
+
+        self.assertTrue(
+            set(get_user_perms_result_active) == 
set(shortcuts_get_user_perms_result_active) == {"change_contenttype"},
+        )
+        self.assertTrue(
+            set(get_user_perms_result_inactive) == 
set(shortcuts_get_user_perms_result_inactive) == set(),
+        )
+
+    def test_get_perms_consistent_inactive_user(self):
+        """Test that get_perms in ObjectPermissionChecker and the get_perms 
shortcut
+        return consistent results for an inactive user."""
+
+        assign_perm("change_contenttype", self.user, self.obj)
+
+        checker = ObjectPermissionChecker(self.user)
+
+        get_perms_result_active = checker.get_perms(self.obj)
+        shortcuts_get_perms_result_active = get_perms(self.user, self.obj)
+
+        # Make user inactive
+        self.user.is_active = False
+        self.user.save()
+
+        get_perms_result_inactive = checker.get_perms(self.obj)
+        shortcuts_get_perms_result_inactive = get_perms(self.user, self.obj)
+
+        self.assertTrue(
+            get_perms_result_active == shortcuts_get_perms_result_active == 
["change_contenttype"],
+        )
+        self.assertTrue(
+            get_perms_result_inactive == shortcuts_get_perms_result_inactive 
== [],
+        )
+
     def test_superuser_behavior(self):
         """Test behavior with superuser."""
         superuser = User.objects.create_superuser(username="superuser", 
email="[email protected]", password="pass")
@@ -2219,6 +2383,7 @@
 
         uuid_objects = get_objects_for_user(self.user, 
"testapp.add_uuidpkmodel")
         self.assertEqual(len(uuid_objects), 1)
+        self.assertEqual(set(uuid_objects.values_list("pk", flat=True)), 
{uuid_obj1.pk})
 
         # Test with TextField (non-standard, uses fix)
         text_obj1 = TextPKModel.objects.create(text_pk="text-id-1")
@@ -2228,6 +2393,7 @@
 
         text_objects = get_objects_for_user(self.user, 
"testapp.add_textpkmodel")
         self.assertEqual(len(text_objects), 1)
+        self.assertEqual(set(text_objects.values_list("pk", flat=True)), 
{text_obj1.pk})
 
         # Both should behave consistently
         self.assertEqual(len(uuid_objects), len(text_objects))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django_guardian-3.3.1/pyproject.toml 
new/django_guardian-3.3.4/pyproject.toml
--- old/django_guardian-3.3.1/pyproject.toml    2026-03-30 11:44:38.000000000 
+0200
+++ new/django_guardian-3.3.4/pyproject.toml    2026-08-27 02:04:37.305000500 
+0200
@@ -1,6 +1,6 @@
 [project]
 name = "django-guardian"
-version = "3.3.1"
+version = "3.3.4"
 description = "Per object permissions for Django"
 keywords = ["django", "permissions", "authorization", "object", "row", "level"]
 readme = "README.md"
@@ -95,24 +95,24 @@
   { name = "Richard de Wit", email = "[email protected]" },
   { name = "Pedro Rojas Gavidia", email = "[email protected]" },
   { name = "Rainshaw Gao", email = "[email protected]" },
-  {name = "Tom Clark", email = "[email protected]"},
+  { name = "Tom Clark", email = "[email protected]"},
+  { name = "David Graham", email = "[email protected]" },
   { name = "Meredith Hoo", email = "[email protected]" },
   { name = "Chris Maggiuli" },
   { name = "Bona Fide IT GmbH"},
   { name = "Columbia University, SIS Development and Application Services" },
   { name = "Cornelius Hoffmann", email = "[email protected]" },
   { name = "Sezer BOZKIR", email = "[email protected]"},
+  { name = "Paul Martin", email = "[email protected]"},
+  { name = "marko1olo", email = "[email protected]" },
+  { name = "Michael K." },
+  { name = "Chris Maggiuli" },
+  { name = "Bona Fide IT GmbH" },
 ]
 maintainers = [
-  {name = "Tom Clark", email = "[email protected]"},
-  { name = "Brian May", email = "[email protected]" },
-  { name = "Lukasz Balcerzak", email = "[email protected]" },
-  { name = "Adam Dobrawy", email = "[email protected]" },
+  { name = "Sezer BOZKIR", email = "[email protected]" },
   { name = "David Graham", email = "[email protected]" },
-  { name = "Michael K." },
-  { name = "Chris Maggiuli" },
-  { name = "Bona Fide IT GmbH"},
-  { name = "Sezer BOZKIR", email = "[email protected]"},
+  { name = "Tom Clark", email = "[email protected]" },
 
 ]
 dependencies = [
@@ -124,7 +124,7 @@
 Homepage = "https://github.com/django-guardian/django-guardian";
 Documentation = "https://django-guardian.readthedocs.io/";
 Repository = "https://github.com/django-guardian/django-guardian";
-Issues = "https://github.com/me/spam/issues";
+Issues = "https://github.com/django-guardian/django-guardian/issues";
 Changelog = "https://github.com/django-guardian/django-guardian/releases";
 
 [dependency-groups]

Reply via email to