【個人開発】Webサービス：「人生でやりたい100のこと」の作成

## 【個人開発】Webサービス：「人生でやりたい100のこと」を作成しました(Vue.js + Python/Django)

## はじめに（自己紹介）
- IT業界にずっと身を置いているものの、企業向けのシステムを扱っているということもあり、WEBサービスを自分で最初から最後まで作成したことはありませんでした。（30代後半のアラフォーです）
- Qiitaでこちら（[「中年の危機」ど真ん中のオッサンがWEBサービス作ってみた](https://qiita.com/hiroz31/items/d7f2f9b7d02f9be1ca92)）の投稿を拝見して、前々から思っていた「このままでよいのか」と「何番煎じでもよいし、ありふれたものでもよいので、なにかを作りたい（作りきってみたい）」がつながり、作成に取りかかることにしました。

## 何をつくろうと思ったか

- **「人生でやりたいことリスト100」** というのをgoogle検索すると、検索結果は色々でてきますが、皆さん自分のブログで書いています。ブログに書くのももちろんありだと思いますが、ブログを持っていないとか、もしくは、メンテナンスとか考慮して、自分で簡単に管理することができるとよいのではないか、と思いました。
- そこで、人生でやりたい100のこと、というタイトルでWebサービスを作成しようと思いました。

※余談：仕事をしていると、ついつい「できること」（Can）で考えがちですし、そうすべきこともたくさんあります。ただ、人生という視点で考えれば、「やりたいこと」（Want）を常に頭に置いておきたいと思っています。
【参考本】[人生の100のリスト(Amazon)](https://www.amazon.co.jp/%E4%BA%BA%E7%94%9F%E3%81%AE100%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88-%E3%83%AD%E3%83%90%E3%83%BC%E3%83%88%E3%83%BB%E3%83%8F%E3%83%AA%E3%82%B9/dp/4062122707)
![101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167772/01e3a0cc-3f32-5901-27b3-3170254b1912.png)

## こだわったこと

唯一のこだわりは、**SPA(Single Page Application)** として開発すること。登録や変更などで画面遷移しているのはすごく煩わしいので、自分のやりたいこと(wants)を1画面にて簡単に追加・変更等の管理ができるようにしたい。

## 機能・できること

簡単に言ってしまうと、Todoリストの拡張版。ただ、チェックボックスがあるような、Todoリストではなく、下記のような機能をつける。

 - 100のことなので、数字つきのリスト
 - 簡単(ドラック＆ドロップ)に上へ下へ移動
 - 達成日 / 達成時コメント が入力できる
 - 達成率がグラフなどで見える
 - 自分のリストのダウンロード
 - やりたいこと(want)単位で、公開/非公開設定ができる(見せたくない場合は非公開にする) 
 - 他の人のWantsリストも参照できるので(公開のみ)、共感できるものは「いいね」ができる

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167772/8f2c2605-44f3-c2aa-47ef-95ca43524ed6.png)

## 使用技術
＜フロントエンド＞
 ・Vue.js / Vuex

＜バックエンド＞
 ・Python3.6 / Django2.0 / REST Framework
 ・MySQL

## 公開サイト

勉強のため、下記の2つで構築・公開

 ①レンタルサーバー
  フロントとバックを違う環境で構築し、APIを呼ぶ
 　- フロント：レンタルサーバー(Vue.js)
 　- バックエンド：Heroku(Python + Django REST Framework + MySQL)
　　※Herokuは一定時間アクセスがないとスリープになるので、少し待つ場合あり
    **→Herokuの無料サービス終了に伴い工事中**

 ②~~AWS 　※ただしhttps非対応~~ (更新停止)
 
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167772/0781bdcd-67e5-9998-e6ba-7439b7a18159.png)


## 実施した勉強
Vue.jsも、Django REST FrameworkによるAPI構築もはじめてやりましたので、勉強のために下記を実施。

- Vue.js / APIの呼出しについて
 - Qiita APIを呼び出し、キーワードによるリアルタイム検索をやってみる　→ [Heroku](https://test-vue-qittaapi.herokuapp.com/index.html)

- Python Djangoについて
 - TodoリストでCRUDを学ぶ　→ [Heroku](https://djangoheroku-todoapp.herokuapp.com/)

- Django REST Framework / Vue.js関連の参考URL
 - 皆様のQiita投稿を参考にさせていただき、同じことをしてみる。
 
【参考URL】
・ [Python Django チュートリアルまとめ](https://qiita.com/maisuto/items/17653f344d1f64afa019)
・ [Django REST Frameworkを使って爆速でAPIを実装する](https://qiita.com/kimihiro_n/items/86e0a9e619720e57ecd8)
・ [Django + Vue.js な開発環境を作ろう](https://qiita.com/kawaMk4/items/89b18c608dc7dd2b946b)
・ [Django REST framework with Vue.js](https://qiita.com/yuuki_1204_/items/d892aa0ba935a1ac7594)
・ [Django REST Frameworkでユーザ認証周りのAPIを作る](https://qiita.com/xKxAxKx/items/60e8fb93d6bbeebcf065)
・ [Django REST framework カスタマイズ方法 - チュートリアルの補足](https://qiita.com/okoppe8/items/c58bb3faaf26c9e2f27f)
・ [サーバーサイドJavaエンジニアがVue.jsの基本を学習したときのメモ](https://qiita.com/rubytomato@github/items/056199b994bb94efb8c0)

## 実装のポイント
### Vue.draggable：ドラッグアンドドロップで自分のWantsを移動させる

Vue.jsでドラッグ＆ドロップするなら「Vue.Draggable」がおすすめらしい。


![3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167772/97e087f8-1b5f-24e1-9ee0-2c3ef7d412a1.gif)

【インストール】　`npm i -S vuedraggable`

【参照URL】
・https://github.com/SortableJS/Vue.Draggable
・https://www.kabanoki.net/1712
・https://qiita.com/kimuray/items/d728fa1635aeacad359f
・http://sagatto.com/20171031_vuejs_sortable

~~~wantslist.vue
<draggable v-model="wants" :element="'tbody'" :options="{handle:'.handle', animation:150, delay:150}" v-on:end="onEnd">

 // ドラック＆ドロップ対象のテーブルを囲む

</draggable>

<script>
import draggable from 'vuedraggable'

export default {
  name: 'WantsIndex',
  components: {
    Chart,
    draggable
  },
  data () {
    //省略
  },
  computed: {
    //省略
  },
  created () {
    //省略
  },
  methods: {
    // Vue.Draggableの移動が終わったら処理を実施
    onEnd () {
      var num = 0
      // wantslistをループして、更新データを作成する
      for (var i = 0; i < this.wants.length; i++) {
        num += 1
        var addnum = {
          id: this.wants[i].id,
          displayOrder: num
        }
        this.upwants.push(addnum)
      }
      // 更新処理を実施
      axios.patch(`${process.env.API_ENDPOINT}wantsupdate/`, {
        upwants: this.upwants
      })
    },
  //省略
  }
}
</script>
~~~

### Chart.js：未着手・実施中・達成のステータスを円グラフ化

vue-chartjsを使用すると、簡単にグラフが作成できる。

- インストール
　`npm install vue-chartjs chart.js --save`

- 参照URL
  https://vue-chartjs.org/guide/#introduction
  http://www.sky-limit-future.com/entry/vue_use_chartjs

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167772/a6c250af-f352-59ea-3d6d-90626a2037ee.png)

~~~wantslist.vue
<template>
  <div class="container">
    <br>
    <div class="card-group">
　　　
　　　// 省略
      
      <!-- カード3: 100wantsのドーナツチャート -->
      <div class="card">
        <Chart :chart-data="datacollection" :height="200"></Chart>
      </div>
    </div>    
    <br>
    
    // 省略
    
  </div>
</template>

<script>
import Chart from './Chart.js'

export default {
  name: 'WantsIndex',
  components: {
    Chart,
    draggable
  },
  data () {
    //省略
  },
  computed: {
    //省略
  },
  created () {
    //省略
  },
  methods: {
    fetchData () {
         // 省略
    },
    // グラフデータの取得
    getChartdata () {
      this.datacollection = {
        labels: ['未着手', '実施中', '達成'],
        datasets: [
          {
            data: [this.getStatus('nostart'), this.getStatus('doing'), this.getStatus('done')],
            backgroundColor: ['lightgreen', 'lightblue', 'lightgray']
          }
        ]
      }
    },
  }
}
</script>
~~~

### Vue-Gravatar：グローバルに認識されるアバター

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167772/d613cea1-f775-49f4-58ca-0862cde0c4fd.png)

アバターアイコンは、ユーザに登録してもらいDBにて保持する形ではなく、グローバルに認識されるアバターを登録してもらい、それを表示されるようにする（e-mailアドレスでの紐付け）

v-gravatar と指定して、emailアドレスをv-bindする。


【参照URL】
https://ja.gravatar.com
https://www.npmjs.com/package/vue-gravatar


~~~wantslist.vue
<!-- カード1: ユーザの情報(e-mailアバター、ニックネーム、likes一覧、いいね数、twitterアイコンを表示) -->
  <div v-for="user in users" v-bind:key="user.id" class="card">
    <div class="card-body">
      <span><v-gravatar v-bind:email="user.email" :size="60" class="w-30 rounded" default-img="mm"/>
        <strong>{{ user.nickname }}</strong>
      </span>
      <br><br>
      <small><router-link to="/userlikelist"><button class="btn-sm btn-warning">Likes一覧</button></router-link></small>
      <small><button v-on:click="download()" class="btn-sm btn-success">List Download</button></small>
    </div>
  </div>
~~~

## まとめ
- 初学者としては、言語の基礎を学んだあとは、チュートリアルとして、TodoList・掲示板・Twitterのような投稿システムなどを作成してみる、という流れが多いと思いますが、その次のステップとして、それらの機能を拡張していくのが、とてもやりやすいのではないか、と作りながら思いました。

- Django REST Framework API の便利さ、Vue.jsのおもしろさ・難しさ、などいろいろ感じることができました。

## 感想・その他
- ログイン機能実装、DB連携、CRUDなどもはじめて実施しましたので、とても苦労しましたが、徐々に機能がついていき、できることが増えていくときなどとても充実感がありました。

- 今回使用した、Django REST Framework API、Vue.jsなどはじめて触りました。当然、いろいろなところでつまりながらです。仕事以外の時間はすべてこれに費やした感じがします。（約3ヶ月弱くらい）

- やっているときは、Qiitaをめちゃくちゃ参考にさせていただきました。結果をQiitaに投稿することが１つの大きな目標になり、その目標も達成することができました。（本投稿）