4

im trying to get mptt working with my current project, but having issues with the database migration.

here is my model

from django.db import models
from mptt.models import MPTTModel, TreeForeignKey

class Section(MPTTModel):
    name = models.CharField(max_length=50, unique=True)
    parent = TreeForeignKey('self', null=True, blank=True, related_name='children', db_index=True)

    class MPTTMeta:
        order_insertion_by = ['name']

and im running this in the command line:

sudo python manage.py makemigrations core

but seem to be getting and error related to the level field

You are trying to add a non-nullable field 'level' to section without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows)
 2) Quit, and let me add a default in models.py
Select an option:

what should I do?

Philippe Fisher
  • 586
  • 7
  • 28

2 Answers2

4

'Level' is automatically added by MPTTModel to denote the 'depth' of a particular node in the tree. If you haven't created the tree structure yet, it should be safe to choose option 1 and default everything to level 0 (root). If you do not have the tree structure set up yet, this should be fine and should get adjusted as you work with the tree later.

If you already have a tree structure in mind and you need to reflect that in your data, you will still need to do this, but you will need to follow it with a (probably handwritten) data migration to set the right values.

Two-Bit Alchemist
  • 17,966
  • 6
  • 47
  • 82
0

--- Update 2022 ---

As far as I see you can set everything to 0 for level, lft, rght and tree_id:

ex:

You are trying to add a non-nullable field 'level' to section without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows)
 2) Quit, and let me add a default in models.py
Select an option:

After you set all your values to zero and migrate, you tree will look like this:

{
  "id": 1,
  "name":"first test tree",
  "lft": 0,
  "rght": 0,
  "tree_id": 0,
  "level": 0,
  "parent": null
}

Then you need to go inside the shell and rebuild all trees:

Section.objects.rebuild()

After your rebuild command is done your trees will be set as normal, able to create new children:

{
   "id": 1,
   "name": "first test tree",
   "lft": 1,
   "rght": 2,
   "tree_id": 1,
   "level": 0,
   "parent": null
}

Other approach:

You can also add the rebuild()command within your model after save; Great for those who don't have access to the database or production termial:

from django.db import models
from mptt.models import MPTTModel, TreeForeignKey

class Section(MPTTModel):
    name = models.CharField(max_length=50, unique=True)
    parent = TreeForeignKey('self', null=True, blank=True, related_name='children', db_index=True)

    class MPTTMeta:
        order_insertion_by = ['name']

    def save(self, *args, **kwargs):
        # before save
        super(Section, self).save(*args, **kwargs)
        # after save...
        try:
            # get all objects from the Section table.
            trees = Section.objects.all()
            # loops through all values.
            for tree in trees:
                # checks if there is default=0 and if yes rebuild the trees.
                if tree.lft or tree.rght or tree.tree_id == 0:
                    Section.objects.rebuild() 
        except Exception as e:
            print(e)
            pass

Elias Prado
  • 1,518
  • 2
  • 17
  • 32