Nuxt&Django REST FrameworkでCRUD POST編

# 概要

フロント:Nuxt
バックエンド:Django REST Framework（以下DRF）
で新しいプロジェクトなどを立ち上げた時に設定などをいちいち調べるのがめんどくさくなったため、まとめておきます。

ただ、設定ファイルだけを書くのでは個人的に記事として物足りない。

なので、ついでに基本的な操作であるAPIを叩いてCRUDを行い、会員登録を実装するところまで書く予定です。
なお、今回はDBはSQLiteを使います。PostgreSQLやMySQLなど他のRDBが使いたい場合はDRF側のDBの設定を書きかえるだけなので、そちらの設定は各自よろしくお願いいたします。

ひとまずこの記事では、NuxtからDRFで作ったAPIを叩いてデータベースにフォームに入力した内容をPOSTするところまでです。

ソースコードは[こちら](https://github.com/Kuehar/nuxt-django)にあるのでわからないところは適宜見てください。

また、[Twitter](https://twitter.com/kueharx)かこの記事のコメント欄でわからないところを聞いていただけると答えられます。

前回
[Nuxt&Django REST FrameworkでCRUD GET編②](https://qiita.com/KueharX/items/48d44db339e4a2fbaa71)

# 更新箇所
## バックエンド

前回までのDRF必要なview、そしてurlを書いていないため、POSTは出来ません。


なぜそうしたかというと、情報を受け取る処理、GETしか出来ないようにするためです。
わざわざそうした理由としては、実用的に使えるアプリを考えた際に、分割した方が管理をしやすかったり、権限の設定が簡単になるからです。
例えば、昨今のWebアプリだと会員登録をしなくても情報をGETすることはできるが、会員登録をしないとPOSTを出来ないようにするとか、そういった権限の切り分けをしていることがほとんどですし、何より怖い人が世の中にはいるのでしっかりと悪用されないようにしておくことが大事です。

なので今回はまずviewとurlに追記するところから始まります。

```Python:views.py
......
# 追加
class ItemCreateView(generics.CreateAPIView):
    serializer_class = ItemSerializer
    queryset = Item.objects.all()
```


```Python:urls.py
......
# 追加
path('items/add',ItemCreateView.as_view()),
```

さて、こうすることで

http://localhost:8000/api/items/add

にアクセスすると以下のようにPOSTができるようになりました。

![スクリーンショット 2020-05-14 19.18.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412789/c48373f2-fed2-2cb2-f794-4b7ab628be74.png)

なんとDRF側の追記はこれだけです！
素晴らしいですね。

ではフロントエンドに移りましょう。

## フロントエンド

こちらではフォームを作り、POSTするためのページを追加する必要があります。

なので簡単なフォームを書いておきました。
また、ロジックに関してはaxiosの基本的な文法に沿って書きました。

```JavaScript:addItem.vue
<template>
<v-card
    light
    :loading="isUpdating"
  >
    <div id="app">
    <v-app id="inspire">
    <v-form @submit.prevent="submitItem">
      <v-container>
        <v-row>
          <v-col
            cols="12"
            md="4"
          >
            <v-text-field
              v-model="item.name"
              label="商品名"
              required
            ></v-text-field>
          </v-col>
  
          <v-col
            cols="12"
            md="4"
          >
            <v-text-field
              v-model="item.category"
              :counter="10"
              label="カテゴリー"
              required
            ></v-text-field>
          </v-col>
  
          <v-col
            cols="12"
            md="4"
          >
            <v-text-field
              v-model="item.price"
              label="値段"
              required
            ></v-text-field>
          </v-col>
          
          <v-col
            cols="12"
            md="4"
          >
            <v-text-field
              v-model="item.description"
              label="商品説明"
              required
            ></v-text-field>
          </v-col>
          <v-col
            cols="12"
            md="4"
          >
           <v-file-input
           v-model="item.image"
           label="商品画像"
           filled
           prepend-icon="mdi-camera"
           ></v-file-input>
          </v-col>
          <v-card-actions>
      <v-spacer />
      <v-btn
        class="btn-primary"
        :loading="isUpdating"
        color="primary"
        depressed
        @click="isUpdating = true"
        type="submit"
      >
        <v-icon left>
          mdi-post
        </v-icon>
        商品を追加
      </v-btn>
    </v-card-actions>
        </v-row>
      </v-container>
    </v-form>
  </v-app>
</div>
</v-card>
</template>

<script>
export default {
  data () {
    return {
      item: {
        name: '',
        category: '',
        image: '',
        price: '',
        description: '',
      },
      preview: '',
      autoUpdate: true,
      isUpdating: false,
      title: '商品追加',
  }
  },
  watch: {
    isUpdating (val) {
      if (val) {
        setTimeout(() => (this.isUpdating = false), 3000)
      }
    }
  },
  methods: {
    createImage (file) {
      const reader = new FileReader()
      const vm = this
      reader.onload = (e) => {
        vm.preview = e.target.result
      }
      reader.readAsDataURL(file)
    },
    async submitItem () {
      const editeditem = this.item
       //if (editeditem.image.includes('http://)') !== -1) {
        //delete editeditem.image
      //}
      const config = {
        headers: { 'content-type': 'multipart/form-data' }
      }
      const formData = new FormData()
      for (const data in editeditem) {
        formData.append(data, editeditem[data])
      }
      try {
        const response = await this.$axios.$post('/items/add', formData, config)　// eslint-disable-line
        this.$router.push('/items')
      } catch (e) {
        console.log(e)
      }
    }
  }
}
</script>
```

![スクリーンショット 2020-05-15 8.56.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412789/6b027b3c-7dca-dbba-4866-7b8234135457.png)

こんな感じのフォームが出てきます。
そしてこれらの欄を入力して送信すると・・・

![スクリーンショット 2020-05-15 8.58.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412789/8f38c1b9-ef1a-9e91-091a-b5a7ac79ab66.png)

無事に追加されていますね。

書いていて思ったのですが、習って書けば動いてくれるので個人的にはaxiosについてのドキュメントをしっかり読み込むことが大事かと思います。

個人的におすすめなのは、
[[axios] axios の導入と簡単な使い方
](https://qiita.com/ksh-fthr/items/2daaaf3a15c4c11956e9)
こちらです。

こちらの方の記事はとてもわかりやすく書かれているので一読の価値ありです。

~~CRUDと会員登録のマニュアルが出来れば非常にスムーズに開発が行えると思うので、次回は情報を修正する方法と、削除、つまりPUTとDELETEについて書きます。~~

書きました
[Nuxt&Django REST FrameworkでCRUD PUT,DELETE編](https://qiita.com/KueharX/items/1c12e5f850cd8eeb875e)