We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Cannot upload content via pulp-container because of the change made to the `Upload` model
The following commit broke the pulp-container upload: https://github.com/pulp/pulpcore/commit/9192c2bf0ccb0e0a2df595fd3efdd0980c80ff34.

Traceback:
```
pulp_1    | pulp [adbae673f9b7498d8240989c1bba93ff]: django.request:ERROR: Internal Server Error: /v2/myorg/mygroup/ubuntu/blobs/uploads/
pulp_1    | Traceback (most recent call last):
pulp_1    |   File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
pulp_1    |     response = get_response(request)
pulp_1    |                ^^^^^^^^^^^^^^^^^^^^^
pulp_1    |   File "/usr/local/lib/python3.11/site-packages/django/core/handlers/base.py", line 197, in _get_response
pulp_1    |     response = wrapped_callback(request, *callback_args, **callback_kwargs)
pulp_1    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pulp_1    |   File "/usr/local/lib/python3.11/site-packages/django/views/decorators/csrf.py", line 56, in wrapper_view
pulp_1    |     return view_func(*args, **kwargs)
pulp_1    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
pulp_1    |   File "/usr/local/lib/python3.11/site-packages/rest_framework/viewsets.py", line 124, in view
pulp_1    |     return self.dispatch(request, *args, **kwargs)
pulp_1    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pulp_1    |   File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 509, in dispatch
pulp_1    |     response = self.handle_exception(exc)
pulp_1    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
pulp_1    |   File "/src/pulp_container/pulp_container/app/registry_api.py", line 271, in handle_exception
pulp_1    |     response = super().handle_exception(exc)
pulp_1    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pulp_1    |   File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 469, in handle_exception
pulp_1    |     self.raise_uncaught_exception(exc)
pulp_1    |   File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
pulp_1    |     raise exc
pulp_1    |   File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 506, in dispatch
pulp_1    |     response = handler(request, *args, **kwargs)
pulp_1    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pulp_1    |   File "/src/pulp_container/pulp_container/app/registry_api.py", line 758, in create
pulp_1    |     upload.save()
pulp_1    |   File "/usr/lib64/python3.11/contextlib.py", line 81, in inner
pulp_1    |     return func(*args, **kwds)
pulp_1    |            ^^^^^^^^^^^^^^^^^^^
pulp_1    |   File "/usr/local/lib/python3.11/site-packages/django_lifecycle/mixins.py", line 196, in save
pulp_1    |     self._run_hooked_methods(AFTER_CREATE, **kwargs)
pulp_1    |   File "/usr/local/lib/python3.11/site-packages/django_lifecycle/mixins.py", line 312, in _run_hooked_methods
pulp_1    |     method.run(self)
pulp_1    |   File "/usr/local/lib/python3.11/site-packages/django_lifecycle/mixins.py", line 46, in run
pulp_1    |     self.method(instance)
pulp_1    |   File "/usr/local/lib/python3.11/site-packages/django_lifecycle/decorators.py", line 119, in func
pulp_1    |     hooked_method(*args, **kwargs)
pulp_1    |   File "/src/pulpcore/pulpcore/app/models/access_policy.py", line 70, in add_perms
pulp_1    |     viewset = get_viewset_for_model(self)
pulp_1    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
pulp_1    |   File "/src/pulpcore/pulpcore/app/util.py", line 188, in get_viewset_for_model
pulp_1    |     raise LookupError("Could not determine ViewSet base name for model {}".format(model_class))
```

This is reproducible always when trying to push any image to the Pulp Container Registry.

Affected code:
https://github.com/pulp/pulp_container/blob/742acc52f8fc44c4d18a41621455b21e2b9133ec/pulp_container/app/models.py#L804

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pulpcore/app/models/access_policy.py`
Content:
```
1 from django.contrib.auth import get_user_model
2 from django.contrib.auth.models import Group as BaseGroup
3 from django.db import models
4 from django_lifecycle import hook, LifecycleModelMixin
5 
6 from pulpcore.app.models import BaseModel
7 from pulpcore.app.util import get_viewset_for_model, get_current_authenticated_user
8 
9 
10 def _ensure_iterable(obj):
11     if isinstance(obj, str):
12         return [obj]
13     return obj
14 
15 
16 class AccessPolicy(BaseModel):
17     """
18     A model storing a viewset authorization policy and permission assignment of new objects created.
19 
20     Fields:
21 
22         creation_hooks (models.JSONField): A list of dictionaries identifying callables on the
23             ``pulpcore.plugin.access_policy.AccessPolicyFromDB`` which can add user or group roles
24             for newly created objects. This is a nullable field due to not all endpoints creating
25             objects.
26         statements (models.JSONField): A list of ``drf-access-policy`` statements.
27         viewset_name (models.TextField): The name of the viewset this instance controls
28             authorization for.
29         customized (BooleanField): False if the AccessPolicy has been user-modified. True otherwise.
30             Defaults to False.
31         queryset_scoping (models.JSONField): A dictionary identifying a callable to perform the
32             queryset scoping. This field can be null if the user doesn't want to perform scoping.
33 
34     """
35 
36     creation_hooks = models.JSONField(null=True)
37     statements = models.JSONField()
38     viewset_name = models.TextField(unique=True)
39     customized = models.BooleanField(default=False)
40     queryset_scoping = models.JSONField(null=True)
41 
42 
43 class AutoAddObjPermsMixin:
44     """
45     A mixin that automatically adds roles based on the ``creation_hooks`` data.
46 
47     To use this mixin, your model must support ``django-lifecycle``.
48 
49     This mixin adds an ``after_create`` hook which properly interprets the ``creation_hooks``
50     data and calls methods also provided by this mixin to add roles.
51 
52     These hooks are provided by default:
53 
54     * ``add_roles_for_object_creator`` will add the roles to the creator of the object.
55     * ``add_roles_for_users`` will add the roles for one or more users by name.
56     * ``add_roles_for_groups`` will add the roles for one or more groups by name.
57 
58     """
59 
60     def __init__(self, *args, **kwargs):
61         self.REGISTERED_CREATION_HOOKS = {
62             "add_roles_for_users": self.add_roles_for_users,
63             "add_roles_for_groups": self.add_roles_for_groups,
64             "add_roles_for_object_creator": self.add_roles_for_object_creator,
65         }
66         super().__init__(*args, **kwargs)
67 
68     @hook("after_create")
69     def add_perms(self):
70         viewset = get_viewset_for_model(self)
71         for permission_class in viewset.get_permissions(viewset):
72             if hasattr(permission_class, "handle_creation_hooks"):
73                 permission_class.handle_creation_hooks(self)
74 
75     def add_roles_for_users(self, roles, users):
76         """
77         Adds object-level roles for one or more users for this newly created object.
78 
79         Args:
80             roles (str or list): One or more roles to be added at object-level for the users.
81                 This can either be a single role as a string, or a list of role names.
82             users (str or list): One or more users who will receive object-level roles. This can
83                 either be a single username as a string or a list of usernames.
84 
85         Raises:
86             ObjectDoesNotExist: If any of the users do not exist.
87 
88         """
89         from pulpcore.app.role_util import assign_role
90 
91         roles = _ensure_iterable(roles)
92         users = _ensure_iterable(users)
93         for username in users:
94             user = get_user_model().objects.get(username=username)
95             for role in roles:
96                 assign_role(role, user, self)
97 
98     def add_roles_for_groups(self, roles, groups):
99         """
100         Adds object-level roles for one or more groups for this newly created object.
101 
102         Args:
103             roles (str or list): One or more object-level roles to be added for the groups. This
104                 can either be a single role as a string, or list of role names.
105             groups (str or list): One or more groups who will receive object-level roles. This
106                 can either be a single group name as a string or a list of group names.
107 
108         Raises:
109             ObjectDoesNotExist: If any of the groups do not exist.
110 
111         """
112         from pulpcore.app.role_util import assign_role
113 
114         roles = _ensure_iterable(roles)
115         groups = _ensure_iterable(groups)
116         for group_name in groups:
117             group = Group.objects.get(name=group_name)
118             for role in roles:
119                 assign_role(role, group, self)
120 
121     def add_roles_for_object_creator(self, roles):
122         """
123         Adds object-level roles for the user creating the newly created object.
124 
125         If the ``get_current_authenticated_user`` returns None because the API client did not
126         provide authentication credentials, *no* permissions are added and this passes silently.
127         This allows endpoints which create objects and do not require authorization to execute
128         without error.
129 
130         Args:
131             roles (list or str): One or more roles to be added at the object-level for the user.
132                 This can either be a single role as a string, or list of role names.
133 
134         """
135         from pulpcore.app.role_util import assign_role
136 
137         roles = _ensure_iterable(roles)
138         current_user = get_current_authenticated_user()
139         if current_user:
140             for role in roles:
141                 assign_role(role, current_user, self)
142 
143 
144 class Group(LifecycleModelMixin, BaseGroup, AutoAddObjPermsMixin):
145     class Meta:
146         proxy = True
147         permissions = [
148             ("manage_roles_group", "Can manage role assignments on group"),
149         ]
150
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pulpcore/app/models/access_policy.py b/pulpcore/app/models/access_policy.py
--- a/pulpcore/app/models/access_policy.py
+++ b/pulpcore/app/models/access_policy.py
@@ -67,10 +67,14 @@
 
     @hook("after_create")
     def add_perms(self):
-        viewset = get_viewset_for_model(self)
-        for permission_class in viewset.get_permissions(viewset):
-            if hasattr(permission_class, "handle_creation_hooks"):
-                permission_class.handle_creation_hooks(self)
+        try:
+            viewset = get_viewset_for_model(self)
+        except LookupError:
+            pass
+        else:
+            for permission_class in viewset.get_permissions(viewset):
+                if hasattr(permission_class, "handle_creation_hooks"):
+                    permission_class.handle_creation_hooks(self)
 
     def add_roles_for_users(self, roles, users):
         """

{"golden_diff": "diff --git a/pulpcore/app/models/access_policy.py b/pulpcore/app/models/access_policy.py\n--- a/pulpcore/app/models/access_policy.py\n+++ b/pulpcore/app/models/access_policy.py\n@@ -67,10 +67,14 @@\n \n     @hook(\"after_create\")\n     def add_perms(self):\n-        viewset = get_viewset_for_model(self)\n-        for permission_class in viewset.get_permissions(viewset):\n-            if hasattr(permission_class, \"handle_creation_hooks\"):\n-                permission_class.handle_creation_hooks(self)\n+        try:\n+            viewset = get_viewset_for_model(self)\n+        except LookupError:\n+            pass\n+        else:\n+            for permission_class in viewset.get_permissions(viewset):\n+                if hasattr(permission_class, \"handle_creation_hooks\"):\n+                    permission_class.handle_creation_hooks(self)\n \n     def add_roles_for_users(self, roles, users):\n         \"\"\"\n", "issue": "Cannot upload content via pulp-container because of the change made to the `Upload` model\nThe following commit broke the pulp-container upload: https://github.com/pulp/pulpcore/commit/9192c2bf0ccb0e0a2df595fd3efdd0980c80ff34.\r\n\r\nTraceback:\r\n```\r\npulp_1    | pulp [adbae673f9b7498d8240989c1bba93ff]: django.request:ERROR: Internal Server Error: /v2/myorg/mygroup/ubuntu/blobs/uploads/\r\npulp_1    | Traceback (most recent call last):\r\npulp_1    |   File \"/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py\", line 55, in inner\r\npulp_1    |     response = get_response(request)\r\npulp_1    |                ^^^^^^^^^^^^^^^^^^^^^\r\npulp_1    |   File \"/usr/local/lib/python3.11/site-packages/django/core/handlers/base.py\", line 197, in _get_response\r\npulp_1    |     response = wrapped_callback(request, *callback_args, **callback_kwargs)\r\npulp_1    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\npulp_1    |   File \"/usr/local/lib/python3.11/site-packages/django/views/decorators/csrf.py\", line 56, in wrapper_view\r\npulp_1    |     return view_func(*args, **kwargs)\r\npulp_1    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^\r\npulp_1    |   File \"/usr/local/lib/python3.11/site-packages/rest_framework/viewsets.py\", line 124, in view\r\npulp_1    |     return self.dispatch(request, *args, **kwargs)\r\npulp_1    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\npulp_1    |   File \"/usr/local/lib/python3.11/site-packages/rest_framework/views.py\", line 509, in dispatch\r\npulp_1    |     response = self.handle_exception(exc)\r\npulp_1    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^\r\npulp_1    |   File \"/src/pulp_container/pulp_container/app/registry_api.py\", line 271, in handle_exception\r\npulp_1    |     response = super().handle_exception(exc)\r\npulp_1    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\npulp_1    |   File \"/usr/local/lib/python3.11/site-packages/rest_framework/views.py\", line 469, in handle_exception\r\npulp_1    |     self.raise_uncaught_exception(exc)\r\npulp_1    |   File \"/usr/local/lib/python3.11/site-packages/rest_framework/views.py\", line 480, in raise_uncaught_exception\r\npulp_1    |     raise exc\r\npulp_1    |   File \"/usr/local/lib/python3.11/site-packages/rest_framework/views.py\", line 506, in dispatch\r\npulp_1    |     response = handler(request, *args, **kwargs)\r\npulp_1    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\npulp_1    |   File \"/src/pulp_container/pulp_container/app/registry_api.py\", line 758, in create\r\npulp_1    |     upload.save()\r\npulp_1    |   File \"/usr/lib64/python3.11/contextlib.py\", line 81, in inner\r\npulp_1    |     return func(*args, **kwds)\r\npulp_1    |            ^^^^^^^^^^^^^^^^^^^\r\npulp_1    |   File \"/usr/local/lib/python3.11/site-packages/django_lifecycle/mixins.py\", line 196, in save\r\npulp_1    |     self._run_hooked_methods(AFTER_CREATE, **kwargs)\r\npulp_1    |   File \"/usr/local/lib/python3.11/site-packages/django_lifecycle/mixins.py\", line 312, in _run_hooked_methods\r\npulp_1    |     method.run(self)\r\npulp_1    |   File \"/usr/local/lib/python3.11/site-packages/django_lifecycle/mixins.py\", line 46, in run\r\npulp_1    |     self.method(instance)\r\npulp_1    |   File \"/usr/local/lib/python3.11/site-packages/django_lifecycle/decorators.py\", line 119, in func\r\npulp_1    |     hooked_method(*args, **kwargs)\r\npulp_1    |   File \"/src/pulpcore/pulpcore/app/models/access_policy.py\", line 70, in add_perms\r\npulp_1    |     viewset = get_viewset_for_model(self)\r\npulp_1    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\npulp_1    |   File \"/src/pulpcore/pulpcore/app/util.py\", line 188, in get_viewset_for_model\r\npulp_1    |     raise LookupError(\"Could not determine ViewSet base name for model {}\".format(model_class))\r\n```\r\n\r\nThis is reproducible always when trying to push any image to the Pulp Container Registry.\r\n\r\nAffected code:\r\nhttps://github.com/pulp/pulp_container/blob/742acc52f8fc44c4d18a41621455b21e2b9133ec/pulp_container/app/models.py#L804\n", "before_files": [{"content": "from django.contrib.auth import get_user_model\nfrom django.contrib.auth.models import Group as BaseGroup\nfrom django.db import models\nfrom django_lifecycle import hook, LifecycleModelMixin\n\nfrom pulpcore.app.models import BaseModel\nfrom pulpcore.app.util import get_viewset_for_model, get_current_authenticated_user\n\n\ndef _ensure_iterable(obj):\n    if isinstance(obj, str):\n        return [obj]\n    return obj\n\n\nclass AccessPolicy(BaseModel):\n    \"\"\"\n    A model storing a viewset authorization policy and permission assignment of new objects created.\n\n    Fields:\n\n        creation_hooks (models.JSONField): A list of dictionaries identifying callables on the\n            ``pulpcore.plugin.access_policy.AccessPolicyFromDB`` which can add user or group roles\n            for newly created objects. This is a nullable field due to not all endpoints creating\n            objects.\n        statements (models.JSONField): A list of ``drf-access-policy`` statements.\n        viewset_name (models.TextField): The name of the viewset this instance controls\n            authorization for.\n        customized (BooleanField): False if the AccessPolicy has been user-modified. True otherwise.\n            Defaults to False.\n        queryset_scoping (models.JSONField): A dictionary identifying a callable to perform the\n            queryset scoping. This field can be null if the user doesn't want to perform scoping.\n\n    \"\"\"\n\n    creation_hooks = models.JSONField(null=True)\n    statements = models.JSONField()\n    viewset_name = models.TextField(unique=True)\n    customized = models.BooleanField(default=False)\n    queryset_scoping = models.JSONField(null=True)\n\n\nclass AutoAddObjPermsMixin:\n    \"\"\"\n    A mixin that automatically adds roles based on the ``creation_hooks`` data.\n\n    To use this mixin, your model must support ``django-lifecycle``.\n\n    This mixin adds an ``after_create`` hook which properly interprets the ``creation_hooks``\n    data and calls methods also provided by this mixin to add roles.\n\n    These hooks are provided by default:\n\n    * ``add_roles_for_object_creator`` will add the roles to the creator of the object.\n    * ``add_roles_for_users`` will add the roles for one or more users by name.\n    * ``add_roles_for_groups`` will add the roles for one or more groups by name.\n\n    \"\"\"\n\n    def __init__(self, *args, **kwargs):\n        self.REGISTERED_CREATION_HOOKS = {\n            \"add_roles_for_users\": self.add_roles_for_users,\n            \"add_roles_for_groups\": self.add_roles_for_groups,\n            \"add_roles_for_object_creator\": self.add_roles_for_object_creator,\n        }\n        super().__init__(*args, **kwargs)\n\n    @hook(\"after_create\")\n    def add_perms(self):\n        viewset = get_viewset_for_model(self)\n        for permission_class in viewset.get_permissions(viewset):\n            if hasattr(permission_class, \"handle_creation_hooks\"):\n                permission_class.handle_creation_hooks(self)\n\n    def add_roles_for_users(self, roles, users):\n        \"\"\"\n        Adds object-level roles for one or more users for this newly created object.\n\n        Args:\n            roles (str or list): One or more roles to be added at object-level for the users.\n                This can either be a single role as a string, or a list of role names.\n            users (str or list): One or more users who will receive object-level roles. This can\n                either be a single username as a string or a list of usernames.\n\n        Raises:\n            ObjectDoesNotExist: If any of the users do not exist.\n\n        \"\"\"\n        from pulpcore.app.role_util import assign_role\n\n        roles = _ensure_iterable(roles)\n        users = _ensure_iterable(users)\n        for username in users:\n            user = get_user_model().objects.get(username=username)\n            for role in roles:\n                assign_role(role, user, self)\n\n    def add_roles_for_groups(self, roles, groups):\n        \"\"\"\n        Adds object-level roles for one or more groups for this newly created object.\n\n        Args:\n            roles (str or list): One or more object-level roles to be added for the groups. This\n                can either be a single role as a string, or list of role names.\n            groups (str or list): One or more groups who will receive object-level roles. This\n                can either be a single group name as a string or a list of group names.\n\n        Raises:\n            ObjectDoesNotExist: If any of the groups do not exist.\n\n        \"\"\"\n        from pulpcore.app.role_util import assign_role\n\n        roles = _ensure_iterable(roles)\n        groups = _ensure_iterable(groups)\n        for group_name in groups:\n            group = Group.objects.get(name=group_name)\n            for role in roles:\n                assign_role(role, group, self)\n\n    def add_roles_for_object_creator(self, roles):\n        \"\"\"\n        Adds object-level roles for the user creating the newly created object.\n\n        If the ``get_current_authenticated_user`` returns None because the API client did not\n        provide authentication credentials, *no* permissions are added and this passes silently.\n        This allows endpoints which create objects and do not require authorization to execute\n        without error.\n\n        Args:\n            roles (list or str): One or more roles to be added at the object-level for the user.\n                This can either be a single role as a string, or list of role names.\n\n        \"\"\"\n        from pulpcore.app.role_util import assign_role\n\n        roles = _ensure_iterable(roles)\n        current_user = get_current_authenticated_user()\n        if current_user:\n            for role in roles:\n                assign_role(role, current_user, self)\n\n\nclass Group(LifecycleModelMixin, BaseGroup, AutoAddObjPermsMixin):\n    class Meta:\n        proxy = True\n        permissions = [\n            (\"manage_roles_group\", \"Can manage role assignments on group\"),\n        ]\n", "path": "pulpcore/app/models/access_policy.py"}], "after_files": [{"content": "from django.contrib.auth import get_user_model\nfrom django.contrib.auth.models import Group as BaseGroup\nfrom django.db import models\nfrom django_lifecycle import hook, LifecycleModelMixin\n\nfrom pulpcore.app.models import BaseModel\nfrom pulpcore.app.util import get_viewset_for_model, get_current_authenticated_user\n\n\ndef _ensure_iterable(obj):\n    if isinstance(obj, str):\n        return [obj]\n    return obj\n\n\nclass AccessPolicy(BaseModel):\n    \"\"\"\n    A model storing a viewset authorization policy and permission assignment of new objects created.\n\n    Fields:\n\n        creation_hooks (models.JSONField): A list of dictionaries identifying callables on the\n            ``pulpcore.plugin.access_policy.AccessPolicyFromDB`` which can add user or group roles\n            for newly created objects. This is a nullable field due to not all endpoints creating\n            objects.\n        statements (models.JSONField): A list of ``drf-access-policy`` statements.\n        viewset_name (models.TextField): The name of the viewset this instance controls\n            authorization for.\n        customized (BooleanField): False if the AccessPolicy has been user-modified. True otherwise.\n            Defaults to False.\n        queryset_scoping (models.JSONField): A dictionary identifying a callable to perform the\n            queryset scoping. This field can be null if the user doesn't want to perform scoping.\n\n    \"\"\"\n\n    creation_hooks = models.JSONField(null=True)\n    statements = models.JSONField()\n    viewset_name = models.TextField(unique=True)\n    customized = models.BooleanField(default=False)\n    queryset_scoping = models.JSONField(null=True)\n\n\nclass AutoAddObjPermsMixin:\n    \"\"\"\n    A mixin that automatically adds roles based on the ``creation_hooks`` data.\n\n    To use this mixin, your model must support ``django-lifecycle``.\n\n    This mixin adds an ``after_create`` hook which properly interprets the ``creation_hooks``\n    data and calls methods also provided by this mixin to add roles.\n\n    These hooks are provided by default:\n\n    * ``add_roles_for_object_creator`` will add the roles to the creator of the object.\n    * ``add_roles_for_users`` will add the roles for one or more users by name.\n    * ``add_roles_for_groups`` will add the roles for one or more groups by name.\n\n    \"\"\"\n\n    def __init__(self, *args, **kwargs):\n        self.REGISTERED_CREATION_HOOKS = {\n            \"add_roles_for_users\": self.add_roles_for_users,\n            \"add_roles_for_groups\": self.add_roles_for_groups,\n            \"add_roles_for_object_creator\": self.add_roles_for_object_creator,\n        }\n        super().__init__(*args, **kwargs)\n\n    @hook(\"after_create\")\n    def add_perms(self):\n        try:\n            viewset = get_viewset_for_model(self)\n        except LookupError:\n            pass\n        else:\n            for permission_class in viewset.get_permissions(viewset):\n                if hasattr(permission_class, \"handle_creation_hooks\"):\n                    permission_class.handle_creation_hooks(self)\n\n    def add_roles_for_users(self, roles, users):\n        \"\"\"\n        Adds object-level roles for one or more users for this newly created object.\n\n        Args:\n            roles (str or list): One or more roles to be added at object-level for the users.\n                This can either be a single role as a string, or a list of role names.\n            users (str or list): One or more users who will receive object-level roles. This can\n                either be a single username as a string or a list of usernames.\n\n        Raises:\n            ObjectDoesNotExist: If any of the users do not exist.\n\n        \"\"\"\n        from pulpcore.app.role_util import assign_role\n\n        roles = _ensure_iterable(roles)\n        users = _ensure_iterable(users)\n        for username in users:\n            user = get_user_model().objects.get(username=username)\n            for role in roles:\n                assign_role(role, user, self)\n\n    def add_roles_for_groups(self, roles, groups):\n        \"\"\"\n        Adds object-level roles for one or more groups for this newly created object.\n\n        Args:\n            roles (str or list): One or more object-level roles to be added for the groups. This\n                can either be a single role as a string, or list of role names.\n            groups (str or list): One or more groups who will receive object-level roles. This\n                can either be a single group name as a string or a list of group names.\n\n        Raises:\n            ObjectDoesNotExist: If any of the groups do not exist.\n\n        \"\"\"\n        from pulpcore.app.role_util import assign_role\n\n        roles = _ensure_iterable(roles)\n        groups = _ensure_iterable(groups)\n        for group_name in groups:\n            group = Group.objects.get(name=group_name)\n            for role in roles:\n                assign_role(role, group, self)\n\n    def add_roles_for_object_creator(self, roles):\n        \"\"\"\n        Adds object-level roles for the user creating the newly created object.\n\n        If the ``get_current_authenticated_user`` returns None because the API client did not\n        provide authentication credentials, *no* permissions are added and this passes silently.\n        This allows endpoints which create objects and do not require authorization to execute\n        without error.\n\n        Args:\n            roles (list or str): One or more roles to be added at the object-level for the user.\n                This can either be a single role as a string, or list of role names.\n\n        \"\"\"\n        from pulpcore.app.role_util import assign_role\n\n        roles = _ensure_iterable(roles)\n        current_user = get_current_authenticated_user()\n        if current_user:\n            for role in roles:\n                assign_role(role, current_user, self)\n\n\nclass Group(LifecycleModelMixin, BaseGroup, AutoAddObjPermsMixin):\n    class Meta:\n        proxy = True\n        permissions = [\n            (\"manage_roles_group\", \"Can manage role assignments on group\"),\n        ]\n", "path": "pulpcore/app/models/access_policy.py"}]}