django-import-export關(guān)聯(lián)外鍵在后臺(tái)管理中導(dǎo)入導(dǎo)出的辦法

本文介紹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ū)籍信息,如下圖:

image.png

image.png

如果將書(shū)籍導(dǎo)出鹦筹,會(huì)得到如下效果铝阐,owner會(huì)顯示user表的id信息,并不是我們想要的結(jié)果:


image.png

導(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)出后的效果如下:


image.png

再來(lái)說(shuō)導(dǎo)入,導(dǎo)入的表如下表:


image.png

提交后的校驗(yàn)界面如下:


image.png

確認(rèn)導(dǎo)入后邓厕,數(shù)據(jù)如下:


image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末逝嚎,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子详恼,更是在濱河造成了極大的恐慌补君,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件昧互,死亡現(xiàn)場(chǎng)離奇詭異挽铁,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)硅堆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)屿储,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)贿讹,“玉大人渐逃,你說(shuō)我怎么就攤上這事∶窆樱” “怎么了茄菊?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)赊堪。 經(jīng)常有香客問(wèn)我面殖,道長(zhǎng),這世上最難降的妖魔是什么哭廉? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任脊僚,我火速辦了婚禮,結(jié)果婚禮上遵绰,老公的妹妹穿的比我還像新娘辽幌。我一直安慰自己,他們只是感情好椿访,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布乌企。 她就那樣靜靜地躺著,像睡著了一般成玫。 火紅的嫁衣襯著肌膚如雪加酵。 梳的紋絲不亂的頭發(fā)上拳喻,一...
    開(kāi)封第一講書(shū)人閱讀 52,736評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音猪腕,去河邊找鬼冗澈。 笑死,一個(gè)胖子當(dāng)著我的面吹牛码撰,可吹牛的內(nèi)容都是我干的渗柿。 我是一名探鬼主播,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼脖岛,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼朵栖!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起柴梆,我...
    開(kāi)封第一講書(shū)人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤陨溅,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后绍在,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體门扇,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年偿渡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了臼寄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡溜宽,死狀恐怖吉拳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情适揉,我是刑警寧澤留攒,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站嫉嘀,受9級(jí)特大地震影響炼邀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜剪侮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一拭宁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瓣俯,春花似錦杰标、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至推掸,卻和暖如春桶蝎,著一層夾襖步出監(jiān)牢的瞬間驻仅,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工登渣, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留噪服,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓胜茧,卻偏偏與公主長(zhǎng)得像粘优,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子呻顽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容