Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: Signal for "post initial migration"

For setting up new development systems I would like to have a "post initial migration" signal.

It seems that something like this does not exist yet.

In detail: I want a signal which runs after the initial migrations have run. The second call to "manage.py migrate" should not emit this signal.

Use case: I want to set up basic data (add some users and groups, add some dummy data for "example.com", ...).

I don't want to use a migration for this, since in a migration I have only the limited model which gets returned by apps.get_model("myapp", "Country").

Same for fixtures: I don't want to use fixtures because I get my tasks done much less painful if I have the real ORM model.

Is there a way to work around it?

like image 608
guettli Avatar asked May 03 '18 09:05

guettli


2 Answers

You could use the post_migrate signal. Check to see whether your dummy data has already been created (e.g. if User.objects.exists():) and stop if it does.

like image 139
Alasdair Avatar answered Nov 07 '22 21:11

Alasdair


@Alasdair's suggestion with the post-migrate signal sounds good, but I'll add my two cents anyways.

In past situations where I needed initial data (for example a superuser and some base config data) I used a custom admin command to assure that some initial data was present. Fixtures were not exactly achieving what I needed in those situations.

This admin command has to be idempotent in the sense that it only makes changes if the desired state is not reached yet.

For example, my ensure_auth_data command looked something like this:

class Command(BaseCommand):
    help = 'Creates superuser, permissions and groups.'

    def _ensure_superuser(self):
        u_created = False
        u_updated = False
        try:
            usr = User.objects.get(username='ralf')
        except User.DoesNotExist:
            usr = User()
            usr.username = 'ralf'
            u_created = True

        if not usr.is_active:
            usr.is_active = True
            u_updated = True
        if not usr.is_superuser:
            usr.is_superuser = True
            u_updated = True

        if u_created or u_updated:
            usr.save()

        if u_created:
            self.stdout.write('Created superuser "{}"'.format(usr.username))
        elif u_updated:
            self.stdout.write('Updated superuser "{}"'.format(usr.username))
        else:
            self.stdout.write('Superuser "{}" already up to date'.format(usr.username))

    def _ensure_permissions(self):
        # create some special permissions if they're not present

    def _ensure_groups(self):
        # create some special groups and assign them permissions

    def handle(self, *args, **options):
        self.stdout.write('Starting command')
        self.stdout.write('...')
        self._ensure_superuser()
        self.stdout.write('...')
        self._ensure_permissions()
        self.stdout.write('...')
        self._ensure_groups()
        self.stdout.write('...')
        self.stdout.write('Command finished')
like image 26
Ralf Avatar answered Nov 07 '22 22:11

Ralf