本文介紹django-import-export在關(guān)聯(lián)外鍵時(shí)它浅,導(dǎo)出可以導(dǎo)出可讀字樣(而非關(guān)聯(lián)id),導(dǎo)入通過(guò)可讀字眼進(jìn)行導(dǎo)入(而非關(guān)聯(lián)id)
模型設(shè)計(jì)如下:
# models.py
from django.db import models
# Create your models here.
class User(models.Model):
gender_by_choice = (
('male', '男'),
('female', '女'),
)
username = models.CharField(max_length=10, unique=True, verbose_name='姓名')
age = models.IntegerField(verbose_name='年齡')
gender = models.CharField(max_length=6, choices=gender_by_choice, verbose_name='性別')
nickname = models.CharField(max_length=10, verbose_name='昵稱')
def __str__(self):
return self.username
class Meta:
verbose_name = '用戶'
verbose_name_plural = '用戶'
class Book(models.Model):
owner = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='歸屬者')
name = models.CharField(max_length=64, verbose_name='書(shū)名')
def __str__(self):
return self.name
class Meta:
verbose_name = '書(shū)'
verbose_name_plural = '書(shū)'
可以看到上述的Book模型中的owner關(guān)聯(lián)了User表挑豌,先按照django-import-export的官網(wǎng)所述的方法配置,看看會(huì)遇到什么問(wèn)題
- 配置admin.py
# admin.py
from import_export import resources
from import_export.admin import ImportExportModelAdmin
class BookResource(resources.ModelResource):
class Meta:
model = Book
class BookAdmin(ImportExportModelAdmin):
resource_class = BookResource
# 這里加幾個(gè)顯示字段
list_display = ['name', 'owner']
class UserResource(resources.ModelResource):
class Meta:
model = User
class UserAdmin(ImportExportModelAdmin):
resource_class = UserResource
# 這里加幾個(gè)顯示字段
list_display = ['username', 'age', 'gender', 'nickname']
admin.site.register(Book, BookAdmin)
admin.site.register(User, UserAdmin)
如下圖墩崩,右上角已經(jīng)有了導(dǎo)入導(dǎo)出按鈕氓英,django-import-export已經(jīng)加載成功
錄入兩條用戶數(shù)據(jù)和三條書(shū)籍信息,如下圖:
如果將書(shū)籍導(dǎo)出鹦筹,會(huì)得到如下效果铝阐,owner會(huì)顯示user表的id信息,并不是我們想要的結(jié)果:
導(dǎo)入會(huì)有同樣的問(wèn)題铐拐,導(dǎo)入時(shí)owner中的值必須是user中的id徘键,而不能是張三、李四遍蟋,所以我們需要對(duì)導(dǎo)入和導(dǎo)出做一些調(diào)整啊鸭,以實(shí)現(xiàn)我們的需求:
from django.contrib import admin
from .models import Book, User
from import_export import resources
from django.apps import apps
from import_export.admin import ImportExportModelAdmin
from django.db import models
import tablib
import collections
class BookResource(resources.ModelResource):
def __init__(self):
super(BookResource, self).__init__()
# 獲取tables應(yīng)用下Book模型中的所有字段,請(qǐng)根據(jù)自己的應(yīng)用將tables更改
field_list = apps.get_model('tables', 'Book')._meta.fields
self.vname_dict = {}
self.fkey = []
for i in field_list:
self.vname_dict[i.name] = i.verbose_name # 獲取所有字段的verbose_name并存放在字典
if(isinstance(i, models.ForeignKey)):
self.fkey.append(i.name) # 獲取所有ForeignKey字段的name存放在列表
def export(self, queryset=None, *args, **kwargs):
self.before_export(queryset, *args, **kwargs)
if queryset is None:
queryset = self.get_queryset()
headers = self.get_export_headers()
data = tablib.Dataset(headers=headers)
# 獲取所有外鍵名稱在headers中的位置
fk_index = {}
for fk in self.fkey:
fk_index[fk] = headers.index(fk)
iterable = queryset
for obj in iterable:
# 獲取將要導(dǎo)出的源數(shù)據(jù)匿值,這里export_resource返回的是列表赠制,便于更改。替換到外鍵的值
res = self.export_resource(obj)
"""
這里是關(guān)鍵挟憔,將owner的值到User中獲取對(duì)應(yīng)的對(duì)象钟些,并截取起可讀名稱username,
這里用的是get绊谭,所以在User的模型中username必須是unique
"""
res[fk_index['owner']] = User.objects.get(id=res[fk_index['owner']]).username
data.append(res)
self.after_export(queryset, data, *args, **kwargs)
return data
def before_import(self, dataset, using_transactions, dry_run, **kwargs):
dict = []
for row in dataset.dict:
tmp = collections.OrderedDict()
books = Book.objects.all()
for item in row:
if item == 'owner':
"""
這里是關(guān)鍵政恍,通過(guò)可讀名稱到User表中找到對(duì)應(yīng)id,并加到導(dǎo)入的數(shù)據(jù)中去
"""
tmp[item] = User.objects.get(username=row[item]).id
else:
tmp[item] = row[item]
"""
這里是關(guān)鍵达传,將數(shù)據(jù)進(jìn)行比對(duì)篙耗,如果數(shù)據(jù)相同迫筑,就把原先在Book表中的id加到需要導(dǎo)入的數(shù)據(jù)中去,
這樣就不會(huì)新增和原先一模一樣的數(shù)據(jù)宗弯,類(lèi)似于create_or_update方法
"""
for book in books:
if row['name'] == book.name:
tmp['id'] = book.id
dict.append(tmp)
dataset.dict = dict
return dataset
class Meta:
model = Book
class BookAdmin(ImportExportModelAdmin):
resource_class = BookResource
class BookAdmin(ImportExportModelAdmin):
resource_class = BookResource
list_display = ['name', 'owner']
class UserResource(resources.ModelResource):
class Meta:
model = User
class UserAdmin(ImportExportModelAdmin):
resource_class = UserResource
list_display = ['username', 'age', 'gender', 'nickname']
admin.site.register(Book, BookAdmin)
admin.site.register(User, UserAdmin)
請(qǐng)?zhí)貏e注意脯燃,關(guān)聯(lián)查詢的字段應(yīng)該在模型中設(shè)定unique=True,如果不唯一蒙保,在User表中可能會(huì)查到多條數(shù)據(jù)辕棚,這樣Book表是不知道要關(guān)聯(lián)那條記錄的
將書(shū)籍導(dǎo)出后的效果如下:
再來(lái)說(shuō)導(dǎo)入,導(dǎo)入的表如下表:
提交后的校驗(yàn)界面如下:
確認(rèn)導(dǎo)入后邓厕,數(shù)據(jù)如下: