react×django(django-rest-framework)での画像アップロード

# この記事の概要

reactとdjango-rest-frameworkを用いた画像アップロード機能について記載する。

# django×Reactの画像アップロード機能の実装方法

## Django(django-rest-framework)の作成【バックエンド】

### configの設定(画像の保存先)

```config/settings.py
import os #追加

MEDIA_ROOT = os.path.join(BASE_DIR, 'media') #追加
MEDIA_URL = '/media/' #追加
```

```config/urls.py
from django.conf import settings # 追加
from django.contrib.staticfiles.urls import static # 追加
from django.contrib.staticfiles.urls import staticfiles_urlpatterns # 追加

urlpatterns += staticfiles_urlpatterns() # 追加
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) # 追加
```

### modelsの作成

```api/models.py
class Food(models.Model):
    img   = models.ImageField(verbose_name='画像', upload_to='images/food/', null=True, blank=True)　# 追加
```

### serializersの作成

```api/serializers.py
# 特に変更なし
```

### viewsの作成

```api/views.py
# 特に変更なし
```

### urlsの作成

```api/urls.py
# 特に変更なし
```

## Reactの作成【フロントエンド】

```App.js
※特に変更なし
```

```FoodList.js
import { useState, useEffect } from 'react';
import axios from 'axios';

const FoodList = () => {
    const initState = {
        id: '',
        name: '',
        content: '',
    }

    // 一覧表示部分
    const [list, setList] = useState(initState);
    const [loading, setLoading] = useState(true);
    useEffect(() => {
        axios.get(`http://localhost:8000/api/food/`)
            .then((res) => {
                setList(res.data);
                setLoading(false);
            })
            .catch((err) => {
                throw new Error(err)
            })
            .finally(() => {

            })
    }, [])

    // 画像アップロード部分
    const [img, setImg] = useState(new Blob());
    const handleImageInputChange = (e) => {
        const files = e.target.files;
        console.log(files)
        if (!files) return;
        setImg(...files)
    }

    const handleUploadClick = () => {
        let data = new FormData();
        data.append('img', img);
        data.append('name', list[4].name)
        console.log(list[4].name)
        console.log(img)

        axios.put('http://localhost:8000/api/food/5/', data)
            .then((res) => console.log(res.data))
            .catch((err) => console.log(err))
    }

    return (
        <>
            <h1>foodlist</h1>
            {
                loading?
                <h1>...Loading</h1>
                :
                <>
                    {list.map(f => 
                            <div key={f.id}>
                                <p key={f.id}>{f.name}</p>
                                <img src={f.img} />
                            </div>
                        )}
                </>
                
            }
            <h1>foodcreate</h1>
            <input type='file' onChange={(e) => {handleImageInputChange(e)}}/>
            <button onClick={() => {handleUploadClick()}}>アップロード</button>
            <div
                style={{
                    position: "relative",
                    width: "40%",
                }}
            >
                <img
                    src={URL.createObjectURL(img)}
                    style={{
                        width: "100%"
                    }}
                />
            </div>
        </>
    )
}

export default FoodList;
```