django-import-export - 从 JSON 文件导入 ManyToMany
django-import-export - Importing ManyToMany from JSON file
我正在尝试导入包含多对多关系的 JSON 文件,但遇到了一些问题。这是我的代码:
book.json
{
"title": "The Lord of the Rings",
"categories": [
"Fantasy",
"Action",
"Adventure"
]
}
models.py
from django.db import models
class Category(models.Model):
guid = models.CharField(max_length=36)
display_name = models.CharField(max_length=50)
description = models.TextField()
def __str__(self):
return self.display_name
class Book(models.Model):
title = models.CharField(max_length=200)
categories = models.ManyToManyField(Category)
def __str__(self):
return self.title
resources.py
from import_export import resources
from import_export.fields import Field
from import_export.widgets import ManyToManyWidget
from .models import Book, Category
class BookResource(resources.ModelResource):
categories = Field(widget=ManyToManyWidget(Category))
class Meta:
model = Book
import_id_fields = ('title',)
importer.py
from resources import BookResource
from models import Book
with open("book.json", 'r') as f:
book = '[' + f.read() + ']'
result = BookResource().import_data(tablib.Dataset().load(book), raise_errors=True, dry_run=True)
这似乎 运行 没有错误,并将新的 book
添加到数据库中。问题是它不会在 book_categories
table (PostgreSQL) 中创建新条目。我认为我肯定在某处遗漏了一步,因为我没有定义如何在给定 display_name
字符串列表的情况下找到正确的 category
数据库条目。我走在正确的轨道上吗?
简而言之,django-import-export
不处理这种情况:如果您查看 ManyToManyWidget.clean()
,您会发现它默认需要一串逗号分隔的整数。您可以在那里做一些事情,但它只是希望您先导入类别,然后再导入书籍。
我最后做的是删除 BookResource 上的 Field 和 Widget 并将其替换为 widgets 字典:
class BookResource(resources.ModelResource):
class Meta:
model = Book
import_id_fields = ("title",)
fields = ("id", "title", "categories")
widgets = {"categories": {"field": "display_name"}}
如果您随后先导入类别,那么您的图书将被正确链接。好吧,对 JSON 进行了一次修改,我将导入程序脚本包装起来,因此在控制台上它可以是 运行:
import django
import os
os.environ["DJANGO_SETTINGS_MODULE"] = "testbed.settings"
BOOK_DATA = """[{
"title": "The Lord of the Rings",
"categories": "Fantasy,Action,Adventure"
}]"""
def run():
from bookstore.resources import BookResource
import tablib
importer = BookResource()
dataset = tablib.Dataset()
data = dataset.load(BOOK_DATA, format="json")
result = importer.import_data(data, raise_errors=True, dry_run=False)
print(result.has_errors())
if __name__ == "__main__":
import sys
sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(__file__))))
django.setup()
run()
可以编写 JSON 特定的 M2M 小部件,但随后在导入类别时,您将需要弄清楚每一行哪些已经存在,哪些不存在。这是可行的,所以也许我已经让你走上了正确的轨道来修复它;)
感谢@Melvyn,我能够通过为 JSON 数组创建自定义小部件来解决这个问题。我会 post 它以防其他人遇到这个问题。
class ManyToManyJSONWidget(ManyToManyWidget):
def __init__(self, model, field=None, *args, **kwargs):
if field is None:
field = 'pk'
self.model = model
self.separator = None
self.field = field
def clean(self, value, row=None, *args, **kwargs):
if not value:
return self.model.objects.none()
else:
objs = []
for i in value:
obj = self.model.objects.filter(**{
'%s__iexact' % self.field: i
}).first()
objs.append(obj)
return objs
def render(self, value, obj=None):
return ""
我正在尝试导入包含多对多关系的 JSON 文件,但遇到了一些问题。这是我的代码:
book.json
{
"title": "The Lord of the Rings",
"categories": [
"Fantasy",
"Action",
"Adventure"
]
}
models.py
from django.db import models
class Category(models.Model):
guid = models.CharField(max_length=36)
display_name = models.CharField(max_length=50)
description = models.TextField()
def __str__(self):
return self.display_name
class Book(models.Model):
title = models.CharField(max_length=200)
categories = models.ManyToManyField(Category)
def __str__(self):
return self.title
resources.py
from import_export import resources
from import_export.fields import Field
from import_export.widgets import ManyToManyWidget
from .models import Book, Category
class BookResource(resources.ModelResource):
categories = Field(widget=ManyToManyWidget(Category))
class Meta:
model = Book
import_id_fields = ('title',)
importer.py
from resources import BookResource
from models import Book
with open("book.json", 'r') as f:
book = '[' + f.read() + ']'
result = BookResource().import_data(tablib.Dataset().load(book), raise_errors=True, dry_run=True)
这似乎 运行 没有错误,并将新的 book
添加到数据库中。问题是它不会在 book_categories
table (PostgreSQL) 中创建新条目。我认为我肯定在某处遗漏了一步,因为我没有定义如何在给定 display_name
字符串列表的情况下找到正确的 category
数据库条目。我走在正确的轨道上吗?
简而言之,django-import-export
不处理这种情况:如果您查看 ManyToManyWidget.clean()
,您会发现它默认需要一串逗号分隔的整数。您可以在那里做一些事情,但它只是希望您先导入类别,然后再导入书籍。
我最后做的是删除 BookResource 上的 Field 和 Widget 并将其替换为 widgets 字典:
class BookResource(resources.ModelResource):
class Meta:
model = Book
import_id_fields = ("title",)
fields = ("id", "title", "categories")
widgets = {"categories": {"field": "display_name"}}
如果您随后先导入类别,那么您的图书将被正确链接。好吧,对 JSON 进行了一次修改,我将导入程序脚本包装起来,因此在控制台上它可以是 运行:
import django
import os
os.environ["DJANGO_SETTINGS_MODULE"] = "testbed.settings"
BOOK_DATA = """[{
"title": "The Lord of the Rings",
"categories": "Fantasy,Action,Adventure"
}]"""
def run():
from bookstore.resources import BookResource
import tablib
importer = BookResource()
dataset = tablib.Dataset()
data = dataset.load(BOOK_DATA, format="json")
result = importer.import_data(data, raise_errors=True, dry_run=False)
print(result.has_errors())
if __name__ == "__main__":
import sys
sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(__file__))))
django.setup()
run()
可以编写 JSON 特定的 M2M 小部件,但随后在导入类别时,您将需要弄清楚每一行哪些已经存在,哪些不存在。这是可行的,所以也许我已经让你走上了正确的轨道来修复它;)
感谢@Melvyn,我能够通过为 JSON 数组创建自定义小部件来解决这个问题。我会 post 它以防其他人遇到这个问题。
class ManyToManyJSONWidget(ManyToManyWidget):
def __init__(self, model, field=None, *args, **kwargs):
if field is None:
field = 'pk'
self.model = model
self.separator = None
self.field = field
def clean(self, value, row=None, *args, **kwargs):
if not value:
return self.model.objects.none()
else:
objs = []
for i in value:
obj = self.model.objects.filter(**{
'%s__iexact' % self.field: i
}).first()
objs.append(obj)
return objs
def render(self, value, obj=None):
return ""