Импорт в таблицы из 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()})
При использовании натуральных клавиш вы можете настроить код по своему усмотрению.