Создайте объект, если он не существует в Django ImportExportModelAdmin

#django #django-import-export

Вопрос:

У меня есть эти две модели:

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
        ...
 

Я использую django s ImportExportModelAdmin для массового импорта и экспорта, но когда я пытаюсь импортировать, я получаю эту ошибку:

введите описание изображения здесь

Я понимаю, что это приводит к этой ошибке, потому что профиль еще не создан. Но что мне нужно сделать, чтобы реализовать update_or_create внутри ImportExportModelAdmin ?

Комментарии:

1. Я никогда не пользовался этим раньше, но, может быть, вы могли бы попробовать это. Создайте резервные модели и импортируйте данные, которые вы будете импортировать в эти модели, но в этих моделях при подключении профиля к Investment модели укажите on_delete=models.SET_NULL и null=True, blank=True свойства. Затем вы можете заполнить поле профиля Investment модели и перенести его в основные модели через оболочку.

Ответ №1:

Вариант 1-использовать before_import() для сканирования набора данных и пакетного создания профилей, если они еще не существуют.

Вариант 2-переопределить методы и создать профили непосредственно перед Investment импортом строки. Это необходимо только для новых Investment объектов. Это предполагает , что «электронная почта» будет однозначно идентифицировать a Profile , вам нужно будет скорректировать это, если нет.

Обратите внимание, что firstname и lastname может быть установлено для 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
 

Очевидно, что создание профиля будет побочным эффектом импорта, поэтому вам может потребоваться рассмотреть возможность использования транзакций, если вы не хотите, чтобы профили создавались в случае сбоя импорта.

Комментарии:

1. Привет, похоже, он сможет создать экземпляр после просмотра журналов с указанным выше кодом . Но он по-прежнему показывает, что запрос на сопоставление профиля ошибки не существует.

2. возможно, он вызывается на этапе «предварительного просмотра» (т. Е. Если вы используете интерфейс администратора). Лучше всего установить отладчик и пройти через него, чтобы вы могли видеть, что происходит.

3. Хорошо. Я так и сделаю, спасибо!

4. привет, не могли бы вы удалить комментарий со ссылкой на чат, пожалуйста? Я не смог заблокировать все поля в одном изображении. Спасибо!

5. хорошо, это было сделано