使用 django-import-export 在 django 迁移中的外键

Posted

技术标签:

【中文标题】使用 django-import-export 在 django 迁移中的外键【英文标题】:Foreign Key in django migration using django-import-export 【发布时间】:2015-02-19 10:53:15 【问题描述】:

我正在使用django-import-export 在迁移文件中加载 csv 文件,据我所知,这是 Django 1.7 加载初始数据的当前最佳做法。这适用于第一个文件:

class Country(models.Model):

    ISO2 = models.CharField(max_length=2, primary_key=True)
    name = models.CharField(max_length=50, unique=True)

以及整个迁移文件的内容。请注意,ISO2 是主键,因此需要添加行 import_id_fields = ['ISO2']。代码改编自这个问题的答案:Loading initial data with Django 1.7 and data migrations:

from django.conf import settings
import tablib
from import_export import resources
from web.models import Country
import os
import csv

# load initial data - assume it is all in web/fixtures directory

class CountryResource(resources.ModelResource):

    class Meta:
         model = Country
         import_id_fields = ['ISO2']

fixture_dir = os.path.abspath(os.path.join(settings.PROJECT_ROOT, 'web/fixtures'))
fixture_filename = 'web_country.csv'

def load_fixture(apps, schema_editor):
    fixture_file = os.path.join(fixture_dir, fixture_filename)

    with open(fixture_file, 'r') as content_file:
        content = content_file.read()

    resource = CountryResource()

    data = tablib.Dataset()
    data.csv = content


    result = resource.import_data(data,  dry_run=False,
                                 raise_errors=True)

def unload_fixture(apps, schema_editor):
    "Brutally deleting all entries for this model..."

    country = apps.get_model("web", "Country")
    country.objects.all().delete()

class Migration(migrations.Migration):

    dependencies = [
        ('web', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(load_fixture, reverse_code=unload_fixture),
    ]

现在是下一个与该文件有主键关系的文件:

class CountryFootprint(models.Model):
    ISO2 = models.ForeignKey(Country)
    footprint = models.DecimalField(max_digits=18,  decimal_places=6)

和迁移文件的一个子集,我尝试链接外键:

class CountryFootprintResource(resources.ModelResource):

    ISO2_id = fields.Field( widget=widgets.ForeignKeyWidget(Country, 'ISO2'))

    class Meta:
         model = CountryFootprint

这个给我:

  django.db.models.fields.related.RelatedObjectDoesNotExist: CountryFootprint has no ISO2.

也试过了:

  ISO2_id = fields.Field(column_name='ISO2_id', attribute='ISO2', widget=widgets.ForeignKeyWidget(Country, 'ISO2'))


  File "/Users/phoebebr/Development/gmd/web/migrations/0003_auto_20141220_1931.py", line 43, in load_fixture
    raise_errors=True)
  File "/Users/phoebebr/.virtualenvs/gmd/lib/python2.7/site-packages/import_export/resources.py", line 359, in import_data
    six.reraise(*sys.exc_info())
  File "/Users/phoebebr/.virtualenvs/gmd/lib/python2.7/site-packages/import_export/resources.py", line 348, in import_data
    row_result.object_repr = force_text(instance)
  File "/Users/phoebebr/.virtualenvs/gmd/lib/python2.7/site-packages/django/utils/encoding.py", line 85, in force_text
    s = six.text_type(s)
TypeError: coercing to Unicode: need string or buffer, Country found

我已经阅读了documentation 并且我确信答案就在那里,但它并没有跳出来!

【问题讨论】:

只在 CountryFootprintResource 的 Meta 类中指定 fields = ('ISO2') 不起作用? 试过了,TypeError: coercing to Unicode: need string or buffer, Country又找到了。奇怪,你会认为 Country 是正确的,它正在寻找一个字符串。 感谢 DRC 的推动,终于到了。 【参考方案1】:

这两行中的任何一个都可以:

ISO2_id = fields.Field( widget=widgets.ForeignKeyWidget(Country, 'ISO2'))

ISO2_id = fields.Field(column_name='ISO2_id', attribute='ISO2', widget=widgets.ForeignKeyWidget(Country, 'ISO2'))

只使用:

fields = ('ISO2', 'footprint')

报错

django.db.models.fields.related.RelatedObjectDoesNotExist: CountryFootprint has no ISO2.

强制转换为 Unicode 错误是由于我没有从 unicode def 返回的字符串:

def __unicode__(self):
    return self.ISO2

应该是

def __unicode__(self):
    return self.ISO2.name

睡个好觉解决了这么多编码问题!

【讨论】:

以上是关于使用 django-import-export 在 django 迁移中的外键的主要内容,如果未能解决你的问题,请参考以下文章

如何在 django-import-export 中使用 ForeignKeywidget 解决 MultipleObjectsReturned

Django-Import-Export插件关于外键的处理

如何使用 django-import-export 为字段定义管理员导入格式

django插件之django-import-export

xadmin引入django-import-export导入功能

Django 导入 Excel 端点