Django數據導入導出神器django-import-export使用


前言

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 這個插件還有很多其他的功能,不過現階段已經滿足了我的工作需要,所以我也沒有再去深入,還有什么功能需要可以直接翻文檔吧。

目前我用到的還是以導出為主,導入的就是更新和新增這一塊,沒多少花樣,如果接下來遇到其他新的需求,我會再更新一篇文章來介紹更新這個插件的功能~

參考資料

歡迎交流

程序設計實驗室專注於互聯網熱門新技術探索與團隊敏捷開發實踐,在公眾號「程序設計實驗室」后台回復 linux、flutter、c#、netcore、android、kotlin、java、python 等可獲取相關技術文章和資料,同時有任何問題都可以在公眾號后台留言~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM