I'm using Django
for my backend and everything's fine.
But I now have to enable permissions and so on.
I'm trying to assign all the permissions of an app to a group during the migration process but here is the problem :
During the initial migration, the Permissions are not created yet. The reason is that in Django, they are created in a post_migrate
signal.
See :
def ready(self):
post_migrate.connect(
create_permissions,
dispatch_uid="django.contrib.auth.management.create_permissions"
)
# ...
in django.contrib.auth.apps
in the ready()
method
The default flow is :
migrate
commandpost_migrate
signal is sent and Permissions records are createdSo I could write a post_migrate function too but, how could I be sure that it will be run after the default one that creates Permissions ?
Other question : is there a better way to assign permissions automatically when an app is first migrated ?
Thanks in advance :)
It seems it is currently impossible to act on Permission creation since they are created in a post_migrate
signal (here) with the method bulk_create().
See here.
bulk_create()
is maintained for creating Permissions) is to run a method in the ready()
method (...) to assign them.For the 2)
solution, I ended up with this :
def distribute_base_permissions():
""" This method is used to automatically grant permissions of 'base' application
to the 'Administrator' Group.
"""
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
group_content_type = ContentType.objects.get_for_model(Group)
group, created = Group.objects.get_or_create(name="Administrator")
for model in ContentType.objects.filter(app_label="base"):
for perm in Permission.objects.filter(content_type__in=[model, group_content_type]):
if (not group.has_permission(perm.codename) and
perm.codename not in model.model_class().UNUSED_PERMISSIONS):
group.add_permissions([perm])
class BaseConfig(AppConfig):
name = 'backend.base'
def ready(self):
distribute_base_permissions()
There are some flourish things in that sample that are used for my specific use case, where I'm able to install/uninstall applications during runtime according to User necessities.
My base
application is installed by default so distributing its permissions can be done like this.
For my installable applications, it's pretty much the same except that it isn't done in the ready()
method but at the end of my custom installation process :
class Application(models.Model):
class Meta:
db_table = "base_application"
verbose_name = "Application"
# ...
def migrate_post_install(self):
# ...
self.distribute_permissions()
def distribute_permissions(self):
""" This method is used to automatically grant permissions of the installed
application to the 'Administrator' Group.
"""
group, created = Group.objects.get_or_create(name="Administrator")
for model in ContentType.objects.filter(app_label=self.name):
for perm in Permission.objects.filter(content_type=model):
if (not group.has_permission(perm.codename) and
perm.codename not in model.model_class().UNUSED_PERMISSIONS):
group.add_permissions([perm])
The solution 1)
has been refused as it can be seen here.
A solution that is discussed would be to add a post_migrate
handler but since Permission creation is already done in a post_migrate
, I don't know how to be sure that my signal handler will be run AFTER the one that creates Permissions...
Otherwise, it seems there is in progress work to change the Permission creation process as can be seen here.