Импорт в таблицы из Django import_export

Я пытаюсь заполнить models в Django с помощью ForeignKey. Допустим, у нас есть, как в документации import_export следующий пример:

class Author(models.Model):
    id = models.BigAutoField(primary_key=True)
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name


class Category(models.Model):
    id = models.BigAutoField(primary_key=True)
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name


class Book(models.Model):
    name = models.CharField('Book name', max_length=100)
    author = models.ForeignKey(Author, blank=True, null=True, )
    ...
    price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    categories = models.ManyToManyField(Category, blank=True)

    def __str__(self):
        return self.name

Как я могу реализовать import_export модуль, который может проверить, существует ли существующий автор по имени (не по id), который не чувствителен к регистру, и который может создать нового автора, если его не существует?

В качестве примера, допустим, CSV-файл выглядит следующим образом:

name,author,...,price,categories
J.R.R. Tolkien,Lord of the Rings,...,40,["cat1","cat2"]

Также, если есть поле DateTime, как сгенерировать его в таблице ForeignKey?

NOTE: Я знаю об использовании натурального ключа:

from import_export.fields import Field
from import_export.widgets import ForeignKeyWidget

class AuthorManager(models.Manager):

    def get_by_natural_key(self, name):
        return self.get(name=name)

class Author(models.Model):

    objects = AuthorManager()

    name = models.CharField(max_length=100)
    birthday = models.DateTimeField(auto_now_add=True)

    def natural_key(self):
        return (self.name,)

# Only the author field uses natural foreign keys.
class BookResource(resources.ModelResource):

    author = Field(
        column_name = "author",
        attribute = "author",
        widget = ForeignKeyWidget(Author, use_natural_foreign_keys=True)
    )

    class Meta:
        model = Book

Но я не уверен, как проверить наличие UPPER или lower случая в CSV. И как сгенерировать новый Author, если он не существует.

Существует несколько способов создания отношения FK во время импорта, если оно еще не существует.

Вариант 1 - переопределить метод before_import_row()

class BookResource(resources.ModelResource):

    # note use of 'iexact' for case-insensitive lookup
    def before_import_row(self, row, **kwargs):
        author_name = row["author"]
        Author.objects.get_or_create(name__iexact=author_name, 
            defaults={"name": author_name})

    # other code omitted

Вариант 2 - подкласс ForeignKeyWidget

Просто подкласс ForeignKeyWidget и реализуйте проверку в clean():

class AuthorForeignKeyWidget(widgets.ForeignKeyWidget):

    def clean(self, value, row=None, **kwargs):
        author, created = Author.objects.get_or_create(name__iexact=value,
            defaults={"name": value})
        return author


class BookResource(resources.ModelResource):
    author = fields.Field(
        column_name='author',
        attribute='author',
        widget=AuthorForeignKeyWidget(Author))

    # other code omitted

Любой из этих способов будет работать хорошо. Я бы лично использовал вариант 2.

Также, если есть поле DateTime, как сгенерировать его в таблице ForeignKey?

Поскольку вы вызываете Author.objects.get_or_create(), вы можете добавить дату, если хотите, например:

author, created = Author.objects.get_or_create(name__iexact=value, 
    defaults={"name": value, "created": timezone.now()})

При использовании натуральных клавиш вы можете настроить код по своему усмотрению.

Соответствующий ответ о создании в массовом режиме

Вернуться на верх