【问题标题】:How to bulk_create using a django-mptt model?如何使用 django-mptt 模型进行批量创建?
【发布时间】:2020-09-15 18:19:09
【问题描述】:

我需要在 django-mptt 模型上使用 bulk_create,但出现错误:

django.db.utils.IntegrityError:“lft”列中的空值违反非空约束 详细信息:失败行包含 (2, Magic, null, null, null, null, null, null, 1)。

如何在没有硬编码 lftrghttree_id 的情况下批量创建 django-mptt 模型?

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)

【问题讨论】:

    标签: python django django-models django-mptt


    【解决方案1】:

    回复较晚,但硬编码lftrghttree_id 并没有错。在创建模型后添加 MPTTModel 类时实际上是recommended,只要在创建后运行rebuild即可。

    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()
    

    您可能需要将模型稍微调整为add some kind of ordering

    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']
    

    【讨论】:

    • 0.13.4版本中,还需要在批量创建时将level定义为level=0,如lftrght
    猜你喜欢
    • 1970-01-01
    • 2012-10-12
    • 2016-08-15
    • 2011-04-06
    • 2015-02-26
    • 1970-01-01
    • 2012-09-21
    • 1970-01-01
    相关资源
    最近更新 更多