简体   繁体   中英

How to bulk_create using a django-mptt model?

I need to use bulk_create on a django-mptt model, but I am getting an error:

django.db.utils.IntegrityError: null value in column "lft" violates not-null constraint DETAIL: Failing row contains (2, Magic, null, null, null, null, null, null, 1).

How can I bulk create a django-mptt model without hard coding lft , rght , and tree_id ?

MRE

models.py:

from mptt.models import MPTTModel, TreeForeignKey

class Category(MPTTModel):
    parent = TreeForeignKey('self', on_delete=models.CASCADE, blank=True,
        null=True, related_name='children',
    )
    name = models.CharField(max_length=255)
    tcgplayer_category = models.ForeignKey('tcgplayer.TcgCategory', on_delete=models.PROTECT,
        blank=True, null=True)

    class Meta:
        unique_together = (
            ('parent', 'name'),
        )

    def __str__(self):
        return self.name

class TcgCategory(models.Model):
    id = models.PositiveSmallIntegerField(primary_key=True)
    name = models.CharField(max_length=255)

class CategoryGroup(models.Model):
    id = models.IntegerField(primary_key=True)
    category = models.ForeignKey('tcgplayer.TcgCategory', on_delete=models.CASCADE)

fixtures/category.json:

[{
    "model": "tcgplayer.tcgcategory",
    "pk": 1,
    "fields": {
      "name": "Magic",
    }
}, {
    "model": "tcgplayer.categorygroup",
    "pk": 1,
    "fields": {
      "category": 1,
      "name": "10th Edition",
    }
}, {
    "model": "tcgplayer.categorygroup",
    "pk": 2,
    "fields": {
      "category": 1,
      "name": "7th Edition",
    }
}]

tasks.py:

def convert_categories(category_ids):
    root_categories = TcgCategory.objects.filter(id__in=category_ids)
    category_parents = Category.objects.bulk_create([ # error is thrown here
        Category(
            tcgplayer_category_id=model['id'],
            name=model['name'],
        )
        for model in root_categories.values('id', 'name')
    ])
    for parent in category_parents:
        category_groups = CategoryGroup.objects.filter(category_id=parent.tcgplayer_category_id)
        category_models.extend([
            Category(
                tcgplayer_category_id=model['id'],
                name=model['name'],
                parent=parent,
            )
            for model in category_groups.values('id', 'name')
        ])
    Category.objects.bulk_create(category_models)

Late reply but it's not wrong to hardcode lft , rght , and tree_id . It's what's actually recommended when adding MPTTModel classes after the model is created, as long as you run rebuild after creation.

for parent in category_parents:
    category_groups = CategoryGroup.objects.filter(category_id=parent.tcgplayer_category_id)
    category_models.extend([
        Category(
            tcgplayer_category_id=model['id'],
            name=model['name'],
            parent=parent,
            lft=0,
            rght=0,
            tree_id=0
        )
        for model in category_groups.values('id', 'name')
    ])
Category.objects.bulk_create(category_models)
Category.objects.rebuild()

You might need to tweak the model a little bit to add some kind of ordering though

from mptt.models import MPTTModel, TreeForeignKey

class Category(MPTTModel):
    parent = TreeForeignKey('self', on_delete=models.CASCADE, blank=True,
        null=True, related_name='children',
    )
    name = models.CharField(max_length=255)
    tcgplayer_category = models.ForeignKey('tcgplayer.TcgCategory', on_delete=models.PROTECT,
        blank=True, null=True)

    class Meta:
        unique_together = (
            ('parent', 'name'),
        )

    def __str__(self):
        return self.name

    class MPTTMeta:
        order_insertion_by = ['name']

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM