javascriptで画像アップロード
mpaのdjnagoで画像をアップロードするにはフロントエンドではhtmlにinputタグ(type="file")をセットして、何らかのボタンを押してpostメソッドで送信し、views.pyにてrequest.POSTのような形で画像データを取り出してやれば画像の取り扱いはできた。
しかしながらSPAにおいてはjavascriptでいろいろ書いてやる必要があり、それの調査に時間がかかってしまったので記録に残しておく。
条件
- vuejsをもちいる。vueファイルにはinputタグを書かないで、ファイルアップロード等のボタンのみ表示されている状態で実装する。
概要
ポイントは4点あった。
- vueファイルに存在しないinputタグをどう対処するか?例えばvueファイルに直接書き込むか、tsファイルでDOM操作としてinputタグを作成するか。
- inputタグををクリックすると新たにウィンドウが表示されることを知っていたか。
- 新たに表示されたウィンドウに画像を選択した時どうやってそのデータを送信するか。
- 画像データ等はFormDataクラスを利用することを知っていたか。
2に関しては気づかなかったが、インプットタグをクリックするだけで画像選択するウィンドウが新たに生成される。3に関してはイベントリスナーに設置するのはcloseではなく"change"だと言うことに気づかなくてとても困った。
参考コード
myButton.vue
<template> <div> <button id="myButton">MyButton.vueのボタン</button> </div> </template> <script> import MyButton from './MyButton.ts' export default MyButton </script>
myButton.ts
import { Component, Vue} from 'vue-property-decorator'; import * as axios from 'axios'; // axios // https://www.digitalocean.com/community/tutorials/how-to-handle-file-uploads-in-vue-2 @Component({}) export default class MyButton extends Vue{ private mounted(): void{ const myButton = window.document.getElementById("myButton"); myButton?.addEventListener('click', this.openWindowButton); } private openWindowButton(): void{ console.log("Hello Vue From Button!!"); const inputImage = window.document.createElement('input'); inputImage.type = 'file'; inputImage.accept = "image/*"; inputImage.setAttribute("name", "file"); inputImage.multiple = true; //複数画像をアップロードしたい時にはコメントアウトを外して編集していく。。。 inputImage.addEventListener('change', this.uploadImage); inputImage.click(); } private async uploadImage(event: Event): Promise<void>{ const url = 'http://localhost:8000/myapp/image/' // Fileデータを送信する場合には、data = {'file': imageFile } みたいなことはできない // 必ずFormDataクラスを利用してデータを送信する。 const params = new FormData(); const imageFile = event.target.files[0]; params.append('file', imageFile); params.append('name', imageFile.name); const response = await axios.post(url, params); } }