Django导入导出:无需添加即可更新

时间:2017-02-08 19:28:58

标签: django django-import-export

我正在使用'django import export'(DIE)来导入和更新一些数据。

导入过程从检查DB中的存在对象开始,按ID字段中的值搜索,如果找不到导入文件中具有ID的行,则将创建新的entre。如何进行“仅更新”方案,如果在DB中找不到“id key”,则会跳过行(不添加新行)?

我的model.py

class Size(models.Model):
    id = models.AutoField(unique=True, primary_key=True, null=False, blank=False)
    height = models.SmallIntegerField()
    width = models.SmallIntegerField()


class Product(models.Model):
    id = models.AutoField(unique=True, primary_key=True, null=False, blank=False)
    vendor_code = models.CharField(unique=True, max_length=50, null=False, blank=False)
    price = models.DecimalField(null=False, blank=False)
    size = models.ForeignKey(Size, verbose_name=u'Size')

在resource.py

class ProductSyncResource(resources.ModelResource):

    class Meta:
        model = ProductVariant
        import_id_fields = ('vendor_code',)
        fields = ('vendor_code', 'price',)
        export_order = ('vendor_code', 'price', 'status', )
        skip_unchanged = True
        report_skipped = True
        dry_run = True

导入表(xls)

enter image description here

如果找不到vendor_code'Tк-12856'(单元格A3),那么DIE将尝试添加此行,并且:

  1. 我们将从DB中获取错误(foreignKey检查列'size')
  2. 我不需要在“更新方案”
  3. 中将此行添加到数据库中

2 个答案:

答案 0 :(得分:1)

最后我通过覆盖skip_row得到了它。现在,字段可以为“null = False”,并且仅导入具有已知import_id_field值的行。

class VariantSyncResource(resources.ModelResource):

    class Meta:
        model = ProductVariant
        import_id_field = 'vendor_code'
        import_id_fields = ('vendor_code',)
        fields = ('vendor_code', 'price', 'status', )
        export_order = ('vendor_code', 'price', 'status', )
        skip_unchanged = True
        report_skipped = False
        dry_run = True

    def skip_row(self, instance, original):
        original_id_value = getattr(original, self._meta.import_id_field)
        instance_id_value = getattr(instance, self._meta.import_id_field)
        if original_id_value != instance_id_value:
            return True
        if not self._meta.skip_unchanged:
            return False
        for field in self.get_fields():
            try:
                if list(field.get_value(instance).all()) != list(field.get_value(original).all()):
                    return False
            except AttributeError:
                if field.get_value(instance) != field.get_value(original):
                    return False
        return True

答案 1 :(得分:0)

如果您不想创建新对象,我认为您需要覆盖ProductSyncResource内的import_row()

然后你可以做if new: return;

def import_row(self, row, instance_loader, using_transactions=True, dry_run=False, **kwargs):

    row_result = self.get_row_result_class()()
    try:
        self.before_import_row(row, **kwargs)
        instance, new = self.get_or_init_instance(instance_loader, row)
        self.after_import_instance(instance, new, **kwargs)
        if new:
            return row_result
        else:
            row_result.import_type = RowResult.IMPORT_TYPE_UPDATE
        row_result.new_record = new
        original = deepcopy(instance)
        ...

根据您对预览错误的评论,请记住这不是应用程序的官方功能,因此您只需遵循堆栈跟踪&解决弹出的问题。我上面的第一个想法看起来像最快的&最简单的方法,但您可以尝试使else保存save条件对新对象;

            elif not new:
                with transaction.atomic():
                    self.save_instance(instance, using_transactions, dry_run)
                self.save_m2m(instance, row, using_transactions, dry_run)
            diff.compare_with(self, instance, dry_run)