16👍
You can define a post_migrate
signal to create required User
and Group
model instances if they don’t exist already.
When you create an application in using python manage.py startapp <app_name>
, it creates an AppConfig
class in apps.py file.
You can specify which signal to call in AppConfig
class definition. Say the signal is called populate_models
. In that case, modify AppConfig to look like following:
from django.apps import AppConfig
from django.db.models.signals import post_migrate
class AppConfig(AppConfig):
name = 'app'
def ready(self):
from .signals import populate_models
post_migrate.connect(populate_models, sender=self)
And in signals.py define the populate_models
function.
def populate_models(sender, **kwargs):
from django.contrib.auth.models import User
from django.contrib.auth.models import group
# create groups
# assign permissions to groups
# create users
5👍
According to @narenda-choudhary and @Rolando Cruz answer,
Here is the code for adding all existing permissions of an app under a Group.
For exemple if you have App1 and App2, and you want to automatically create 2 groups named app1 and app2 containing permissions to the models of each app (respectively), try this :
For App1 on apps.py :
from django.apps import AppConfig
from django.db.models.signals import post_migrate
class App1Config(AppConfig):
name = 'app1'
def ready(self):
from .signals import populate_models
post_migrate.connect(populate_models, sender=self)
Create a signals.py file that contains :
def populate_models(sender, **kwargs):
from django.apps import apps
from .apps import App1Config
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
group_app, created = Group.objects.get_or_create(name=App1Config.name)
models = apps.all_models[App1Config.name]
for model in models:
content_type = ContentType.objects.get(
app_label=App1Config.name,
model=model
)
permissions = Permission.objects.filter(content_type=content_type)
group_app.permissions.add(*permissions)
Do the same for App2
Then assign users to their groups.
For usage :
Create a file called permissions.py on each app and add :
from .apps import App1Config
def is_in_group_app1(user):
return user.groups.filter(name=App1Config.name).exists()
In views.py use :
from django.contrib.auth.decorators import login_required, user_passes_test
from .permissions import is_in_group_app1
@login_required(login_url='where_to_redirect')
@user_passes_test(is_in_group_app1)
def myview(request):
# Do your processing
For CBV :
@method_decorator(user_passes_test(is_in_group_app1), name='dispatch')
class LogListView(ListView):
""" Displays all logs saved on App1 """
model= Logger.objects.order_by('-date_created')
Create a folder named templatestag and subfolder app1 and a has_perms.py file :
from django import template
from app1.permissions import is_in_group_app1
register = template.Library()
@register.filter
def has_perms(user):
return is_in_group_app1(user)
In your template :
{% load has_perms %}
{% if request.user|has_perms %}
<li class="nav-item">
<a href="{% url 'app1:log' %}" class="nav-link">
<i class="icon-history"></i>
<span data-i18n="nav.dash.main">App1 Log</span>
</a>
</li>
{% endif %}
It took me a while to find all this process, so if it can help others :
Enjoy 😉 !
- Django Rest Framework: `get_serializer_class` called several times, with wrong value of request method
- How to logout in django?
- Django View Causes Psycopg2 Cursor Does/Does Not Exist Error
- Using django-rest-interface with http put
- What are some alternative for ModelChoiceField for large number of choices?
1👍
Note: scroll down to see my code implementation.
Django automatically populates the database at least on the following:
- Populating
contenttypes.ContentType
for each defined models - Populating
auth.Permission
for each default model permissions - Populating
sites.Site
with a default site example.com
Looking at the source code (django.contrib.contenttypes
, django.contrib.auth
, django.contrib.sites
), I found the following pattern:
-
Connect the receiver function to
post_migrate
signal inside theAppConfig
.Example from
django.contrib.sites.apps
:class SitesConfig(AppConfig): ... def ready(self): post_migrate.connect(create_default_site, sender=self) ...
-
Define the receiver function in the
management
module (instead of inside thesignal
module, which is usually used for defining the signal itself), and get the model class usingapps.get_model()
(instead of directly import the model class which could be inconsistent with the current state of migration).Example from
django.contrib.sites.management
:def create_default_site(app_config, verbosity=2, interactive=True, using=DEFAULT_DB_ALIAS, apps=global_apps, **kwargs): try: Site = apps.get_model('sites', 'Site') except LookupError: return if not router.allow_migrate_model(using, Site): return if not Site.objects.using(using).exists(): ...
The most important parameter here is
apps
for getting a model in the current migration state. If you use multiple databases, you’ll also need theusing
parameter to check if the model is allowed to be migrated and to be used in your query’s.using()
. For other parameter explanations, check thepost_migrate
signal docs.
Talk is cheap. Show me the code!
-
I created an
assign_group_permissions()
function, which returns a receiver function that populates some permissions for a given group.someproject/accounts/management.py
:from django import apps as global_apps from django.db.models import Q def assign_group_permissions(group_name, permissions): def receiver(*args, apps=global_apps, **kwargs): try: Group = apps.get_model('auth', 'Group') Permission = apps.get_model('auth', 'Permission') except LookupError: return perm_q = Q() for perm in permissions: app_label, codename = perm.split('.') perm_q |= Q(content_type__app_label=app_label) & Q(codename=codename) group, _ = Group.objects.get_or_create(name=group_name) group.permissions.add( *Permission.objects.filter(perm_q) ) return receiver
-
Call the function inside each of the corresponding
AppConfig
. The example below shows how to assign view, add, change, and delete permissions of theAnnouncement
model, which lives insomeproject.announcements
app toevent_admin
group.someproject/announcements/apps.py
:from django.apps import AppConfig from django.db.models.signals import post_migrate from someproject.accounts.management import assign_group_permissions class AnnouncementConfig(AppConfig): name = 'someproject.announcements' def ready(self): post_migrate.connect(assign_group_permissions( 'event_admin', [ 'announcements.add_announcement', 'announcements.change_announcement', 'announcements.delete_announcement', 'announcements.view_announcement', ], ))
- Django proxy User model example
- How to check that an uploaded file is a valid Image in Django
- Django South migration conflict while working in a team
- Django-allauth: Only allow users from a specific google apps domain
- Django 1.7 makemigrations freezing/hanging