前言
Django以快速開發聞名,但是如果處理數據的導出導入還需要自己寫腳本,那就有違“Python之禪”了……
而且導數據通常需要不同的格式,Excel、csv、json等,每種格式的數據就要寫一個腳本太麻煩了,這時直接祭出django-import-export這個神器,官方一句話介紹:django-import-export is a Django application and library for importing and exporting data with included admin integration.
特點:
- support multiple formats (Excel, CSV, JSON, ... and everything else that tablib support)
- admin integration for importing
- preview import changes
- admin integration for exporting
- export data respecting admin filters
反正好用就完事了,下面我開始上使用介紹
首先安裝
pip install django-import-export
然后得添加到INSTALLED_APPS
里面
# settings.py
INSTALLED_APPS = (
...
'import_export',
)
編寫Resource
不得不說,這很Django
Resource的寫法與Model、Form類似,就是定義你要導入或者導出的數據格式。
這里借用一下官方的例子,首先上Model代碼
class Author(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Category(models.Model):
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)
author_email = models.EmailField('Author email', max_length=75, blank=True)
imported = models.BooleanField(default=False)
published = models.DateField('Published', 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
現在要導入數據到Book表,開始編寫我們的Resource,我是在app所在目錄下創建一個resource.py
來放Resource定義代碼
from import_export import resources
from core.models import Book
class BookResource(resources.ModelResource):
class Meta:
model = Book
這樣一個最簡單的Resource就定義好了,可以使用代碼進行數據導出,但現在我不想用,因為我要把導出功能放在DjangoAdmin后台里面
配置Admin
修改admin.py
,修改的地方就是把我們定義的Admin類原本繼承的admin.ModelAdmin
改成ImportExportModelAdmin
,代碼如下
from .models import Book
from import_export.admin import ImportExportModelAdmin
class BookAdmin(ImportExportModelAdmin):
resource_class = BookResource
admin.site.register(Book, BookAdmin)
這樣就可以在后台看到有導出和導入的按鈕了。
只想導出不想有導入功能咋辦,改成這樣:
from .models import Book
from django.contrib import admin
from import_export.admin import ExportMixin
class BookAdmin(ExportMixin, admin.ModelAdmin):
resource_class = BookResource
admin.site.register(Book, BookAdmin)
只導入不導出也行,把ExportMixin
換成ImportMixin
就行。
當然這些只是最簡單的用法,實際需求是比較復雜的,接下來我列舉幾個我用到的。
調整字段順序
要導入的數據(Excel、csv這些),可能字段順序和Model定義的字段順序不一樣,這時就得在Resource里手動調整一下
由於我自己寫的代碼涉及到公司業務,所以繼續借用官網的代碼例子:
class BookResource(resources.ModelResource):
class Meta:
model = Book
fields = ('id', 'name', 'author', 'price',)
export_order = ('id', 'price', 'author', 'name')
其中export_order
是導出的字段順序,fields
是指定哪些字段需要導入,導入的時候是根據數據文件的列名來導入的,所以Excel、csv或者json文件里面字段名就要和fields
里的或者是Model里的字段名一樣,才可以進行導入。
排除字段
顧名思義,就拿那個Book
的模型來說,Model定義里沒有指定主鍵,那Django會安排一個默認的主鍵字段id,但是我們導入數據的Excel里應該是沒有這個id的,這樣就沒法導入,於是我們得把這個id字段排除了,很簡單,在Meta
里這行代碼
exclude = ['id']
設置主鍵字段
也是顧名思義,假如我們數據庫本來就有很多書了,現在需要通過導入一個Excel來更新這批書的數據,那我就得把找一個字段來設置成主鍵字段,不然導入就變成新增了,跟前面提到的一樣,一般Excel里不會有數據庫主鍵id的,所以這里我選擇了書名(假設我們這是一個小書店,書名都不重復的)
代碼:
import_id_fields = ['name']
自定義列名
按照前文配置導出來的Excel,列名全是字段名,也就是英文的,但我想中文列名啊,也可以,就是需要花一點代碼(這里就不再借用官網代碼了,我自己手打)
from import_export.fields import Field
class BookResource(resources.ModelResource):
id = Field(attribute='id', column_name='編號')
name = Field(attribute='name', column_name='書籍名稱')
class Meta:
model = Book
export_order = ('id', 'name', 'author', 'price',)
這樣就實現了,so easy。其中Field
里的attribute
是指這個字段對應Model里的屬性也就是字段名,column_name
顧名思義就是列名。
然后可能有同學要問,Model里已經給每個字段都設置了verbose_name
了,這里還要在column_name
里再寫一遍是不是重復了?
別急,也很簡單,既然有verbose_name
,那直接拿來用就完事啦~
name = Field(attribute='name', column_name=Book.name.field.verbose_name)
這就完事美滋滋啦~
加入自定義的列
最后一個,如果想在導出的數據中加入Model里不存在的字段,行不?
那肯定行啊,也很簡單,直接代碼:
from import_export.fields import Field
class BookResource(resources.ModelResource):
id = Field(attribute='id', column_name='編號')
name = Field(attribute='name', column_name='書籍名稱')
new_field = Field(column_name='一個新的字段')
class Meta:
model = Book
export_order = ('id', 'name', 'author', 'price', 'new_field')
@staticmethod
def dehydrate_new_field(instance: Book):
return '新字段內容'
可以看到就是先在export_order
里添加這個字段,然后再加這行new_field = Field(column_name='一個新的字段')
,然后下面加一個類方法來實現生成這個字段的值,這個方法是以dehydrate_字段名
這樣的格式來命名的,具體可以根據實際來寫。
總結
django-import-export 這個插件還有很多其他的功能,不過現階段已經滿足了我的工作需要,所以我也沒有再去深入,還有什么功能需要可以直接翻文檔吧。
目前我用到的還是以導出為主,導入的就是更新和新增這一塊,沒多少花樣,如果接下來遇到其他新的需求,我會再更新一篇文章來介紹更新這個插件的功能~
參考資料
- 項目主頁:https://github.com/django-import-export/django-import-export
- 官方文檔:https://django-import-export.readthedocs.io/en/latest/installation.html
歡迎交流
程序設計實驗室專注於互聯網熱門新技術探索與團隊敏捷開發實踐,在公眾號「程序設計實驗室」后台回復 linux、flutter、c#、netcore、android、kotlin、java、python 等可獲取相關技術文章和資料,同時有任何問題都可以在公眾號后台留言~