【Django入門】アクセスカウンターのページを作ってデータベースの操作を体感する

※ 当サイトではアフィリエイト広告を利用しています。リンクは広告リンクも含みます。

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

最小限のコードでDjangoのデータベースを使ったアプリを作る方法
Python、Djangoをインストールしない開発環境
PaizaCloudを使用することで簡単に体験できます。
プログラム中でデータベースに書き込む簡単な例になります。
アクセス回数をカウントアップさせデータベースに書き込みます。
完成品(アクセスカウンタ)はこちらになります。Railwayデプロイ(毎月21日以降は停止してます)
完成品お名前.comVPS(有料)にデプロイ
完成品(アクセスカウンタ)はこちらになります。Renderデプロイ(表示するまで数分かかることがあります)
Djangoの基本及びPaizaCloudについてはこちらの記事を参考にしてください。

広告

PaizaCloudで新規サーバー作成

パソコンに開発環境がある方は飛ばしてください。
PaizaCloud は無料インストールなしでPython、Djangoが使えます。
PaizaCloudに登録したら新規サーバー作成
サーバー名を適当な名前で入力
初期インストール&設定するものを選択してください」で
 Web開発:Djangoを選択
 データベース:PostgreSQLを選択もしくは何も選択しないでいい。
PostgreSQLを選択しておくと後でHerokuへデプロイできます。
新規サーバー作成で完了です。
503 Service Temporarily Unavailableとエラーが出てるかもしれませんが
メッセージを閉じてください。
PaizaCloudの無料プランは使いづらいですが、
こちらを参考に使ってください。

プロジェクト、アプリ作成、settings.py変更

PaizaCloudの左にあるターミナルをクリック
以下のコードを入力

access_counterという名前でプロジェクトの作成
django-admin startproject access_counter 

access_counterディレクトリへ移動
cd access_counter

ac_appという名前でアプリ作成
python manage.py startapp ac_app
settings.py変更
access_counter/access_counter/settings.pyをダブルクリック

以下のように2か所変更
・ホストを全部許可する。
・アプリを追加

ALLOWED_HOSTS = [] → ALLOWED_HOSTS = ['*']

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
  'ac_app.apps.AcAppConfig',      
#追加 ac_app/apps.pyにあるclass AcAppConfig(AppConfig):のクラス名を追加。'ac_app', だけでも動く
]
PaizaCloudの場合、今後ファイルを変更したら各Window左上の保存をクリック。
車両通行止めと同じマークが出ている場合は保存完了してます。

データモデル作成 models.py

Accessというデータモデルを定義し
access_noというフィールド(カラム名)を正の整数のフィールド型で定義します。

access_counter/ac_app/models.pyを以下のように作成

from django.db import models
class Access(models.Model):
    access_no = models.PositiveIntegerField(blank=True, null=True)

データモデルの定義に関してここが分かりやすいです。
【django】モデルのフィールドについて:フィールドの型・オプション一覧
目次へ

データベース準備

データベースは今回SQLiteを使用します。
Djangoの場合SQLiteと接続するのに特に何もする必要がありません。
上で定義したデータモデルをデータベースへ教えます。
そのための手順は以下です。

  1. モデルを作成、変更する (models.py の中にモデルを定義)
  2. モデルの作成、変更をデータベースに反映させるマイグレーションファイルを作成するために python manage.py makemigrations(これをコピペするとcommand not foundになるので、手打ち、または下のをコピペ)を実行。
  3. データベースにマイグレーションファイルを適用するために python manage.py migrate(これをコピペするとcommand not foundになるので、手打ち、または下のをコピペ) を実行します。

1番は済んでいるので2と3をやります。
それぞれ簡単な1命令だけです。

ターミナルで
python manage.py makemigrationsを実行
ターミナルで
python manage.py migrateを実行

データベースに1個だけデータを書きます。
Pythonシェル(対話方式でPythonを実行できる)を起動し
1行1行実行します。

python manage.py shell でPythonシェル起動

from ac_app.models import Access

q = Access(access_no=0)
q.save()

exit

データベースの操作はこちらが分かりやすいです。
【Django】データベース操作(取得・作成・更新・削除):ORMの利用

プログラムを書く順番として、この後出てくるviews.pyより先に今回の操作をします。
例えばviews.pyでq=Access.objects.get(id=1)等のコード書いちゃうと
python manage.py makemigrationsでエラーになります。
目次へ

URL設定urls.py

URLと処理を紐づけします。
urls.pyはプロジェクト(access_counter)とアプリ(ac_app)にそれぞれ必要です。
プロジェクト側は毎回同じです。
path(”,の’’はサーバーに割り当てられている大元のアドレスになります。
PaizaCloudの場合は後程プログラムを実行すればわかりますが
https://localhost-個人別の名前.paiza-user-free.cloud:8000/が大元となります。
なのでpath(”,include(“ac_app.urls”)),は上記アドレスにアクセスしたら
ac_app/urls.pyに行けという意味です。

プロジェクト(access_counter)のurls.pyを変更

from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('',include("ac_app.urls")),
]

アプリ(ac_app)のurls.pyは最初ないので
acc_appを右クリックして新規ファイル作成でurls.py作成
中身を以下にします。

from django.urls import path
from . import views

app_name    = "ac_app"
urlpatterns = [ 
    path('', views.AccessView.as_view(), name="index"),
]

これもpath(’’なので大元のアドレスにアクセスしたら
views.pyのAccessView.as_view()を実行しろという意味です。
as.view()は継承元のViewクラスのメソッドでviewオブジェクトを生成します。
Viewクラスを継承したクラスを実行する場合はこの形で共通のようです。
目次へ

データ処理 views.py

Viewクラス(get()、post()などHTTPメソッドに特化したビュークラス)を
継承してAccessViewをつくります。
このViewクラスはgetとpostが来たときの処理を書けば済みます。
取りあえずgetのみ書きます。

ポイントは
青色と緑色の部分以外はお決まりの形。
contextの中に辞書型でテンプレートに渡したい変数を書く。
緑色部分にテンプレートに使うファイル名を書く。

HTTPメソッドについては以下が分かりやすいです。
基礎
「HTTPリクエスト」と「HTTPレスポンス」
DjangoのHTTPメソッド
PythonのWebフレームワーク「Django」のHttpRequestオブジェクトを徹底解説
【Django】views.pyの引数resquest:HttpRequestオブジェクトの使用方法

views.pyを
from django.shortcuts import render
from .models import Access
from django.views import View

class AccessView(View):
    def get(self, request, *args, **kwargs):
        q=Access.objects.get(id=1)
        kaisuu=q.access_no+1
        q.access_no=kaisuu
        q.save()
        test_text=str(kaisuu)+'回目のアクセスです'
    
        context = { "test_text"     : test_text
                    }
    
        return render(request,"ac_app/index.html",context)
Tips:
以下のようにget_or_createを使うとPythonシェル起動でデータオブジェクトを作らなくてもよくなります。
get_or_create(条件,defaults={デフォルト値設定})は条件に当てはまるデータオブジェクトがない場合デフォルト値に設定した値で作ってくれます。
この場合id=1が存在しない場合だけaccess_no=0のデータオブジェクトを作成します。
略
class AccessView(View):
    def get(self, request, *args, **kwargs):
        Access.objects.get_or_create(id=1, defaults={'access_no':0})
        q=Access.objects.get(id=1)
        kaisuu=q.access_no+1
略

注意
Render.comにデプロイした場合このアプリのLogsを見ると下のように数秒ごとにアクセスされています。多分Renderが何かチェックしているものと思われます。
Nov 23 08:54:23 AM  127.0.0.1 - - [23/Nov/2022:08:54:23 +0900] "GET / HTTP/1.1" 200 493 "-" "kube-probe//"
このためviews.pyが呼ばれてしまいカウンタ値がどんどん上がっていきます。
なのでRender.comにデプロイする場合は別途対策が必要になります。

目次へ

表示 Template

テンプレートは実際に表示する画面をHTMLで記述します。
Viewから受け取ったcontextは{{変数}}の形で使用します。
基本的なHTMLフォーマットに変数test_textを配置しただけです。

ac_appを右クリック、新規ディレクトリでtemplatesディレクトリ作成
その下にもう1個ac_appディレクトリ作成
templates/ac_appを右クリックして新規ファイル作成でindex.html作成

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Access Counter</title>
  </head>
  <body>
  <h1>アクセスカウンタ</h1>
    <p>{{test_text}}</p>
  </body>
</html>
python manage.py runserverでプログラムが実行できます。
PaizaCloudの右の8000をクリックすると表示します。
個人の開発環境の場合、ターミナルに下のように表示されるので赤色のhttp://127.0.0.1:8000/(http://0.0.0.0:8000/など違う表示のときもある)の部分をCTRLと一緒にクリックすれば見れます。
System check identified no issues (0 silenced).
June 21, 2023 - 00:26:51
Django version 3.2.19, using settings 'access_counter.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

目次へ

カウンターリセットボタンを追加

index.htmlに以下の赤い部分を追加
formは一般的なhtmlの書式です。
{% csrf_token %}はDjangoでformを使うとき中に決まって入れるコードです。
これが何をやっているか、こちらで実験しています。

CSRFについては、こちらの動画でDjangoではなくPHPのはなしですが
CSRFについて具体的に何に対して対策しているのかが分かります。
初心者PHPプログラミング講座9完結編 お問合せフォーム セキュリティCSRFクロスサイトリクエストフォージェリ対策
上記で学んだあとDjangoではどうしてるのかを以下で見ると理解できます。
【Django】 csrf_tokenの仕組みとCSRF無効化・画面カスタマイズする方法

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Access Counter</title>
  </head>
  <body>
  <h1>アクセスカウンタ</h1>
    <p>{{test_text}}</p>
    <form action="" method="post">
    {% csrf_token %}
    <input type="submit" value="Reset" name="name">
    </form>
    <p></p>
    <a href="">Home</a>
  </body>
</html>

上のhtmlによりResetボタンを押すとpostが送られてくるので
views.pyにpostの処理追加(赤い部分)

from django.shortcuts import render

from .models import Access
from django.views import View
class AccessView(View):

    def get(self, request, *args, **kwargs):
        q=Access.objects.get(id=1)
        kaisuu=int(q.access_no)+1
        q.access_no=kaisuu
        q.save()
        test_text=str(kaisuu)+'回目のアクセスです'
        context = { "test_text"     : test_text
                    }
    
        return render(request,"ac_app/index.html",context)

    def post(self, request, *args, **kwargs):
        q=Access.objects.get(id=1)
        if request.POST['name'] == 'Reset':
            kaisuu=0
        q.access_no=kaisuu
        q.save()

        test_text='カウンタークリア'
        context = { "test_text"     : test_text
                    }
    
        return render(request,"ac_app/index.html",context)

これで完成です。完成品をRailwayへデプロイしたもの。r(毎月21日以降は停止してます)
完成品(アクセスカウンタ)はこちらになります。Renderデプロイ(表示するまで数分かかることがあります)
目次へ
Herokuへデプロイしたい場合はこちらの記事を参考にしてください。(Herokuが有料になったので今はRailwayRenderを使っています。

複数のアプリケーションを入れるときの注意点

RailwayとRenderへデプロイした完成品はアドレスを大元ではなく/acにしてあります。
https://ac-web2.up.railway.app/ac(Railwayにデプロイしたもの。毎月20日以降停止)
https://ac-web2ren.onrender.com/ac(Renderにデプロイしたもの。立ち上がるまで数分かかることがあります。)
もう一つ別のアプリを同じプロジェクトに入れてあります。
https://ac-web2.up.railway.app/web/(Railwayにデプロイしたもの。毎月20日以降停止)
https://ac-web2ren.onrender.com/(Renderにデプロイしたもの。立ち上がるまで数分かかることがあります。)
このように複数のアプリをプロジェクトに入れるとき
一つの時とは異なる注意点があります。

同じ名前のものでも使えるようにする

テンプレートやcssが同じ名前でも使えるように
template、staticの下に、それぞれの名前のディレクトリを作ってファイルを配置する。
そうするとディレクトリ付きで指定できるので誤動作しない。

アプリが複数の場合の階層
ac_app
   ├ templates
  ├ static
  │ 
website
   ├ templates
  │ └ website
  │   └ index.html
  ├ static
  │ └ website
   │      ├ welcome.jpg
  │   └ main.css 
template例
template_name = "website/index.html"
static例
<link rel="stylesheet" href="{% static 'website/main.css' %}">
<img src="{% static 'website/welcome.jpg' %}" />

テンプレートの中でurl作るときはアプリ間の重複を避けるため
各アプリのurls.pyでapp_nameを指定
htmlで呼び出すときはwebsite:の形で指定

各アプリのurls.pyでapp_name指定
app_name = 'website'
urlpatterns = [
    path('', IndexView.as_view(), name="index"),

html
<a href="{% url 'website:index' %}">Home</a>

標準のクラスビューはtemplate_nameを指定する

一つのアプリではtemplate_name=は省略しても動きますが
場所を移動するとうまくいかないので
template_name=でしっかり記述するとうまくいきます。

class Detail(DetailView):
    # 詳細表示するモデルを指定 -> `object`で取得可能
    model = Post
    template_name = "blog/post_detail.html"

大元のアドレスに戻る”/”

アプリを複数にすると大元のアドレスに戻るのではなく
各アプリごとのディレクトリに戻ることになると思います。
大元のアドレス/db3に戻る場合
“/”で使用していたものを”/db3″に変更します。
“db3/”というようにスラッシュの位置を後ろに持ってくると
今いるアドレスの後ろに/db3/がくっついてしまうので注意が必要です。

could not be loaded; Error importing module.

個人的メモです。
settings.pyのDebug=Falseの時(Debug=Trueでは起きない)
HerokuへデプロイしたプロジェクトをPaizaCloudに
クローンして実行しようとすると
could not be loaded; Error importing module.エラーになった。

settings.pyのWSGI_APPLICATION = ‘access_counter.wsgi.application’を
コメントアウトするとうまくいきました。
その後は元に戻しても大丈夫なので元に戻しました。

Herokuのデータベース使用行数確認方法

Herokuの無料プランで使えるデータベースの行数は10000です。
現在どれくらい使っているかは各アプリの
Overview→Installed add-onsのHeroku Postgresをクリック

20 of 10,000
ROWS IN COMPLIANCE
が現在使用中の行数です。

この記事を書いたイチゲを応援する(質問でもokです)
Vプリカでのお支払いがおすすめです。
MENTAやってます(ichige)
目次へ


コメント

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