Repository: pulp/pulpcore

Issue:
get_user_model calls cause circular imports
**Version**
pulpcore 3.27, pulp container 2.16.x

**Describe the bug**
```
Traceback (most recent call last):
  File "/venv/bin/django-admin", line 8, in <module>
    sys.exit(execute_from_command_line())
  File "/venv/lib64/python3.9/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line
    utility.execute()
  File "/venv/lib64/python3.9/site-packages/django/core/management/__init__.py", line 416, in execute
    django.setup()
  File "/venv/lib64/python3.9/site-packages/django/__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/venv/lib64/python3.9/site-packages/django/apps/registry.py", line 116, in populate
    app_config.import_models()
  File "/venv/lib64/python3.9/site-packages/django/apps/config.py", line 269, in import_models
    self.models_module = import_module(models_module_name)
  File "/usr/lib64/python3.9/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 850, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "/venv/lib64/python3.9/site-packages/pulp_container/app/models.py", line 28, in <module>
    from pulpcore.plugin.util import gpg_verify
  File "/venv/lib64/python3.9/site-packages/pulpcore/plugin/util.py", line 1, in <module>
    from pulpcore.app.role_util import (  # noqa
  File "/venv/lib64/python3.9/site-packages/pulpcore/app/role_util.py", line 14, in <module>
    from pulpcore.app.models.role import GroupRole, Role, UserRole
  File "/venv/lib64/python3.9/site-packages/pulpcore/app/models/role.py", line 30, in <module>
    class UserRole(BaseModel):
  File "/venv/lib64/python3.9/site-packages/pulpcore/app/models/role.py", line 44, in UserRole
    get_user_model(), related_name="object_roles", on_delete=models.CASCADE
  File "/venv/lib64/python3.9/site-packages/django/contrib/auth/__init__.py", line 170, in get_user_model
    return django_apps.get_model(settings.AUTH_USER_MODEL, require_ready=False)
  File "/venv/lib64/python3.9/site-packages/django/apps/registry.py", line 211, in get_model
    app_config.import_models()
  File "/venv/lib64/python3.9/site-packages/django/apps/config.py", line 269, in import_models
    self.models_module = import_module(models_module_name)
  File "/usr/lib64/python3.9/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "/app/galaxy_ng/app/models/__init__.py", line 17, in <module>
    from .container import (
  File "/app/galaxy_ng/app/models/container.py", line 11, in <module>
    container_models.ContainerDistribution,
AttributeError: partially initialized module 'pulp_container.app.models' has no attribute 'ContainerDistribution' (most likely due to a circular import)
make: *** [Makefile:108: docker/loaddata] Error 1
```

**To Reproduce**
Spin up galaxy_ng with pulpcore updated to 3.27.

**Expected behavior**
No circular import errors.

**Additional context**




Discussion:

Resolving patch:
diff --git a/pulpcore/app/models/role.py b/pulpcore/app/models/role.py
--- a/pulpcore/app/models/role.py
+++ b/pulpcore/app/models/role.py
@@ -1,4 +1,4 @@
-from django.contrib.auth import get_user_model
+from django.conf import settings
 from django.contrib.auth.models import Permission
 from django.contrib.contenttypes.fields import GenericForeignKey
 from django.contrib.contenttypes.models import ContentType
@@ -41,7 +41,7 @@ class UserRole(BaseModel):
     """
 
     user = models.ForeignKey(
-        get_user_model(), related_name="object_roles", on_delete=models.CASCADE
+        settings.AUTH_USER_MODEL, related_name="object_roles", on_delete=models.CASCADE
     )
     role = models.ForeignKey(Role, related_name="object_users", on_delete=models.CASCADE)
     content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=True)
diff --git a/pulpcore/app/role_util.py b/pulpcore/app/role_util.py
--- a/pulpcore/app/role_util.py
+++ b/pulpcore/app/role_util.py
@@ -1,19 +1,23 @@
 from gettext import gettext as _
 
 from collections import defaultdict
+from functools import lru_cache
 
 from django.conf import settings
 from django.core.exceptions import BadRequest
 from django.db.models import Q, Exists, OuterRef, CharField
 from django.db.models.functions import Cast
-from django.contrib.auth import get_user_model
+from django.contrib.auth import get_user_model as django_get_user_model
 from django.contrib.auth.models import Permission
 from django.contrib.contenttypes.models import ContentType
 
 from pulpcore.app.models import Group
 from pulpcore.app.models.role import GroupRole, Role, UserRole
 
-User = get_user_model()
+
+@lru_cache(maxsize=1)
+def get_user_model():
+    return django_get_user_model()
 
 
 def assign_role(rolename, entity, obj=None, domain=None):
@@ -300,6 +304,7 @@ def get_users_with_perms_roles(
     include_model_permissions=True,
     for_concrete_model=False,
 ):
+    User = get_user_model()
     qs = User.objects.none()
     if with_superusers:
         qs |= User.objects.filter(is_superuser=True)
@@ -338,6 +343,7 @@ def get_users_with_perms_attached_perms(
     include_model_permissions=True,
     for_concrete_model=False,
 ):
+    User = get_user_model()
     ctype = ContentType.objects.get_for_model(obj, for_concrete_model=for_concrete_model)
     perms = Permission.objects.filter(content_type__pk=ctype.id)
     if only_with_perms_in:
@@ -422,6 +428,7 @@ def get_users_with_perms(
     include_model_permissions=True,
     for_concrete_model=False,
 ):
+    User = get_user_model()
     if attach_perms:
         res = defaultdict(set)
         if "pulpcore.backends.ObjectRolePermissionBackend" in settings.AUTHENTICATION_BACKENDS:


Test patch: