Your goal is as follows:
- Goal X (Real goal): Create permissions dynamically according to the model fields
- Goal Y (Perceived goal that will achieve X): Call the model class while creating it.
Note: See What is the XY problem?
Let us first discuss Goal Y and why it is too complex, and somewhat unfeasable. When one wants to customize how the creation of a class occurs one would use metaclasses, and at first sight this would appear as a perfect solution for your needs (in fact if you do create one properly it would be). But the problem here is that Model
already has a metaclass being ModelBase
and it is already doing lots of stuff and is a little complicated. If we would want a custom metaclass we would need to inherit from it and very carefully work around its implementation to do what we want. Furthermore making it would not be the end of the story, because then we would need to maintain it since it would be easily breakable by updates to Django. Hence Goal Y is not feasible.
Moving on to the actual Goal X to do that one can Programmatically create permissions [Django docs]. A good place to do this would be in the app configs ready
method. For all apps created using startapp
there is an apps.py
file which has an appconfig inheriting from AppConfig
, when the models are loaded its ready
method is called. Hence this method is used to do various tasks like attaching signals, various setup like tasks, etc. Modify the appconfig of your app to create permissions programmatically like so:
from django.apps import AppConfig
class YourAppConfig(AppConfig):
default_auto_field = 'django.db.models.AutoField' # Don't modify, keep it as it is in your code
name = 'your_app' # Don't modify, keep it as it is in your code
def ready(self):
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from path.to import make_fields_permissions
from .models import Person
# import models here, not outside as models may not be loaded yet
content_type = ContentType.objects.get_for_model(Person)
for codename, name in make_fields_permissions(Person):
Permission.objects.get_or_create(
codename=codename, # 'can_view_first_name_field'
name=name, # 'can view first name'
content_type=content_type,
)