How to execute code on post_migrate signal in Django?
Asked Answered
S

3

16

I'm doing some kind of refactoring for my project, where I'm relying on the django django.contrib.auth.models.Permission model. So far I define the permissions for each new user using a post_save signal, so when the user is created, I assign their permissions using user.user_permissions.add(the_permission), this works perfectly.

Now I want to use the django.contrib.auth.models.Group model to clasify the permissions a user should have.

This is my code:

from django.apps import AppConfig
from django.db.models.signals import post_migrate
from django.contrib.auth.models import Group, Permission


def create_group(name, permissions):
    group = Group.objects.create(name=name)
    [group.permissions.add(permission) for permission in permissions]


def define_company_groups(sender, **kwargs):
    permissions = [
        Permission.objects.get(codename='add_mymodel'),
        Permission.objects.get(codename='change_mymodel'),
    ]
    create_group('managers', permissions)


class MyAppConfig(AppConfig):
    name = 'players'
    verbose_name = 'The players app'

    def ready(self):
        post_migrate.connect(define_company_groups, sender=self)

After define this code, I'm expecting that after call ./manage.py migrate this handler should be fired. But it doesn't happen, all I got is:

Running post-migrate handlers for application players
Adding permission 'players | mymodel | Can add mymodel'
Adding permission 'companies | company | Can change mymodel'
Adding permission 'companies | company | Can delete company'

I found this https://groups.google.com/forum/#!topic/django-developers/8MdaWtJp4VQ article, they say I should define my post_migrate handler inside a file named management.py, but it does not work for me.

Finally, here's my question: Where should I put this code for my custom post_migrate signal?

Shushan answered 7/9, 2015 at 22:29 Comment(2)
How are you telling Django to use MyAppConfig? In your INSTALLED_APPS setting?Marcin
Actually just by adding the app name to the INSTALLED_APPS tuple, Should be sufficient or should I add another config?Shushan
M
14

The Django docs recommend connecting the post_migrate signal in your app config's ready method. The Google groups post you link to is out of date, from before the docs were updated.

You also need to specify the app config in your INSTALLED_APPS setting.

INSTALLED_APPS = [
    'myapp.apps.MyAppConfig',
    # ...
]

Another way to configure your app is to use default_app_config in __init__.py of your app. See Configuring Applications. But the other way (dotted path to AppConfig) is preferred.

Marcin answered 7/9, 2015 at 22:39 Comment(0)
B
8

I have had done a post_migrate example for another question before. I will write down its solution. Maybe it will be helpful for you.

# in apps.py

...
from django.conf import settings
from django.db.models.signals import post_migrate

def create_default_site_profile(sender, **kwargs):
    """after migrations"""
    from django.contrib.sites.models import Site
    from core.models import SiteProfile

    site = Site.objects.get(id=getattr(settings, 'SITE_ID', 1))

    if not SiteProfile.objects.exists():
        SiteProfile.objects.create(site=site)

class CoreConfig(AppConfig):
    name = 'core'

    def ready(self):
        post_migrate.connect(create_default_site_profile, sender=self)
        
        # if you have other signals e.g. post_save, you can include it 
        # like the one below.
        from .signals import (create_site_profile)  
Biparietal answered 10/10, 2020 at 2:34 Comment(0)
G
2

Signal post_migrate is different from other signals. './manage.py' command will not execute the code from the apps.py files or the signals.py files To execute this signal, place it in the models.py file. Then you will get the desired result

Gagliardi answered 21/10, 2019 at 11:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.