2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Nuxt&Django REST FrameworkでCRUD POST編

Last updated at Posted at 2020-05-15

概要

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

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

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

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

ソースコードはこちらにあるのでわからないところは適宜見てください。

また、Twitterかこの記事のコメント欄でわからないところを聞いていただけると答えられます。

前回
Nuxt&Django REST FrameworkでCRUD GET編②

更新箇所

バックエンド

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

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

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

views.py
......
# 追加
class ItemCreateView(generics.CreateAPIView):
    serializer_class = ItemSerializer
    queryset = Item.objects.all()
urls.py
......
# 追加
path('items/add',ItemCreateView.as_view()),

さて、こうすることで

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

スクリーンショット 2020-05-14 19.18.35.png

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

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

フロントエンド

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

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

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

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

スクリーンショット 2020-05-15 8.58.22.png

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

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

個人的におすすめなのは、
[axios] axios の導入と簡単な使い方

こちらです。

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

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

書きました
Nuxt&Django REST FrameworkでCRUD PUT,DELETE編

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?