お金も無いのでアルバイトがやりたいと言ってたら、Web開発の業務が舞い込んだ。
私「使えるプログラミング言語はPerl、PHP、Pythonです。」
担当「Ruby on Rails使えないとか、もうね・・・仕事なんて無いよ。」
私「勉強を始めました!インストールまで完了しました。」
担当「いや、そんなレベルいらないから!!お荷物だから!」
「不採用」じゃねーか!
40歳にもなって、アルバイトもロクに採用されねーのかよ、俺。
そもそも「Ruby on Rails」なんてオワコンだろ。
このWebフレームワークの人気(月の質問数)グラフを担当者に突きつけたいわ。
あきらかに今から必要なのは「Django」か「Laravel」ができるエンジニアじゃん。
てか、過去の日記見たら「Laravel」は2017年の学習目標だった・・・
遊んでる場合じゃねー、何やってんだよ過去の俺!
Python3をCGIで動かす事前準備
そもそも、PythonでCGI(Common Gateway Interface)を使用したことがない。そこから挑戦。
さくらインターネットでPython3のCGIで「Hello world」を表示する
ハマった・・・・。なんどやっても「500 Internal Server Error」が表示される。
1 2 3 4 |
#!/home/ユーザ名/.pyenv/versions/3.7.7/bin/python # coding: utf-8 print('Content-type: text/html; charset=UTF-8\r\n') print("Hello World!") |
そもそも which コマンドを使うと次のようなパスが表示される。
1 2 |
$ which python /home/ユーザ名/.pyenv/shims/python |
このパスからの呼び出しはできない。次のようなエラーが出た。
1 2 |
[Thu Feb 11 11:57:01.643192 2021] [cgi:error] [pid 65545] [client 126.39.143.167:0] AH01215: suexec policy violation: see suexec log for more details: /home/ユーザ名/www/cgi-bin/django/index.cgi [Thu Feb 11 11:57:01.643292 2021] [cgi:error] [pid 65545] [client 126.39.143.167:0] End of script output before headers: index.cgi |
エラーの内容からは意味が分からない。CGIはここが良くない。
で、ネットで色々と確認して修正。かつアップロードするファイルも次のような規則がある。
- 文字コード: UTF-8N(BOMが付いていないUTF-8)
- 改行コード: LF
- パーミッション:755(-rwxr-xr-x)
これで正しく「Hello world」が見れた。表示が遅いな。
【付録】treeコマンドがない環境でツリー構造で表示する
Findコマンドを使うとワンライナーで実現が可能だ。
1 |
pwd;find . | sort | sed '1d;s/^\.//;s/\/\([^/]*\)$/|--\1/;s/\/[^/|]*/| /g' |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|--.gitignore |--README.md |--app | |--__init__.py | |--admin.py | |--apps.py | |--filters.py | |--forms.py | |--migrations | | |--0001_initial.py | | |--__init__.py | |--models.py | |--static | | |--app | | | |--css | | | | |--app.css | | | |--js | | | | |--app.js | | | | |--plugins | | | | | |--responsive-paginate.js | |--templates | | |--app | | | |--_base.html | | | |--_pagination.html | | | |--item_card.html |
これは単なるTipsだけど、知っていて損はない。
さくらインターネットで、django(CGI版)を使う方法
さくらインターネット(スタンダードプラン)は他のユーザとの共有サーバのためデーモンは禁止されており、runserverで立てたDjangoのプロセスは、ターミナルを閉じるとkillされてしまう。
そこで、1アクセスされるたびにプロセスを立ち上げるCGIを利用してDjangoを動作させる方法があるらしい。
だから、PythonをCGIで実行するところから始めた。
cgiでDjangoを使えるようにする
python3 で Django を動かすには次のように書く。データベースはsqlite3にしている。
モジュールがなければ「pip」でインストール。
1 2 3 4 5 |
import django import sqlite3 print(django.get_version()) print(sqlite3.version) |
無事に動けばバージョンが表示される。うん正常。
1 2 3 |
[ukyo@www366 ~/www/django]$ python sample.py 3.1.6 2.6.0 |
サンプルを動作させる
適当に「Python Django simple」でググって一番最初に出てきたソースコード。CRUDとは「Create、Read、Update、Delete」のこと。
解凍して必要なライブラリはインストールしておく。
1 2 3 4 |
$ pip install -r requirements.txt Collecting Django==2.1.3 Downloading Django-2.1.3-py3-none-any.whl (7.3 MB) ... |
完了。はい次!
python3用のdjango3.cgiを設置
ネットを調べると「django-python3.cgi」を使って、CGIとしてDjangoを動かすことができるらしい。
ダウンロードしてリネームして実行権限をつける。
CGIとして動かす方法は前述通り。
で、各種設定を変更する。
1 2 3 4 5 6 7 |
# Change this to the directory above your site code. sys.path.append("/home/ユーサ名/.pyenv/versions/3.7.7/lib/python3.7/site-packages") sys.path.append("/home/ユーサ名/www/cgi-bin/django/Django-Simple-CRUD-Sample") # Change to the name of your settings module os.environ['DJANGO_SETTINGS_MODULE'] = 'project.settings' |
「DJANGO_SETTINGS_MODULE」には、settings.pyが存在するパスを指定してあげるっぽい。
つまり今回は「project」→「settings」だ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|--.gitignore |--README.md |--app |--manage.py |--project | |--__init__.py | |--__pycache__ | | |--__init__.cpython-37.pyc | | |--settings.cpython-37.pyc | | |--urls.cpython-37.pyc | |--settings.py | |--urls.py | |--wsgi.py |--requirements.txt |
では、URLを叩いていざ実行。
1 2 3 4 5 |
DisallowedHost at / Invalid HTTP_HOST header: 'uguisu.skr.jp'. You may need to add 'uguisu.skr.jp' to ALLOWED_HOSTS. Request Method: GET Request URL: https://uguisu.skr.jp/cgi-bin/django/django3.cgi/ Django Version: 2.1.3 |
エラーではあるが「500 Internal Server Error」ではない。一歩前進した感じがある。
Invalid HTTP_HOST header: ”. You may need to add ” to ALLOWED_HOSTS
エラーの説明通り、settings.py中のALLOWED_HOSTS変数へアクセスを許可するホスト名を記載する。
1 |
ALLOWED_HOSTS = ['uguisu.skr.jp'] |
これでページが表示されるようになった。
no such table: auth_user
色々とページを飛んでると、エラーが表示された。
1 2 3 4 5 6 |
OperationalError at /admin/login/ no such table: auth_user Request Method: POST Request URL: https://uguisu.skr.jp/cgi-bin/django/django3.cgi/admin/login/?next=/cgi-bin/django/django3.cgi/ Django Version: 2.1.3 Exception Type: OperationalError |
no such table: auth_userとなっているので、migrateしてあげる。
migrateをすることで、データベース構成を変更したり、その変更を取り消したりすることができる。
1 2 3 4 5 6 |
python manage.py migrate Operations to perform: Apply all migrations: admin, app, auth, contenttypes, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK |
更にユーザを作成。てかGitHubのReadmeに書いてあったわ。
1 2 3 |
python manage.py createsuperuser ユーザー名 (leave blank to use 'ユーサ名'): hoge メールアドレス: |
で、再度実行。
お、動いた!
no such table: main.auth_user__old
エラーが出てユーザ登録が出来なかった・・・・。
SQALightの仕様が変わったのが原因っぽい。バージョンを落とすと動作するっぽいけど、そんな事はしたくないよ。
またサンプル探してみる。
お!
CSSのパス修正が必要だったが、こっちは動いた。
[settings.py]
1 2 3 4 5 6 7 |
# Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.10/howto/static-files/ STATIC_URL = 'https://uguisu.skr.jp/cgi-bin/django/Simple-CRUD-with-Django-SQLite-3/firstapp/static/' MEDIA_ROOT = os.path.join(BASE_DIR, 'firstapp/static/media') MEDIA_URL = 'https://uguisu.skr.jp/cgi-bin/django/Simple-CRUD-with-Django-SQLite-3/firstapp/static/media/' |
各子ページに移動する
最初、urls.pyの中を書き換えて root パスで各ページを見えるようにしていた。
1 2 3 4 5 6 |
urlpatterns = [ url(r'^admin/', admin.site.urls), - url(r'^firstapp/', include('firstapp.urls')), + url(r'^', include('firstapp.urls')), ] |
これは「.htaccess」に次のように書けば良い。
1 2 3 4 |
RewriteEngine on RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ django3.cgi/$1 [L] |
そうすれば「django3.cgi/firstapp/」や「django3.cgi/admin/」というURLで各子画面に遷移できるようになる。
んもう、早く言ってよ・・・・。
まとめ
さくらのスタンダード(500円)でpython3 + Django3 が使えるのは嬉しいね。Ruby on Railsは動かせなかったし。
ただ、叩くたびにpythonのライブラリを全て読み込んでいるのか、1リクエストあたり1秒程度かかり、非常に動作は遅い。
WordPress等もキャッシュを使わないと同様に重く、Djangoだけが遅いというわけではないが・・・・。
お試し公開サービスぐらいには使えるし、Ruby on RailsよりDjangoは直感的で分かりやすい気がする。