Django(drf)配合 Vue Element 實現(xiàn)文件上傳下載功能

后臺代碼

Models

編輯 models.py 代碼,通過 FileField 字段記錄文件信息:

from django.db import models


class FilesModel(models.Model):
    file = models.FileField(upload_to='uploads/')

    class Meta:
        db_table = 'files_storage'
        ordering = ['-id']
Serializer

這里使用 Django REST framework 實現(xiàn)后端 REST API,需要創(chuàng)建序列化器 serializers.py,內(nèi)容如下:

from rest_framework import serializers
# files 是 app 的名字
from files import models


class FilesSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.FilesModel
        fields = '__all__'
Views

編輯 views.py 代碼,內(nèi)容如下:

from rest_framework.viewsets import ModelViewSet
from files import models, serializers


class FileViewSet(ModelViewSet):
    queryset = models.FilesModel.objects.all()
    serializer_class = serializers.FilesSerializer
Urls

在 files 路徑下新建 urls.py 文件,填寫路由配置:

from django.urls import include, path
from rest_framework import routers
from files import views

router = routers.DefaultRouter()
router.register(r'files', views.FileViewSet)

urlpatterns = [
    path('', include(router.urls))
]

在項目總配置路徑下(settings.py 所在的路徑)編輯根路由配置文件 urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('storage/', include('files.urls'))
]
測試后端 API

運行后臺服務(wù) python manage.py runserver 0.0.0.0:8000,訪問 http://xx.xx.xx.xx:8000/storage/files/,界面如下:

Django REST framework

測試上傳文件,效果如下:


上傳成功

前端代碼(手動上傳)

借助 Element UI 的 upload 組件,Vue 代碼(index.vue)如下:

<template>
  <div>
    <el-upload
      ref="upload"
      drag
      action="http://xx.xx.xx.xx:8000/storage/files/"
      :auto-upload="false"
      :on-success="onSuccess"
    >
      <i class="el-icon-upload" />
      <div class="el-upload__text">將文件拖到此處,或<em>點擊上傳</em></div>
    </el-upload>
    <el-button style="margin-left: 10px;" size="small" type="success" @click="submitUpload">上傳到服務(wù)器</el-button>
  </div>
</template>

<script>

export default {
  name: 'UploadDemo',
  methods: {
    submitUpload() {
      this.$refs.upload.submit()
    },
    onSuccess() {
      this.$message.success('上傳成功')
    }
  }
}
</script>

其中 el-upload 組件的 action 屬性用于指定后臺 API 的 URI;
:auto-upload 屬性用于設(shè)置是否自動上傳(這里設(shè)置為 false,手動觸發(fā)上傳動作);
:on-success 屬性用于指定上傳成功后觸發(fā)的方法。

submitUpload() 中的 this.$refs.upload.submit() 方法觸發(fā)文件上傳動作。

界面如下:


上傳界面

測試文件上傳:


上傳成功

后臺數(shù)據(jù)如下:

[
    {
        "file": "http://172.20.23.34:8000/storage/files/uploads/template.html",
        "id": 18
    },
    {
        "file": "http://172.20.23.34:8000/storage/files/uploads/20171215091830_55126_hSnPtZR.png",
        "id": 17
    }
]

文件上傳的同時添加其他數(shù)據(jù)

修改數(shù)據(jù)庫模型

編輯后端 models.py 文件,添加其他字段:

from django.db import models


class FilesModel(models.Model):
    name = models.CharField(max_length=20, default='')
    file = models.FileField(upload_to='uploads/')

    class Meta:
        db_table = 'files_storage'
        ordering = ['-id']

數(shù)據(jù)庫遷移后,重啟后臺 Web 服務(wù)。

后臺數(shù)據(jù)如下:

[
    {
        "file": "http://172.20.23.34:8000/storage/files/uploads/template.html",
        "id": 18,
        "name": ""
    },
    {
        "file": "http://172.20.23.34:8000/storage/files/uploads/20171215091830_55126_hSnPtZR.png",
        "id": 17,
        "name": ""
    }
]
修改前端代碼

添加其他數(shù)據(jù)的輸入界面,同時將附加數(shù)據(jù)綁定到 el-upload 組件中:

<template>
  <div>
    <el-label>名稱</el-label>
    <el-input v-model="fileData.name" style="width: 20%" />
    <el-upload
      ref="upload"
      drag
      class="upload-demo"
      action="http://xx.xx.xx.xx:8000/storage/files/"
      :data="fileData"
      :auto-upload="false"
      :on-success="onSuccess"
      style="padding: 30px"
    >
      <i class="el-icon-upload" />
      <div class="el-upload__text">將文件拖到此處,或<em>點擊上傳</em></div>
    </el-upload>
    <el-button style="margin-left: 10px;" size="small" type="success" @click="submitUpload">上傳到服務(wù)器</el-button>
  </div>
</template>

<script>

export default {
  name: 'UploadDemo',
  data() {
    return {
      fileData: {
        name: ''
      }
    }
  },
  methods: {
    submitUpload() {
      this.$refs.upload.submit()
    },
    onSuccess() {
      this.$message.success('上傳成功')
    }
  }
}
</script>

其中 el-upload 組件的 :data 屬性用于指定文件上傳時附加的數(shù)據(jù)(類型為 JavaScript 對象)。

文件上傳測試:


文件上傳(帶數(shù)據(jù))

上傳完成,后臺數(shù)據(jù)如下:

[
    {
        "file": "http://172.20.23.34:8000/storage/files/uploads/AnyDesk.exe",
        "id": 19,
        "name": "測試文件"
    },
    {
        "file": "http://172.20.23.34:8000/storage/files/uploads/template.html",
        "id": 18,
        "name": ""
    },
    {
        "file": "http://172.20.23.34:8000/storage/files/uploads/20171215091830_55126_hSnPtZR.png",
        "id": 17,
        "name": ""
    }
]

文件下載

修改后臺視圖代碼(views.py),添加文件下載的 API 響應(yīng)邏輯:

from rest_framework.viewsets import ModelViewSet
from files import models, serializers
from rest_framework.decorators import action
from django.http import FileResponse


class FileViewSet(ModelViewSet):
    queryset = models.FilesModel.objects.all()
    serializer_class = serializers.FilesSerializer

    @action(methods=['get', 'post'], detail=True)
    def download(self, request, pk=None, *args, **kwargs):
        file_obj = self.get_object()
        response = FileResponse(open(file_obj.file.path, 'rb'))
        return response

此時訪問 http://xx.xx.xx.xx:8000/storage/files/[id]/download/ 鏈接,即可直接下載上傳到服務(wù)器上的文件。

下載文件

$ curl -o anydesk.exe 172.20.23.34:8000/storage/files/19/download/
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 3584k  100 3584k    0     0   102M      0 --:--:-- --:--:-- --:--:--  102M

參考資料

Element UI 官方文檔
Django 官方文檔

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,716評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,746評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,991評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,706評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,036評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,203評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,725評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,451評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,677評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,857評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,266評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,606評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,407評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,643評論 2 380

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