Navid Khan
Navid Khan

Reputation: 1169

Django MPTT: Rebuild tree in migrations file

I already have a model in my project that I now want to use with django-mptt. This model already has some data in it.

During migrations, you are asked to set default values for some of the fields django-mptt creates. As directed in the documentation, I set 0 as the one off default value. The documentation goes ahead and recommends running Model.objects.rebuild() after this is done to set the correct values in the fields. I would like to perform this operation via my migrations files. I do NOT want to run this via my django-shell as this is not a one off operation.

My migration files is so:

# -*- coding: utf-8 -*-
# Generated by Django 1.11.16 on 2018-12-27 17:33
from __future__ import unicode_literals

from django.db import migrations, models


def migrate_mptt(apps, schema_editor):
    ProductCategory = apps.get_model("product", "ProductCategory")
    ProductCategory.objects.rebuild()


class Migration(migrations.Migration):

    dependencies = [
        ('product', '0016_auto_20181227_2303'),
    ]

    operations = [
        migrations.RunPython(migrate_mptt),
    ]

On migration, I receive the error AttributeError: 'Manager' object has no attribute 'rebuild'. The same command works perfectly in the shell, of course.

I need to do this via migrations since I want this operation to be run automatically every time my project is deployed.

Upvotes: 1

Views: 1054

Answers (1)

ncopiy
ncopiy

Reputation: 1624

If you want to do rebuild due migration you may to use this code. If you catch AttributeError with that, try to set model manager as your_name attribute (not as objects).

Also if you expect to rebuild after migrations you may extend your app config:

    from django.apps import AppConfig
    from django.db.models.signals import post_migrate

    def rebuild_tree(sender, **kwargs):
        from .models import YourModel
        YourModel.objects.rebuild()

    class YouApponfig(AppConfig):
        name = 'app_name'

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

Upvotes: 1

Related Questions