【Vue.js入門】Vue CLIとDjango REST frameworkで作ってHerokuへデプロイしました!

この記事は約36分で読めます。
広告

バックエンドをDjango REST framework
フロントエンドをVue3 CLIで作り
ビルドしてできた静的ファイル(index.html、*js、*.css)をDjangoのtemplatesとstaticで使えるように修正。
Herokuへデプロイしました。完成品 (祝日登録削除機能は下の記事で追加しました。)

Vueに関心がある方は、こちらの記事が参考になると思います。


私のブログ記事は無料WEB開発環境PaizaCloudの使用前提で書いてます。(パソコンのストレージ不足のため)しかしパソコンで開発環境を作っている場合にも参考になると思います。

元になるアプリはこちらのサイトを参考にさせていただきました。
【次の祝日はいつですか】Vue CLIとDjango REST frameworkでREST APIを実装する
直近の祝日ではなく登録した順で答えが出るようです。

作業するにあたりハマった点をあげます。

  • ネットでVue2とVue3の情報があるので調べるときは確認する。今回はVue3。
  • ログインが必要なAPIからjsonを取得するときはcredentialsの設定が必要。セッション情報(クッキー)を送る必要があるため。今回PaizaCloud(ログイン必要)でDjangoによるAPIを作っているので該当した(開発中のみ本番では危険な設定)。最終的にはindex.htmlをtemplatesに入れたので不要。
  • 上記は検証ツールで確認するとCorsエラーが発生してるように見える。
  • CORS対策はDjango側だけでできたフロント側は何もしなかった。プリフライトなしのGetしか使用していためかも。POSTではプリフライト飛んでしまいうまくいかない。調査中
  • ビルドしてdist/index.htmlを開いても<router-view />部分が表示されない。(よくある原因の絶対パスと相対パスの問題以外にも問題がある。ここは開発中発生で本番ではでない。開発中は力技で表示させたので未解決)

このブログをコピペして実行したときSyntaxError: invalid character in identifierが発生する場合は、エラー箇所が全角スペースになっているので半角スペースに書き直してください。

広告

開発環境はPaizaCloudを使った。

開発環境はPaizaCloud を使用します。無料インストールなしでNode.jsが使えます。エディタだけ使用することも可能です。その場合、作ったhtmlファイルの動作確認をしたいときは右クリックで「プラウザで開く」をクリックすればいいだけです。なのでVSCodeなどのエディタの代わりとしても使用できます。

バックエンド(Django)側作成

新規サーバー作成→サーバー名入力
Web開発:はNode.jsとDjango選択
データベース:はPostgreSQLを選択
新規サーバー作成
まずDjangoのプロジェクトを作成します。

PaizaCloudの左にあるターミナルアイコンをクリックするとターミナルが立ち上がります。
django-admin startproject project_cal でEnter、プロジェクトが作成されます。(以下Enterは省略)
cd project_cal ディレクトリが移動されます
python manage.py startapp app_cal アプリ作成

settings.pyでPaizaCloudの場合、以下変更も必要です。
ALLOWED_HOSTS = []
→ALLOWED_HOSTS = ['*']

LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'


INSTALLED_APPS = [
・・・
    'django.contrib.staticfiles',
  'rest_framework', # 追加
    'corsheaders',#追加
    'app_cal', #追加
]
MIDDLEWARE = [
・・・・
'corsheaders.middleware.CorsMiddleware',#追加
]
CORS_ORIGIN_ALLOW_ALL =True #追加 どこからでも受け入れるので危険な設定
# CORS_ORIGIN_WHITELIST = [ #個別に許可する場合はこっちを使う
#     'http://***.jp', 
# ]
# レスポンスを公開する
CORS_ALLOW_CREDENTIALS = True #追加
にして保存
ターミナルで
pip install djangorestframework
pip install django-cors-headers

python manage.py runserverで動作確認。
CTRL+Cで停止。

モデルのところのmodels.pyから参考サイトのコードをコピペしてください。
ディレクトリ構成は、この記事とはちがいます。
アプリの名前を変えているので以下のように変更が必要です。

project_call/urls.py
path('calendar/', include('app.urls')),   # 追加
→path('calendar/', include('app_cal.urls')),# 追加

参考サイトのvcalendar/urls.pyはapp_cal/urls.pyです。
データベース構築
modeles.py修正後
python manage.py makemigrations
python manage.py migrate
管理ユーザー作成
python manage.py createsuperuser
ユーザー名、メールアドレス(空欄でEnterでOK)パスワード(入力しても反応なく見えないが、ちゃんと入力されている)
サンプルデータ作成
python manage.py runserver
左の8000アイコンをクリックしてプラウザを立ち上げたらアドレスの最後に/adminでEnterすると管理画面に入れます。
 https://localhost-それぞれのサーバー名.paiza-user-free.cloud:8000/admin
Holidaysの+追加をクリックしてデータをいくつか追加してください。
参考サイトではhttp://127.0.0.1:8000/api/holiday/ となっていますがhttps://localhost-それぞれのサーバー名.paiza-user-free.cloud:8000/calendar/api/holiday/でDRFのページに遷移します。参考サイトはcalendarが抜けています。

最終的にDjangoのテンプレートを使うので同一オリジンになります。
なのでCors対策は不要なのでVueで画面が完成したら削除したほうが安全だと思います。
今回Herokuへデプロイしたものも削除しています。
目次へ

Vueプロジェクト作成

参考サイトとは違い大元のルートにプロジェクトを作ります。(GitHubへたくさんファイルを入れたくないので。)

cdで大元に戻ります。または別のターミナルを立ち上げます。
npm install -g @vue/cli
vue create vue-calendar
参考サイトと同じように設定してください。VuexとVue Routerの追加を忘れないように注意。
選択するところは上下キー、スペース(全角だと効かないので半角モードで入力)を押すと選択、決定はEnter
最後はuse NPMにしました。

vue.config.jsにPaizaCloud対策する。これをやらないとInvalid Host headerというエラーになります。(~allowedHosts: "all",~の部分、注意、ビルド前には消した方がいい)
またビルドしたとき相対パスで出力するようにpublicPathの設定もしておきます。
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true
})
module.exports = {
  devServer: {
    allowedHosts: "all",
  },
  publicPath: './',
}
ディレクトリを移動して実行します。
cd vue-calendar
npm run serve

コードを書いていきます。
参考サイトのコンポーネント作成(その1)からコードのコピペではPaizaCloudの場合うまくいかないので以下のように改造しました。
Footer.vueは使用してません。
参考サイトの説明を読んで、使うコードは下のコードで作ってください。

<template>
<body>
  <nav>
    <router-link to="/home">Home</router-link> |

    <router-link to="/">Calendar(表示しないときクリック)</router-link>
  </nav>

  <div id="app">
    <!-- ここでコンポーネントをタグで配置 -->
    <Header />
    <router-view />

  </div>
</body>
</template>
<script>
// ここでコンポーネントを呼び出し
import Header from "./components/Header.vue";

export default {
  name: "App",
  // コンポーネントを設定
  components: {
    Header,

  }
};
</script>
<style>
* {
  margin: 0;
}
#app {
  text-align: center;
  color: #2c3e50;
}
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

nav {
  padding: 30px;
}

nav a {
  font-weight: bold;
  color: #2c3e50;
}

nav a.router-link-exact-active {
  color: #42b983;
}
</style>
<template>
  <header>
    <div>
      <h1>Calendar</h1>
    </div>
  </header>
</template>

<script>
export default {
  name: "site-header"
};
</script>

<style scoped>
h1 {
  margin: 8px;
}
</style>
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import Calendar from '@/components/Calendar_test.vue'
const routes = [
  {
    path: '/home',
    name: 'home',
    component: HomeView
  },

    {
    path: '/',
    name: 'django-calender',
    components: {
      default: Calendar,
    }
  }
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router
注意 赤色はそれぞれ違いますのでご自分のサーバー名に変えてください。
app.config.globalProperties.$httpHoliday = 'https://localhost-それぞれのサーバー名.paiza-user-free.cloud:8000/calendar/api/holiday/?format=json'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

// createApp(App).use(store).use(router).mount('#app')
const app = createApp(App).use(store).use(router)

// fetchを定義
app.config.globalProperties.$http = (url, opts) => fetch(url, opts)
// DRFのURL(API用)
app.config.globalProperties.$httpHoliday = 'https://localhost-それぞれのサーバー名.paiza-user-free.cloud:8000/calendar/api/holiday/?format=json'

app.mount('#app')
import { createStore } from 'vuex'
import { UPDATE_HOLIDAY } from './mutation-types'


export default createStore({
  strict: process.env.NODE_ENV !== 'production',
  state: {
    holiday: {},
  },
  getters: {
    holidayList(state) {
      return state.holiday
    }
  },
  mutations: {
    [UPDATE_HOLIDAY](state, payload) {
      state.holiday = payload
    },
  },
  actions: {
    [UPDATE_HOLIDAY]({ commit }, payload) {
      commit(UPDATE_HOLIDAY, payload)
    },
  },
  modules: {
  }
})

src/store/mutation-types.js

// 処理を把握しやすくするため定数化
export const UPDATE_HOLIDAY = 'updateHoliday'
<template>
  <div>
    <!-- カレンダーヘッダー -->
    <div id="cal-header">
      <span class="header-arrow" @click="setLastMonth"><</span>
      <span class="selected-month">{{ year }}.{{ month }}</span>
      <span class="header-arrow" @click="setNextMonth">></span>
    </div>
    <!-- カレンダーテーブル -->
    <table id="cal-main">
      <thead>
        <th v-for="dayname in weekdays" :key="dayname">{{ dayname}}</th>
      </thead>
      <tbody>
        <tr class="cal-day" v-for="(weekData, index) in calData" :key="index">
          <td v-for="(dayNum, index) in weekData" :key="index" @click="dateClick(dayNum)" :class="{'cal-today': isToday(dayNum), active: day === dayNum, isSaturday: index === 6, isSunday: index === 0, 'cal-holiday': isHoliday(dayNum)}">
            <span v-if="isToday(dayNum)">
              <strong>today</strong>
            </span>
            <span v-else>{{ dayNum }}</span>
          </td>
        </tr>
      </tbody>
    </table>
    <!-- 日付表示部分 -->
    <div class="holiday">
      <p>Today:{{ today }}</p>
      <button @click="setNextHoliday">Let's check next holiday!</button>
      <ul v-show="checkHoliday">
        <li>Next Holiday:{{nextHolidayDate}} ({{nextHolidayName}})</li>
        <transition>
          <li v-show="checkHoliday" class="check">
            There's
            <strong>{{termUntilNextHoliday}} days</strong> to next holiday...
          </li>
        </transition>
      </ul>
    </div>
  </div>
</template>

<script>
import { mapGetters, mapActions } from 'vuex'
import { UPDATE_HOLIDAY } from '../store/mutation-types'
export default {
  data() {
    return {
      weekdays: ['Sun', 'Mon', 'Tue', 'Wed', 'Tur', 'Fri', 'Sat'],
      year: 2020,
      month: 10,
      day: -1,
      today: '',
      checkHoliday: false,
      nextHolidayObj: '',
      nextHolidayName: '',
      nextHolidayDate: '',
      termUntilNextHoliday: 0
    };
  },
  computed: {
    ...mapGetters(['holidayList']),
    calData() {
      const calData = []
      const firstWeekDay = new Date(this.year, this.month - 1, 1).getDay()
      const lastDay = new Date(this.year, this.month, 0).getDate()
      let dayNum = 1
      while (dayNum <= lastDay) {
        const weekData = []
        // 日曜~土曜の日付データを配列で作成
        for (let i = 0; i <= 6; i++) {
          if (calData.length === 0 && i < firstWeekDay) {
            // 初週の1日以前の曜日は空文字
            weekData[i] = ''
          } else if (lastDay < dayNum) {
            // 最終日以降の曜日は空文字
            weekData[i] = ''
          } else {
            // 通常の日付入力
            weekData[i] = dayNum
            dayNum++
          }
        }
        calData.push(weekData)
      }
      return calData
    }
  },
  created() {
    // 祝日データ取得
    this.$http(this.$httpHoliday,{credentials:'include'})
      .then(response => {
        return response.json()
      })
      .then(data => {
        this[UPDATE_HOLIDAY](data)
      })
  },
  mounted() {
    // 今日の日付を文字列で算出
    const date = new Date()
    const y = date.getFullYear()
    const m = ('0' + (date.getMonth() + 1)).slice(-2)
    const d = ('0' + date.getDate()).slice(-2)
    this.year = y
    this.month = Number(m)
    this.today = y + '-' + m + '-' + d
  },
  methods: {
    ...mapActions([UPDATE_HOLIDAY]),
    setLastMonth() {
      if (this.month === 1) {
        this.year--
        this.month = 12
      } else {
        this.month--
      }
      this.day = -1
    },
    setNextMonth() {
      if (this.month === 12) {
        this.year++
        this.month = 1
      } else {
        this.month++
      }
      this.day = -1
    },
    dateClick(dayNum) {
      if (dayNum !== '') {
        this.day = dayNum
      }
    },
    isToday(day) {
      const date = this.setDateToString(day)
      if (this.today === date) {
        return true
      }
      return false
    },
    setDateToString(day) {
      // 日を年月日の文字列にして返す
      const date =
        this.year +
        '-' +
        String(this.month).padStart(2, '0') +
        '-' +
        String(day).padStart(2, '0')
      return date
    },
    isHoliday(day) {
      // Ajaxで取得した日と一致しているかチェック
      const date = this.setDateToString(day)
      for (const holiday in this.holidayList) {
        if (this.holidayList[holiday].date === date) {
          return true
        }
      }
      return false
    },
    calcTermDays(day1, day2) {
      // Dateオブジェクトの日数の差分を計算
      return (day2 - day1) / 86400000
    },
    calcNextHoliday() {
      // 次の祝日までの日数、および次の祝日のオブジェクトを返す
      for (const holiday in this.holidayList) {
        const holidayToDate = new Date(this.holidayList[holiday].date.split('-'))
        const todayToDate = new Date(this.today.split('-'))
        const termDays = this.calcTermDays(todayToDate, holidayToDate)
        if (termDays >= 0) {
          return [termDays, this.holidayList[holiday]]
        }
      }
    },
    setNextHoliday() {
      // 次の祝日の名前、日数をセット
      [this.termUntilNextHoliday, this.nextHolidayObj] = this.calcNextHoliday()
      this.nextHolidayName = this.nextHolidayObj.name
      this.nextHolidayDate = this.nextHolidayObj.date
      this.checkHoliday = true
    }
  }
};
</script>


<style scoped>
body {
  margin: 0;
}
#cal-header {
  font-size: 24px;
  padding: 0;
  text-align: center;
  margin-bottom: 10px;
  background-color: green;
  border-bottom: 1px solid #ddd;
  display: flex;
  justify-content: space-between;
}
#cal-header span {
  padding: 15px 20px;
  color: white;
  display: inline-block;
}
#cal-header .header-arrow {
  cursor: pointer;
}
#cal-main {
  font-size: 14px;
  line-height: 20px;
  table-layout: fixed;
  width: 100%;
  margin-bottom: 1rem;
  color: #212529;
  border-bottom: 1px solid #ddd;
  border-collapse: collapse;
}
#cal-main th {
  padding: 0;
  text-align: center;
  vertical-align: middle;
  font-weight: normal;
  color: #999;
}
#cal-main td {
  padding: 8px;
  text-align: center;
  vertical-align: middle;
  border-top: 1px solid #ddd;
}
.cal-today {
  background-color: #fcf8e3;
}
.cal-holiday {
  color: red;
}
.cal-day .active {
  background-color: #ffc9d7;
}
.cal-day .isSaturday {
  color: blue;
}
.cal-day .isSunday {
  color: red;
}
.holiday {
  position: absolute;
  top: 400px;
  right: 0;
  left: 0;
}
p {
  font-size: 30px;
}
li.check {
  font-family: "Eater", cursive;
}
button {
  margin: 30px auto 10px;
  width: 300px;
  font-size: 20px;
  padding: 5px;
  border: solid 1px #000;
  line-height: 30px;
  background: darkblue;
  color: #fff;
}
button:hover {
  cursor: pointer;
}
ul {
  list-style: none;
}
li {
  margin: 15px;
}
li > strong {
  color: red;
}
li {
  font-size: 30px;
}
.v-enter-active {
  transition: opacity 3s;
}
.v-enter-from {
  opacity: 0;
}
.v-enter-to {
  opacity: 1;
}
@media (min-width: 900px) {
  #cal-main,
  #cal-header {
    width: 900px;
    margin: auto;
  }
}
</style>
<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <!-- フォントのリンク -->
    <link href="https://fonts.googleapis.com/css2?family=Eater&display=swap" rel="stylesheet" />
    <!-- タイトル修正 -->
    <title>django_calendar</title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>
npm run serve
Django側も 
python manage.py runserver
で動作確認してみてください。

目次へ

Vueファイル修正箇所

修正した部分の詳細です。上のコードは修正済みのものなので以下は修正されています。

コンポーネントの名前が単純だとエラーになる

発生したエラー
error  Component name "Calendar" should always be multi-word  vue/multi-word-component-names

Vue コンポーネントの名前には複数のワードを用いましょうというものです。
対策・・・コンポーネントのファイル名を変更
参考サイトの名前だとエラーになったので変えました。
componentsのCalendar.vue→Calendar_test.vue
router/index.js
import Calendar from '@/components/Calendar.vue'
→import Calendar from '@/components/Calendar_test.vue'

Corsエラーではなくログインが必要なAPIにはセッション情報が必要(fetchの場合)

これはログインして使っているPaizaCloudの場合の話です。
Corsエラーが出ていたんですが原因はAPIのデータを取得するときにセッション情報(クッキー)を送っていないため。
検証ツールでの見た目は、なぜかCorsエラーになっていました。
fetchでAPIデータを取得している部分を解説します。

参考サイトのAPIからデータを取得している部分は
main.jsの以下の部分
// fetchを定義
app.config.globalProperties.$http = (url, opts) => fetch(url, opts)

$はどこからでも呼び出せる変数の印。
インスタンスが利用できるプロパティに対して接頭辞に $ をつけるよう規約を設けているようです。
文の構造はこの簡単例とな同じで定義部分は
let sample2 = (a,b) => {
  document.write(a+b);
}

使用するときは
sample2(2,3);これの出力は5

同じように今回の場合http(url,opts)はfetch(url, opts)になる。

// DRFのURL(API用)
app.config.globalProperties.$httpHoliday = 'http://127.0.0.1:8000/api/holiday/'
ここでAPIのURLをセット。
PaizaCloudの場合
app.config.globalProperties.$httpHoliday = 'https://localhost-それぞれのサーバー名.paiza-user-free.cloud:8000/calendar/api/holiday/?format=json'

?format=jsonはDjango Rest frameworkのGUI画面でget→jsonとするとurlが上のように表示されます。GUIを表示させないでjsonデータだけが送られていたためこうしました。?format=jsonなしでうまくいくは試していない。(htmlファイルとか余計なもの送られてきて、うまくいかなそうな気はします。)

APIのデータ取得するときセッション情報(クッキー)を付けるやり方は以下になります。
include: クロスオリジン呼び出しであっても、常にユーザーの資格情報 (クッキー、HTTP Basic 認証、、など) を送信します。危険な設定なので十分注意
components/Calendar.vue
    // 祝日データ取得
    this.$http(this.$httpHoliday)
→this.$http(this.$httpHoliday,{credentials:'include'})

最終的にDjangoのテンプレートを使うのでセッション情報(クッキー)を付ける必要はなくなります。
不要なのでVueで画面が完成したら削除したほうが安全だと思います。
今回Herokuへデプロイしたものも削除しています。
目次へ

Corsエラーではなくログインが必要なAPIにはセッション情報が必要(axiosの場合)

今回関係ありませんがaxiosの場合も書いときます。
クッキーを送っていいか十分注意して使用してください。

this.axios
      .get("https://localhost-それぞれの.サーバー名.paiza-user-free.cloud:8000/api/v1/posts/?format=json",
      {
          withCredentials: true
          
      })

npm run buildしたけどApp.vueの<router-view />部分が表示されない。

ビルド後、index.htmlが真っ白な場合。相対パスで出力するようにvue.config.jsを以下のようにすれば解決する。
module.exports = {
    publicPath: './',
}
これはこれで必要だが、今回これだけでは直らなかった。

検証ツールの要素で見ると<router-view />部分は<-- -->という表示になっている。
jsファイルはちゃんとプラウザに読み込まれているようであるが実行されていない。

原因は分からないがVueでrouterを使うときのデフォルトの<nav>の部分を使って表示を切り替えるとうまく表示したので利用した。

ここは力技です。
(参考サイトのままでビルドしなければうまくいきます。)

目次へ

ビルドでできたdist/の静的ファイルをDjangoで使う

ビルドしてdistディレクトリにindex.html、css、jsファイルが出来上がっているので、これをDjangoのテンプレートとstaticに入れます。

試しにビルド

その前に試しにビルドしてみます。あとで修正して、もう1回ビルドします。
CTRL+Cで停止させたあと
npm run build
vue-calendar/dist/index.htmlを右クリック→プラウザで開く
本来ここでカレンダー表示するはずなのですがしないのでCalendar(表示しないときクリック)をクリックすると出ます
「Let's check next holiday!」ボタンの動作も確認できます。

Djangoで使えるように修正してビルド

そのままでは使えないので修正します。

Djangoのテンプレートに入れる分には不要なところを戻す。

この変更をするとPaizaCloudのでは動かなくなります。
components/Calendar.vueの以下を戻す。
    // 祝日データ取得
this.$http(this.$httpHoliday,{credentials:'include'})
→this.$http(this.$httpHoliday)

vue.config.jsの以下を消す。
  devServer: {
    allowedHosts: "all",
  },
ビルドします。
npm run build

Django側の変更

app_calを右クリック、新規ディレクトリでtemplatesディレクトリ作成
できたtemplatesを右クリック、app_calディレクトリ作成
templates/app_calを右クリックして新規ファイル作成でindex.html作成
、dist/index.htmlをコピーしstatic対応します。一旦メモ帳にコピーして作業すると楽です。

冒頭に{% load static %}
jsファイルやcssファイルを参照しているところを{% static 'jsファイル' %}で囲む。
今回のindex.htmlの場合

{% load static %}<!doctype html>
略
src="{% static 'js/chunk-vendors.7d99a92b.js' %}"></script><script defer="defer" src="{% static 'js/app.424304bd.js' %}"></script><link href="{% static 'css/app.1f781f81.css' %}" rel="stylesheet"></head>
略

app_calディレクトリを右クリックしてstaticディレクトリを作ります。staticディレクトリを右クリックして新規ディレクトリでcssとjsディレクトリ作成
dist/css→static/css、dist/js→static/jsにそれぞれファイルをコピーします。*.mapファイルはいりません。
Djangoからindex.htmlを表示するように変更します。

app_cal/urls.pyに以下追加
path('', views.HajimeteView.as_view(), name="index"),

project_cal/urls.pyに以下追加
path('',include("app_cal.urls")),

views.pyに追加
from django.shortcuts import render
from django.views import View

class HajimeteView(View):
    def get(self, request, *args, **kwargs):
       return render(request,"app_cal/index.html")

python manage.py runserverで動きます。

同オリジンになるのでCors対策はなくしました。
目次へ

Herokuへ

HerokuでNew→Create New Appでアプリ名を決めてください。
その後API取得元のアドレスを変更します。
static/js/app.424304bd.jsの
$httpHoliday=”https://localhost-それぞれのサーバー名.paiza-user-free.cloud:8000/calendar/api/holiday/?format=json”を
“https://HerokuのそれぞれのApp Name.herokuapp.com/calendar/api/holiday/?format=json”に変更

Postgresへデータベース変更、静的ファイル対応

現状データベースはSQLite3なのでHerokuでは使えません。Postgresに変更します。
まず下の記事の静的ファイル対応をやってください。

静的ファイルのほうを先にやってください。
settings.pyのDATABASE設定はSQLiteなのでコメントアウトしてHerokuのPostgres用の2行追加
# DATABASES = {
#     'default': {
#         'ENGINE': 'django.db.backends.sqlite3',
#         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
#     }
# }
import django_heroku
django_heroku.settings(locals())


データは引きつかず改めて入力することを考えた方がいいと思います。Herokuでデータベースへの入力方法は下で紹介します。
データベースがうまくいかなくて最初からやりたいときは
migrationsディレクトリの中の__init__.py以外のファイルとdb.sqlite3というファイルを消せば最初からできます。

最終的なHeroku用のPostgre設定はsettings.pyの上記になりますがGitHubへプッシュ直前に変更してください。変更したあとpython manage.py collectstaticなど実行すると: No module named 'django_heroku'というエラーが出ます。

PaizaCloud→GitHub→Herokuへ

下の記事を参考にPaizaCloud→GitHub→Herokuへデプロイしてください。

今回のrequirements.txtとProcfileは以下です。
project_calを右クリックで新規ファイル作成でそれぞれ追加してください。

requirements.txt
django
gunicorn
whitenoise
djangorestframework
django-heroku

Procfile
web: gunicorn project_cal.wsgi
Herokuでデータを入力します。
Herokuの今自分で作ったアプリ画面で右上のMORE→Run console
python manage.py migrate
1回閉じでもう1回MORE→Run console
python manage.py shell
from app_cal.models import Holiday
q=Holiday(name="敬老の日",date="2022-09-19")
q.save()
記録されてるか確認
q.name
q.date
exit()

右上のOpen Appをクリックすると立ち上がります。

完成品 祝日登録削除機能を追加しました。詳細は以下の記事


目次へ

あとがき

今回の方法は一言でいえば、もっといい方法があると思います。BundleTrackerとか色々やってみたもののエラーで先に進めずこんな形となりました。
自分のパソコンに開発環境作らないでPaizaCloud使っているのも遠回りの原因かと思います。
フロント側をVueで作成しても結局Djangoのテンプレートに入れているので今一スッキリした形ではないです。
ただデプロイまでいけると途中の改善点も見つけやすいかと思います。
目次へ

この記事を書いたイチゲを応援する
Vプリカでのお支払いがおすすめです。

MENTAやってます(ichige)

コメント

タイトルとURLをコピーしました