如果 Django ImportExportModelAdmin 中不存在则创建对象

Create object if not exists in Django ImportExportModelAdmin

我有这两个型号:

Profile_model.py

class Profile(models.Model):
    firstname = models.CharField(max_length=200, blank=False)
    lastname = models.CharField(max_length=200, blank=False)
    email = models.CharField(max_length=200, unique=True, blank=False)
    ...

Investment_model.py

class Investment(models.Model):
    invested = models.DecimalField(max_digits=9, decimal_places=2, blank=True, null=True)
    profile = models.ForeignKey(Profile, on_delete=models.CASCADE)
    ...

我有这个管理员:

Investment_admin.py

class InvestmentResource(resources.ModelResource):
    ...
    firstname = fields.Field(attribute='profile', 
        widget=ForeignKeyWidget(Profile, field='firstname'), 
        column_name='firstname')
    lastname = fields.Field(attribute='profile', 
        widget=ForeignKeyWidget(Profile, field='lastname'), 
        column_name='lastname')
    email = fields.Field(attribute='email', 
        widget=ForeignKeyWidget(Profile, field='email'), 
        column_name='email')
    class Meta:
        model = Investment
        fields = (
            'firstname',
            'lastname',
            'email',
            'invested',)
        
        export_order = fields


class InvestmentAdmin(ImportExportModelAdmin, admin.ModelAdmin):
        ...
        resource_class = InvestmentResource
        ...

我正在使用 djangoImportExportModelAdmin 进行批量导入和导出,但是当我尝试导入时,出现此错误:

我知道它会产生此错误,因为尚未创建配置文件。但是我需要做什么才能在 ImportExportModelAdmin 中实现 update_or_create

选项 1 是使用 before_import() 扫描数据集并批量创建配置文件(如果尚不存在)。

选项 2 是覆盖方法并在导入 Investment 行之前创建配置文件。这仅对新的 Investment 对象是必需的。这里假设 'email' 将唯一标识一个 Profile,如果不是,则需要调整它。

请注意,firstnamelastname 可以在创建 Profile 对象之前设置。

class InvestmentResource(resources.ModelResource):
    firstname = fields.Field(attribute='profile__firstname', 
        widget=CharWidget(), column_name='firstname')

    lastname = fields.Field(attribute='profile__lastname', 
        widget=CharWidget(), column_name='lastname')

    email = fields.Field(attribute='email', 
        widget=ForeignKeyWidget(Profile, field='email'), 
        column_name='email')

    def before_import_row(self, row, row_number=None, **kwargs):
        self.email = row["email"]

    def after_import_instance(self, instance, new, row_number=None, **kwargs):
        """
        Create any missing Profile entries prior to importing rows.
        """
        if (
            new
            and not Profile.objects.filter(
                name=self.email
            ).exists()
        ):
            obj, created = Profile.objects.get_or_create(
                name=self.email
            )
            if created:
                logger.debug(f"no Profile in db with name='{self.email}' - created")
                instance.profile = obj

显然,配置文件创建将是导入的副作用,因此如果您不想在导入失败时创建配置文件,则可能需要考虑使用事务。