django入門
目次
- 1. 概要
- 2. リンク
- 3. インストール
- 4. ローカルディレクトリへのインストールしたものを最新のバージョンにアップグレード
- 5. 最初のdjangoアプリ
- 6. djangoアプリ2(Hello World)
- 7. djangoアプリ3(テンプレートの利用)
- 8. djangoアプリ4(計算アプリ)
- 9. djangoアプリ5(ファイルアップロード)
- 9.1. 以下の操作を行っている動画
- 9.2. djangoアプリ5(ファイルアップロード)作成手順
- 9.2.1. プロジェクトとmyfile_uploadアプリのベース作成
- 9.2.2. プロジェクトのセッティング修正
- 9.2.3. myfile_upload/urls.py には以下を記述します
- 9.2.4. mytest003/urls.py に 以下の変更を行う
- 9.2.5. テンプレートファイルを入れるディレクトリの準備
- 9.2.6. テンプレートファイル1用意
- 9.2.7. テンプレートファイル2(成功時用)用意
- 9.2.8. myfile_upload/forms.py を作成
- 9.2.9. myfile_upload/views.py を以下に変更します。
- 9.2.10. ファイル保管用のディレクトリ作成
- 9.2.11. サーバーを起動しブラウザで確認
- 9.3. この章まとめ
- 10. urlでのパラメータ渡し
- 11. カスタムフィルタ
- 12. セッション(session)関係の機能を試してみる
- 13. カスタムユーザーの作成(AbstractUserを継承タイプ)
- 14. カスタムユーザーの作成2(AbstractBaseUserを継承タイプ)
- 15. 郵便番号検索アプリの作成
- 15.1. 以下の操作を行っている動画
- 15.2. 郵便番号csvデータの取得と準備
- 15.3. 郵便番号検索アプリの作成手順
- 15.3.1. myzipcodes というアプリを作成し、その中にmyappというアプリケーションを作成
- 15.3.2. myzipcodes/settings.py 修正
- 15.3.3. myzipcodes/settings.py 修正2
- 15.3.4. zipcodes/models.py 修正
- 15.3.5. zipcodes/admin.py 修正
- 15.3.6. migration作成、適用
- 15.3.7. 郵便局から得たcsvファイルを前節で加工して生成した ken_all_utf_wh.json ファイルをデータベースに読み込み
- 15.3.8. zipcodes/views.py を以下に修正
- 15.3.9. zipcodes/templates/zipcodes/getAddress.html を作成
- 15.3.10. zipcodes/templates/zipcodes/getZipcodes.html を作成
- 15.3.11. myzipcodes/urls.py を以下に修正
- 15.3.12. サーバーを起動しブラウザで確認
- 15.4. この章でのまとめ
- 16. djangoのshellの活用
- 17. MySQLの利用
- 18. 実際裏で実行されてるSQLの確認方法
- 19. この文書のチェンジログ
- 20. 続きを追記してきます。
1 概要
1.1 djangoの概要
- djangoは2019/11でPythonで最もユーザー数が多いとされているWebアプリケーションフレームワーク
- 最新のdjangoはpython3系をサポートらしい
1.2 この文書の概要
- django関係の入門者用文書
- Ubuntu19系をを利用して最新のdjangoを使って確認してますが、他のOSでもほぼ同じ手順で作成可能
- 実際の作業部分を真似しやすいように作成
- 学習手順として、実際やってみてから、修正したり調べた方が効率良いケースが多い為
- ベースはdjangoの本家の文書なので、この文書のライセンスもdjangoの本家と同じとします。
2 リンク
2.1 本家
- Django ドキュメント (version 2.2)
- https://docs.djangoproject.com/ja/2.2/
- 入門文書(version 2.2)
- https://docs.djangoproject.com/ja/2.2/intro/
- 本家ドキュメント目次
- https://docs.djangoproject.com/ja/2.2/contents/
- 本家ドキュメント索引
- https://docs.djangoproject.com/ja/2.2/genindex/
- モジュール索引
- https://docs.djangoproject.com/ja/2.2/py-modindex/
3 インストール
- 2019/10月頃、Ubuntuのパッケージのdjangoは1系統であるため、Ubuntuのパッケージによるインストールはお勧めしません。
- WindowsやMacの場合、Ubuntuの仮想環境や模擬環境であれば、同じ操作で可能だと思います。
3.1 以下の操作を行っている動画
3.2 pipによるローカルへのインストール手順
3.2.1 必要パッケージのインストール
sudo apt install pip3
3.2.2 ローカルディレクトリへのインストール
- ホームディレクトリの python3/dist-packages ディレクトリにインストールする場合
- 下のコマンドを実行しパッケージ関係のファイルをインストール
pip3 install Django -t ~/python3/dist-packages
- インストールしたファイルを検索パスで検索できるように以下の設定を ~/.bashrcに追加し、再起動するか、端末を開きなおし、設定を読み込んだ状態にする
export PYTHONPATH="$HOME/python3/dist-packages:$PYTHONPATH" export PATH="$HOME/python3/dist-packages/bin:$PATH" alias python=python3
4 ローカルディレクトリへのインストールしたものを最新のバージョンにアップグレード
4.1 以下の操作を行っている動画
4.2 アップグレードするコマンド
pip3 install --upgrade Django -t ~/python3/dist-packages
5 最初のdjangoアプリ
- https://docs.djangoproject.com/ja/2.2/intro/ がお勧め
- 上の本家の文書の手順をベースとして簡略化し、多少アレンジした内容になってます。
5.1 以下の操作を行っている動画
5.2 現状のdjangoのバージョン確認
python -m django --version
- 2019/11/10現在で 2.2.7 の出力が得られています
5.3 python自体のバージョン確認
python --version
- 2019/11/10現在で Python 3.7.5rc1 の出力が得られています
5.4 プロジェクトの作成
- 以下のコマンドで mysite という名前のプロジェクトを作成できます。
- mysiteというディレクトリが作成され、その中にディレクトリや各種ファイルが生成されます
- プロジェクト名は mysite である必用はなく別の名前でもOK
django-admin startproject mysite
5.5 生成した空プロジェクトを動かしてブラウザで確認する方法
- 以下のコマンドでプロジェクトのルートにカレントディレクトリを移動
cd mysite
- 以下のコマンドでサーバーを起動
- デフォルトで http://127.0.0.1:8000/ で動きます
- ポート番号とかはオプションで変更可能
- http://127.0.0.1:8000/ をブラウザで開くとデフォルト画面が表示されます。
python manage.py runserver
6 djangoアプリ2(Hello World)
- https://docs.djangoproject.com/ja/2.2/intro/ がお勧め
- 上の本家の文書の手順をベースとして簡略化し、多少アレンジした内容になってます。
- 指定のurlにアクセスすると、指定の文字が表示されるものを作ります
6.1 以下の操作を行っている動画
6.2 指定のurlで指定の文字が表示されるウェッブアプリを作成する手順
6.2.1 mytest001というアプリを作成し、その中にmypageというアプリケーションを作成
django-admin startproject mytest001
cd mytest001
python manage.py startapp mypage
6.2.2 mypage/views.py を以下に変更します。
from django.http import HttpResponse def index(request): return HttpResponse("Hello, world!")
6.2.3 mypage/urls.py には以下を記述します
from django.urls import path from . import views urlpatterns = [ path('', views.index, name='index'), ]
6.2.4 mytest001/urls.py に 以下の変更を行う
- django.urls.include のimportを追加
- urlpatterns のリストに include() を挿入
- ルートディレクトリへのアクセスは /mypage/ にリダイレクト(https://docs.djangoproject.com/en/2.2/ref/class-based-views/base/)
from django.contrib import admin from django.urls import include, path from django.views.generic.base import RedirectView urlpatterns = [ path('mypage/', include('mypage.urls')), path('', RedirectView.as_view(url='/mypage/')), path('admin/', admin.site.urls), ]
6.2.5 サーバーを起動しブラウザで確認
- 以下でサーバー起動
python manage.py runserver
- http://localhost:8000/mypage/ あるいは http://localhost:8000/ にアクセスすると “Hello, world!” と表示されます。
7 djangoアプリ3(テンプレートの利用)
- 本家の文書だとhttps://docs.djangoproject.com/ja/2.2/intro/tutorial03/に詳しい文書があります。
- 前章のHello Worldアプリを改造して、テンプレートを利用した表示を行います
7.1 以下の操作を行っている動画
7.2 テンプレートファイルを利用して表示させるための手順
7.2.1 テンプレートファイルを入れるディレクトリの準備
- プロジェクトのルート(manage.py があるディレクトリにあるmypageディレクトリ)に templates/mypage ディレクトリを作成します。
- 以下のコマンド実行前に プロジェクトのルート(manage.py があるディレクトリ)に移動してから実行
mkdir -p mypage/templates/mypage
7.2.2 プロジェクトのセッティング修正
- INSTALLED_APPS 以外の部分は変更しないでください。
- mytest001/settings.py の INSTALLED_APPS に ‘mypage.apps.MypageConfig’, を追加
- これを行うことで、テンプレートファイルの検索パスにmypageが含まれるようになります。
... 省略 # Application definition INSTALLED_APPS = [ 'mypage.apps.MypageConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ] ... 省略
7.2.3 テンプレートファイル用意
- 今回はemacsのorgモードを利用して自動生成したhtmlをベースに改造して以下を作成しました。
- 以下の内容をmypage/templates/mypage/index.html として保存します。
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <title>djangoの始め方</title> </head> <body> <h1 class="title">djangoの始め方</h1> </body> </html>
7.2.4 表示部分の改造
- mypage/views.py を以下の内容に変更します
from django.http import HttpResponse from django.template import loader def index(request): template = loader.get_template('mypage/index.html') context = {} return HttpResponse(template.render(context, request))
7.2.5 サーバーを起動しブラウザで確認
- 以下でサーバー起動
python manage.py runserver
7.3 この章まとめ
- テンプレートファイルを利用して表示できる手順を説明
8 djangoアプリ4(計算アプリ)
- フォームを利用して、計算結果(足し算)をテンプレートで表示
- 本家で関係する文書1 フォームAPI https://docs.djangoproject.com/ja/2.2/ref/forms/api/
- 本家で関係する文書2 フォームとフィールドの検証 https://docs.djangoproject.com/ja/2.2/ref/forms/validation/
- 本家で関係する文書3 Form fields https://docs.djangoproject.com/ja/2.2/ref/forms/fields/
- 本家で関係する文書4 バリデータ https://docs.djangoproject.com/ja/2.2/ref/validators/
8.1 以下の操作を行っている動画
8.2 djangoアプリ4(計算アプリ)作成手順
8.2.1 プロジェクトとmycalcアプリのベース作成
- 今回はmytest002という名前で新規に作っていきます。
django-admin startproject mytest002
cd mytest002
python manage.py startapp mycalc
8.2.2 プロジェクトのセッティング修正
- INSTALLED_APPS 以外の部分は変更しないでください。
- mytest002/settings.py の INSTALLED_APPS に ‘mycalc.apps.MypageConfig’, を追加
- これを行うことで、テンプレートファイルの検索パスにmycalcが含まれるようになります。
... 省略 # Application definition INSTALLED_APPS = [ 'mycalc.apps.MycalcConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ] ... 省略
8.2.3 テンプレートファイルを入れるディレクトリの準備
mkdir -p mycalc/templates/mycalc
8.2.4 テンプレートファイル用意
- 以下の内容をmycalc/templates/mycalc/index.html として保存します。
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <title>計算アプリ</title> </head> <body> <form action="" method="POST"> <table> {{ form.as_table }} </table> {% csrf_token %} <button type="submit">計算</button> </form> {% if ans != "" %} {{ ans }} </br> {% endif %} </body> </html>
8.2.5 mycalc/form.py を作成
from django import forms class numForm(forms.Form): num1 = forms.DecimalField(label='num1', initial=2, required=True) num2 = forms.DecimalField(label='num2', initial=1, required=True)
8.2.6 mycalc/views.py を以下に変更します。
from django.shortcuts import render from .form import numForm def index(request): if request.method == 'POST': form = numForm(request.POST) if form.is_valid(): # print(request.POST) # print(form.cleaned_data['num1']) # print(form.cleaned_data['num2']) # return HttpResponseRedirect('/answer/') # print([form.cleaned_data['num1'],form.cleaned_data['num2']]) n1=int(form.cleaned_data['num1']) n2=int(form.cleaned_data['num2']) ans=str(n1)+" + "+str(n2)+" = "+str(n1+n2) # print(ans) else: form=numForm() ans="" return render(request,'mycalc/index.html',{'form':form, 'ans' : ans})
8.2.7 mycalc/urls.py には以下を記述します
from django.urls import path from . import views urlpatterns = [ path('', views.index, name='index'), ]
8.2.8 mytest002/urls.py に 以下の変更を行う
- django.urls.include のimportを追加
- urlpatterns のリストに include() を挿入
- ルートディレクトリへのアクセスは /mypage/ にリダイレクト(https://docs.djangoproject.com/en/2.2/ref/class-based-views/base/)
from django.contrib import admin from django.urls import include, path from django.views.generic.base import RedirectView urlpatterns = [ path('mycalc/', include('mycalc.urls')), path('', RedirectView.as_view(url='/mycalc/')), path('admin/', admin.site.urls), ]
8.2.9 サーバーを起動しブラウザで確認
- 以下でサーバー起動
python manage.py runserver
8.3 この章まとめ
- 整数を2つ入力して、足し算結果を返すアプリの作成(JavaScriptで作った方が楽っぽいけど)
- formの使い方の基礎を確認
9 djangoアプリ5(ファイルアップロード)
- ファイルをアップロード
- 本家で関係する文書1 https://docs.djangoproject.com/ja/2.2/topics/http/file-uploads/
9.1 以下の操作を行っている動画
9.2 djangoアプリ5(ファイルアップロード)作成手順
9.2.1 プロジェクトとmyfile_uploadアプリのベース作成
- 今回はmytest003という名前で新規に作っていきます。
django-admin startproject mytest003
cd mytest003
python manage.py startapp myfile_upload
9.2.2 プロジェクトのセッティング修正
- INSTALLED_APPS 以外の部分は変更しないでください。
- mytest003/settings.py の INSTALLED_APPS に ‘myfileUpload.apps.MypageConfig’, を追加
- これを行うことで、テンプレートファイルの検索パスにmyfile_uploadが含まれるようになります。
... 省略 # Application definition INSTALLED_APPS = [ 'myfile_upload.apps.MyfileUploadConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ] ... 省略
9.2.3 myfile_upload/urls.py には以下を記述します
from django.urls import path from . import views urlpatterns = [ path('', views.upload_file, name='index'), ]
9.2.4 mytest003/urls.py に 以下の変更を行う
- django.urls.include のimportを追加
- urlpatterns のリストに include() を挿入
- ルートディレクトリへのアクセスは /mypage/ にリダイレクト(https://docs.djangoproject.com/en/2.2/ref/class-based-views/base/)
from django.contrib import admin from django.urls import include, path from django.views.generic.base import RedirectView import myfile_upload.views as myfile_upload urlpatterns = [ path('success/url/',myfile_upload.success), path('myfile_upload/', include('myfile_upload.urls')), path('', RedirectView.as_view(url='/myfile_upload/')), path('admin/', admin.site.urls), ]
9.2.5 テンプレートファイルを入れるディレクトリの準備
mkdir -p myfile_upload/templates/myfile_upload
9.2.6 テンプレートファイル1用意
- 以下の内容をmyfile_upload/templates/myfile_upload/index.html として保存します。
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <title>ファイルアップロードアプリ</title> </head> <body> <form action="" method="POST" enctype="multipart/form-data"> <table> {{ form.as_table }} </table> {% csrf_token %} <button type="submit">ファイルアップロード実行</button> </form> </body> </html>
9.2.7 テンプレートファイル2(成功時用)用意
- 以下の内容をmyfile_upload/templates/myfile_upload/success.html として保存します。
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <title>ファイルアップロードアプリ</title> </head> <body> <h1>ファイルのアップロードに成功しました!</h1> </body> </html>
9.2.8 myfile_upload/forms.py を作成
from django import forms class UploadFileForm(forms.Form): # title = forms.CharField(max_length=50) file = forms.FileField()
9.2.9 myfile_upload/views.py を以下に変更します。
from django.http import HttpResponseRedirect from django.shortcuts import render from .forms import UploadFileForm # Imaginary function to handle an uploaded file. # from somewhere import handle_uploaded_file def upload_file(request): if request.method == 'POST': form = UploadFileForm(request.POST, request.FILES) if form.is_valid(): handle_uploaded_file(request.FILES['file']) return HttpResponseRedirect('/success/url/') else: form = UploadFileForm() return render(request, 'myfile_upload/index.html', {'form': form}) def handle_uploaded_file(f): fname='files/'+f.name print("fname:"+fname) with open(fname, 'wb+') as destination: for chunk in f.chunks(): destination.write(chunk) def success(request): return render(request, 'myfile_upload/success.html', {})
9.2.10 ファイル保管用のディレクトリ作成
mkdir -p files
9.2.11 サーバーを起動しブラウザで確認
- 以下でサーバー起動
python manage.py runserver
9.3 この章まとめ
- ファイルのアップロードを行う方法を確認
10 urlでのパラメータ渡し
- urlでパラメーターを渡して、処理を行わせる
- djangoアプリ4(計算アプリ)をベースに改造(結果表示を別urlにリダイレクト)
- フォームを利用して、計算結果(足し算)をテンプレートで表示
- 本家で関係する文書1 https://docs.djangoproject.com/ja/2.2/intro/tutorial03/
- 本家で関係する文書2 URL ディスパッチャ https://docs.djangoproject.com/ja/2.2/topics/http/urls/
- 本家で関係する文書3 組み込みタグとフィルタ https://docs.djangoproject.com/ja/2.2/ref/templates/builtins/
- stack overflow <int:ではマイナスの整数にマッチしない件 https://stackoverflow.com/questions/48867977/django-2-url-path-matching-negative-value/48868140
10.1 以下の操作を行っている動画
10.2 djangoアプリ4(計算アプリ)の改造手順
10.2.1 mycalc/urls.py を以下に修正
- <int: だとマイナスの数値にマッチしてくれないため、re_pathで正規表現マッチを利用 (?P<name>pattern)
from django.urls import path, re_path from . import views urlpatterns = [ path('', views.index, name='index'), # ex: /mycalc/5/6/results/ # path('<int:num1>/<int:num2>/results/', views.results, name='results'), # ex: /mycalc/5/-1/4/results/ re_path(r'^(?P<num1>-?\d+)/(?P<num2>-?\d+)/(?P<num3>-?\d+)/results/$', views.results, name='results'), ]
10.2.2 mycalc/views.py を以下に変更します。
from django.shortcuts import render, redirect from .form import numForm from django.views.generic.base import RedirectView def index(request): if request.method == 'POST': form = numForm(request.POST) if form.is_valid(): n1=int(form.cleaned_data['num1']) n2=int(form.cleaned_data['num2']) return redirect(str(n1)+'/'+str(n2)+'/'+str(n1+n2)+'/results/') else: form=numForm() return render(request,'mycalc/index.html',{'form':form}) def results(request, num1, num2, num3): return render(request,'mycalc/results.html',{'num1':num1, 'num2':num2, 'num3':num3})
10.2.3 元のテンプレートファイルを修正
- mycalc/templates/mycalc/index.html を以下に修正
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <title>計算アプリ</title> </head> <body> <form action="" method="POST"> <table> {{ form.as_table }} </table> {% csrf_token %} <button type="submit">計算</button> </form> </body> </html>
10.2.4 結果表示用のテンプレートファイル作成
- mycalc/templates/mycalc/results.html を以下の内容で作る
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <title>計算アプリ 計算結果</title> </head> <body> {{ num1 }} + {{ num2 }} = {{ num3 }} </br> {{ num1 }} + {{ num2 }} = {{ num1|add:num2 }} </br> <a href="/mycalc/">計算設定画面へ</a> </form> </body> </html>
10.2.5 サーバーを起動しブラウザで確認
- 以下でサーバー起動
python manage.py runserver
10.3 この章まとめ
- urlでのパラメーター渡し
- 正規表現を利用したマッチも利用
- 組み込みタグとフィルタの活用
11 カスタムフィルタ
- カスタムフィルタを利用
- djangoアプリ4(計算アプリ)改造バージョンをベースに更に改造
- 本家で関係する文書1 独自のテンプレートタグとフィルタ https://docs.djangoproject.com/ja/2.2/howto/custom-template-tags/
11.1 以下の操作を行っている動画
11.2 カスタムフィルタの作成手順
11.2.1 カスタムフィルタ保存用のフォルダ作成
mkdir -p mycalc/templatetags
11.2.2 カスタムフィルタ用ファイルの作成
- touchコマンドで空の__init__.pyを作成してます。エディタで空の__init__.pyを作成してもOK
touch mycalc/templatetags/__init__.py
- mycalc/templatetags/mysub.py を以下の内容で作成
from django import template register = template.Library() @register.filter("mysub") def mysub(value, arg): return int(value)-int(arg) @register.filter("mymul") def mymul(value, arg): return int(value)*int(arg) @register.filter("mydiv") def mydiv(value, arg): return int(value)/int(arg) @register.filter("mymod") def mymod(value, arg): return int(value)%int(arg)
11.2.3 結果表示用のテンプレートファイル修正
- mycalc/templates/mycalc/results.html を以下の内容で作る
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <title>計算アプリ 計算結果</title> </head> <body> {{ num1 }} + {{ num2 }} = {{ num3 }} </br> {{ num1 }} + {{ num2 }} = {{ num1|add:num2 }} </br> {% load mysub %} {{ num1 }} - {{ num2 }} = {{ num1|mysub:num2 }} </br> {{ num1 }} * {{ num2 }} = {{ num1|mymul:num2 }} </br> {{ num1 }} / {{ num2 }} = {{ num1|mydiv:num2 }} </br> {{ num1 }} % {{ num2 }} = {{ num1|mymod:num2 }} </br> <a href="/mycalc/">計算設定画面へ</a> </form> </body> </html>
11.2.4 サーバーを起動しブラウザで確認
- 以下でサーバー起動
python manage.py runserver
11.3 この章まとめ
- カスタムフィルタを作成し利用してみた
12 セッション(session)関係の機能を試してみる
- djangoアプリ5(ファイルアップロード mytest003)をベースに改造してセッション使ってみます
- アップロードファイルのファイル名をセッション関係の機能を用いてサーバー側に保存し、成功画面でファイル名を表示
- 同じ名前のファイルを複数アップロードした場合でも不具合が発生しないように、テンポラリーファイル(一時ファイル)で書き込み
- 本家で関係する文書1 セッションの使い方 https://docs.djangoproject.com/ja/2.2/topics/http/sessions/
- 本家で関係する文書2 セッションのセキュリティ https://docs.djangoproject.com/ja/2.2/topics/security/#session-security
- 本家で関係する文書3 セッション https://docs.djangoproject.com/ja/2.2/ref/settings/#sessions
12.1 以下の操作を行っている動画
12.2 djangoアプリ5(ファイルアップロード mytest003)の改造手順
12.2.1 マイグレートを行う
- セッション機能を利用するのに必用(デフォルトのセッションの設定の場合、データベースを利用するため)
python manage.py migrate
12.2.2 テンプレートファイル2(成功時用)を改造
- myfile_upload/templates/myfile_upload/success.html を以下の内容に変更
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <title>ファイルアップロードアプリ</title> </head> <body> <h1>ファイル {{ orgfilename }} を {{ dfilename }} として、アップロードすることに成功しました!</h1> </body> </html>
12.2.3 myfile_upload/views.py を以下に変更します。
- テンポラリファイルを利用するように変更
- success画面で、セッションに保存したファイル名を利用する様に変更
- セッションでの値の保存は request.session[‘名前’]=値
- 保存していたセッションでの値の取り出し request.session[‘名前’]
from django.http import HttpResponseRedirect from django.shortcuts import render from .forms import UploadFileForm import tempfile # Imaginary function to handle an uploaded file. # from somewhere import handle_uploaded_file def upload_file(request): if request.method == 'POST': form = UploadFileForm(request.POST, request.FILES) if form.is_valid(): tfname=handle_uploaded_file(request.FILES['file']) request.session['org_fname']=request.FILES['file'].name request.session['tmp_fname']=tfname return HttpResponseRedirect('/success/url/') else: form = UploadFileForm() return render(request, 'myfile_upload/index.html', {'form': form}) def handle_uploaded_file(f): # fname='files/'+f.name tfname="" # print("fname:"+fname) # with open(fname, 'wb+') as destination: with tempfile.NamedTemporaryFile(mode='wb+',delete=False) as destination: tfname=destination.name print(tfname) for chunk in f.chunks(): destination.write(chunk) return tfname def success(request): return render(request, 'myfile_upload/success.html', {'orgfilename':request.session['org_fname'], 'dfilename':request.session['tmp_fname']})
12.2.4 サーバーを起動しブラウザで確認
- 以下でサーバー起動
python manage.py runserver
12.3 この章まとめ
- セッション関係の機能を利用
- 一時ファイル(tempfile)を利用
13 カスタムユーザーの作成(AbstractUserを継承タイプ)
- デフォルトのユーザーを利用せずにカスタムユーザーを利用した方が良いらしいので、それをやってみます
- 本家で関係する文書1 プロジェクトの開始時にカスタムのユーザーモデルを使用する https://docs.djangoproject.com/ja/2.2/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project
- AUTH_USER_MODEL に指定する( 指定するものは INSTALLED_APPS に含まれている必要あり )
- 最初に実行する manage.py migrate の前に行う
- モデルをアプリの admin.py に登録
- 本家で関係する文書2 Django の認証方法のカスタマイズ https://docs.djangoproject.com/ja/2.2/topics/auth/customizing/
- プロジェクト途中からのカスタムユーザーモデルへの変更は面倒
- 再利用可能アプリはカスタムのユーザーモデルを実装するべきでない
- 本家で関係する文書3 Django でのユーザー認証 https://docs.djangoproject.com/ja/2.2/topics/auth/
- 本家で関係する文書4 Djangoの認証システムを使用する https://docs.djangoproject.com/ja/2.2/topics/auth/default/
- AUTH_USER_MODEL をデータベーステーブルの作成後に変更することは、たとえば、外部キーや多対多の関係に影響するため、非常に困難となります。
- 本家で関係する文書4 はじめての Django アプリ作成、その2 https://docs.djangoproject.com/ja/2.2/intro/tutorial02/
- 関係するインストールしたpythonファイル (ローカルの~/python3/にインストールした場合) ~/python3/dist-packages/django/contrib/auth/models.py
13.1 以下の操作を行っている動画
13.2 カスタムユーザー設定(AbstractUserを継承タイプ)を行ってプロジェクトを始める手順
13.2.1 mytest004というアプリを作成し、その中にmyuserというアプリケーションを作成
django-admin startproject mytest004
cd mytest004
python manage.py startapp myuser
13.2.2 mytest004/settings.py 修正
- INSTALLED_APPS に ‘myuser’, を追加
- AUTH_USER_MODEL = ‘myuser.User’ を追加
... 省略 # Application definition INSTALLED_APPS = [ 'mypage.apps.MypageConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'myuser', ] AUTH_USER_MODEL = 'myuser.User' ... 省略
13.2.3 myuser/models.py 修正
- 「pass はヌル操作 (null operation) です — pass が実行されても、何も起きません。 pass は、構文法的には文が必要だが、コードとしては何も実行したくない場合のプレースホルダとして有用です。」 https://docs.python.org/ja/3/reference/simple_stmts.html#pass から引用
- 後でUserを修正してカスタマイズ出来ます
# from django.db import models from django.contrib.auth.models import AbstractUser class User(AbstractUser): pass
13.2.4 myuser/admin.py 修正
rom django.contrib import admin from django.contrib.auth.admin import UserAdmin from .models import User admin.site.register(User, UserAdmin)
13.2.5 migration作成、適用
python manage.py makemigrations python manage.py migrate
13.2.6 superuserを作成
python manage.py createsuperuser
- 以下の感じで、ユーザーネーム、メールアドレスを入れて(ここでメールアドレスは適当なもにしてます、わたしのメールアドレスではありません)
Username: admin Email address: xxx@xxx.xxx Password: Password (again):
- パスワードが簡単すぎると以下のようなメッセージが表示されます、以下の例では強引にそれを認めさせてます
This password is too short. It must contain at least 8 characters. This password is too common. This password is entirely numeric. Bypass password validation and create user anyway? [y/N]: y
- パスワード2つ入力したものが異なると以下のメッセージが出ます。そのときは再度2回同じパスワードを入れてください
Error: Your passwords didn't match.
13.2.7 サーバーを起動しブラウザで確認
- 以下でサーバー起動
python manage.py runserver
- http://localhost:8000/admin/ にアクセスして、設定した管理者権限のユーザー名とパスワードでログインします
13.3 この章まとめ
- プロジェクト開始時にカスタムユーザー作成
14 カスタムユーザーの作成2(AbstractBaseUserを継承タイプ)
- 前章はAbstractUserを継承していましたが、今回はより自由度が高くなるAbstractBaseUserを継承
- myuser/models.py 修正する箇所が異なるのみで、他はほぼ一緒
- 本家で関係する文書 は前章と同じになります。
- 関係するインストールしたpythonファイル (ローカルの~/python3/にインストールした場合) ~/python3/dist-packages/django/contrib/auth/models.py
14.1 以下の操作を行っている動画
14.2 カスタムユーザー設定(AbstractBaseUserを継承タイプ)を行ってプロジェクトを始める手順
14.2.1 mytest005というアプリを作成し、その中にmyuserというアプリケーションを作成
django-admin startproject mytest005
cd mytest005
python manage.py startapp myuser
14.2.2 mytest005/settings.py 修正
- INSTALLED_APPS に ‘myuser’, を追加
- AUTH_USER_MODEL = ‘myuser.User’ を追加
... 省略 # Application definition INSTALLED_APPS = [ 'myuser', 'mypage.apps.MypageConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ] AUTH_USER_MODEL = 'myuser.User' ... 省略
14.2.3 mytest005/settings.py 修正2
- ローカライズの修正も行います。(今回特に必用ないけど)
- LANGUAGE_CODE を ‘en-us’ から ‘ja’に変更
- TIME_ZONE を ‘UTC’ から ‘Asia/Tokyo’ に変更
... 省略 LANGUAGE_CODE = 'ja' TIME_ZONE = 'Asia/Tokyo' ... 省略
14.2.4 myuser/models.py 修正
- 関係するインストールしたpythonファイル (ローカルの~/python3/にインストールした場合) ~/python3/dist-packages/django/contrib/auth/models.py をベースに削って作成。修正内容は以下の感じ
- 関係しそうなimportのみを残す
- from django.contrib.auth.models import PermissionsMixin, UserManager を追加(オリジナルの PermissionsMixin, UserManagerを利用するため)
- from django.contrib.auth.validators import UnicodeUsernameValidator を追加
- AbstractUser 部分をコピペ
- クラス名をUserに変更
- abstract = True をコメントアウト
- 後で修正してカスタマイズ可能
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager from django.core.mail import send_mail from django.db import models from django.utils import timezone from django.utils.translation import gettext_lazy as _ from django.contrib.auth.models import PermissionsMixin, UserManager from django.contrib.auth.validators import UnicodeUsernameValidator class User(AbstractBaseUser, PermissionsMixin): """ An abstract base class implementing a fully featured User model with admin-compliant permissions. Username and password are required. Other fields are optional. """ username_validator = UnicodeUsernameValidator() username = models.CharField( _('username'), max_length=150, unique=True, help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'), validators=[username_validator], error_messages={ 'unique': _("A user with that username already exists."), }, ) first_name = models.CharField(_('first name'), max_length=30, blank=True) last_name = models.CharField(_('last name'), max_length=150, blank=True) email = models.EmailField(_('email address'), blank=True) is_staff = models.BooleanField( _('staff status'), default=False, help_text=_('Designates whether the user can log into this admin site.'), ) is_active = models.BooleanField( _('active'), default=True, help_text=_( 'Designates whether this user should be treated as active. ' 'Unselect this instead of deleting accounts.' ), ) date_joined = models.DateTimeField(_('date joined'), default=timezone.now) objects = UserManager() EMAIL_FIELD = 'email' USERNAME_FIELD = 'username' REQUIRED_FIELDS = ['email'] class Meta: verbose_name = _('user') verbose_name_plural = _('users') # abstract = True def clean(self): super().clean() self.email = self.__class__.objects.normalize_email(self.email) def get_full_name(self): """ Return the first_name plus the last_name, with a space in between. """ full_name = '%s %s' % (self.first_name, self.last_name) return full_name.strip() def get_short_name(self): """Return the short name for the user.""" return self.first_name def email_user(self, subject, message, from_email=None, **kwargs): """Send an email to this user.""" send_mail(subject, message, from_email, [self.email], **kwargs)
14.2.5 myuser/admin.py 修正
from django.contrib import admin from django.contrib.auth.admin import UserAdmin from .models import User admin.site.register(User, UserAdmin)
14.2.6 migration作成、適用
python manage.py makemigrations python manage.py migrate
14.2.7 superuserを作成
- 質問に答えていって、作成
- 実際の途中の様子は前章参照
python manage.py createsuperuser
14.2.8 サーバーを起動しブラウザで確認
- 以下でサーバー起動
python manage.py runserver
- http://localhost:8000/admin/ にアクセスして、設定した管理者権限のユーザー名とパスワードでログインします
14.3 この章まとめ
- プロジェクト開始時にカスタムユーザー作成
15 郵便番号検索アプリの作成
- 下の郵便番号のデータの説明 https://www.post.japanpost.jp/zipcode/dl/readme.html
- 関係する本家の文書1 モデルに対する初期データを投入する https://docs.djangoproject.com/ja/2.2/howto/initial-data/
- 関係する本家の文書2 django-admin と manage.py https://docs.djangoproject.com/ja/2.2/ref/django-admin/
- 関係する本家の文書3 QuerySet API reference https://docs.djangoproject.com/ja/2.2/ref/models/querysets/
- 関係する本家の文書4 Field lookups https://docs.djangoproject.com/ja/2.2/ref/models/querysets/#field-lookups
- 関係する本家の文書5 クエリを作成する https://docs.djangoproject.com/ja/2.2/topics/db/queries/
- 関係する本家の文書6 検索 https://docs.djangoproject.com/ja/2.2/topics/db/search/
- 関係する本家の文書7 クエリー式 https://docs.djangoproject.com/ja/2.2/ref/models/expressions/
- 関係する本家の文書8 素の SQL 文の実行 https://docs.djangoproject.com/ja/2.2/topics/db/sql/
- 関係する本家の文書9 Qオブジェクト https://docs.djangoproject.com/ja/2.2/ref/models/querysets/#django.db.models.Q
- 関係する本家の文書10 Q オブジェクトを用いた複雑な検索 https://docs.djangoproject.com/ja/2.2/topics/db/queries/#complex-lookups-with-q
- 関係する本家の文書11 distinct(*fields) https://docs.djangoproject.com/ja/2.2/ref/models/querysets/#django.db.models.query.QuerySet.distinct
15.1 以下の操作を行っている動画
15.2 郵便番号csvデータの取得と準備
15.2.1 データの取得が面倒な方は ken_all_utf_wh.json として以下を保存
- 3つのデータのみ入っているデータ
[ { "model": "zipcodes.zipcode", "pk": 1, "fields": { "jisx": "01101", "zipold": "060 ", "zip": "0600000", "prefecture": "ホッカイドウ", "city": "サッポロシチュウオウク", "street": "イカニケイサイガナイバアイ", "kprefecture": "北海道", "kcity": "札幌市中央区", "kstreet": "以下に掲載がない場合", "c1": "0", "c2": "0", "c3": "0", "c4": "0", "c5": "0", "c6": "0" } }, { "model": "zipcodes.zipcode", "pk": 79393, "fields": { "jisx": "26104", "zipold": "604 ", "zip": "6048182", "prefecture": "キョウトフ", "city": "キョウトシナカギョウク", "street": "オオサカザイモクチョウ", "kprefecture": "京都府", "kcity": "京都市中京区", "kstreet": "大阪材木町", "c1": "0", "c2": "0", "c3": "0", "c4": "0", "c5": "0", "c6": "0" } }, { "model": "zipcodes.zipcode", "pk": 124340, "fields": { "jisx": "47382", "zipold": "90718", "zip": "9071801", "prefecture": "オキナワケン", "city": "ヤエヤマグンヨナグニチョウ", "street": "ヨナグニ", "kprefecture": "沖縄県", "kcity": "八重山郡与那国町", "kstreet": "与那国", "c1": "0", "c2": "0", "c3": "0", "c4": "0", "c5": "0", "c6": "0" } } ]
15.2.2 データの取得
- 郵便番号と住所のデータの準備が面倒な方は上のken_all_utf_wh.jsonを準備してスキップ可
- ブラウザでダウンロードしに行く場合
- 郵便番号csvデータダウンロードサイト https://www.post.japanpost.jp/zipcode/dl/kogaki-zip.html
- 郵便局の番号データ(郵便局様) https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/ken_all.zip
- wgetを利用してのダウンロードする場合
- データと、データの説明ページをダウンロードしてます
wget "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/ken_all.zip" wget "https://www.post.japanpost.jp/zipcode/dl/readme.html"
- unarを利用してzipファイルを解凍する場合
- unar以外のツールでzipを解凍してもOK
- KEN_ALL.CSV を取り出せます
unar ken_all.zip
- 文字コードをユニコードに変換(nkfを利用する場合)
- 複数の文字コードを変換できるエディタや、ツールを利用してもOK
- ここではnkfコマンドでやってみます。
- 環境がユニコードなら以下でOK
- 作成したファイル名は ken_all_utf.csv
nkf KEN_ALL.CSV > ken_all_utf.csv
**
- 1行目に各列のデータ名をつける
jisx,zipold,zip,prefecture,city,street,kprefecture,kcity,kstreet,c1,c2,c3,c4,c5,c6
- echo と cat コマンドで行うと以下の感じ、普通のエディタで上の1行をデータの頭に入れてもOK
echo "jisx,zipold,zip,prefecture,city,street,kprefecture,kcity,kstreet,c1,c2,c3,c4,c5,c6" > ken_all_head.csv cat ken_all_head.csv ken_all_utf.csv > ken_all_utf_wh.csv
- csvをjsonデータに変換
- 他のツールを使ってもOK
- 以下の内容のpythonファイルを作成し、convert.pyという名前で保存
import csv import json with open('ken_all_utf_wh.csv', 'r') as f: r = csv.DictReader(f) c = 1 a=[] for row in r: a.append({"model" : "zipcodes.zipcode", "pk" : c, 'fields' : row }) c=c+1 print(json.dumps(a, ensure_ascii=False, indent=2))
- 以下を実行すると ken_all_utf_wh.csv(ヘッダー追加してユニコードにしたcsvファイル)をjson形式に変換し ken_all_utf_wh.json として保存
python convert.py > ken_all_utf_wh.json
15.3 郵便番号検索アプリの作成手順
15.3.1 myzipcodes というアプリを作成し、その中にmyappというアプリケーションを作成
- カスタムユーザーを最初に追加した方が後々カスタムユーザーを使う時に便利になりますが、説明上カスタムユーザーを追加せずに作って行きます。(前章を参考にカスタムユーザーを作っておく方が良い。)
django-admin startproject myzipcodes
cd myzipcodes
python manage.py startapp zipcodes
15.3.2 myzipcodes/settings.py 修正
- INSTALLED_APPS に ‘zipcodes.apps.ZipcodesConfig’, を追加
... 省略 # Application definition INSTALLED_APPS = [ 'zipcodes.apps.ZipcodesConfig', 'mypage.apps.MypageConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ] ... 省略
15.3.3 myzipcodes/settings.py 修正2
- ローカライズの修正も行います。(今回特に必用ないけど)
- LANGUAGE_CODE を ‘en-us’ から ‘ja’に変更
- TIME_ZONE を ‘UTC’ から ‘Asia/Tokyo’ に変更
... 省略 LANGUAGE_CODE = 'ja' TIME_ZONE = 'Asia/Tokyo' ... 省略
15.3.4 zipcodes/models.py 修正
from django.db import models class Zipcode(models.Model): jisx = models.CharField(max_length=20) zipold = models.CharField(max_length=10) zip = models.CharField(max_length=10) prefecture = models.CharField(max_length=200) city = models.CharField(max_length=200) street = models.CharField(max_length=200) kprefecture = models.CharField(max_length=200) kcity = models.CharField(max_length=200) kstreet = models.CharField(max_length=200) c1 = models.CharField(max_length=10) c2 = models.CharField(max_length=10) c3 = models.CharField(max_length=10) c4 = models.CharField(max_length=10) c5 = models.CharField(max_length=10) c6 = models.CharField(max_length=10)
15.3.5 zipcodes/admin.py 修正
- Zipcodeを管理サイトに登録(これで管理メニューでzipcodeをいじれます)
from django.contrib import admin from .models import Zipcode admin.site.register(Zipcode)
15.3.6 migration作成、適用
python manage.py makemigrations python manage.py migrate
15.3.7 郵便局から得たcsvファイルを前節で加工して生成した ken_all_utf_wh.json ファイルをデータベースに読み込み
python manage.py loaddata ../ken_all_utf_wh.json
15.3.8 zipcodes/views.py を以下に修正
from django.shortcuts import render, get_object_or_404, get_list_or_404 from .models import Zipcode from django.db.models import Q def getAddress(request,zipcode): d=get_list_or_404(Zipcode, zip__regex=zipcode) return render(request, 'zipcodes/getAddress.html', {'zipcode':zipcode, 'd':d}) def getZipcodesStreet(request,s): d=get_list_or_404(Zipcode, kstreet__regex=s) return render(request, 'zipcodes/getZipcodes.html', {'s':s, 'x':"町域名", 'd':d}) def getZipcodesCity(request,s): d=get_list_or_404(Zipcode, kcity__regex=s) return render(request, 'zipcodes/getZipcodes.html', {'s':s, 'x':"市区町村名", 'd':d}) def getZipcodesPrefecture(request,s): d=get_list_or_404(Zipcode, kprefecture__regex=s) return render(request, 'zipcodes/getZipcodes.html', {'s':s, 'x':"都道府県名", 'd':d}) def getZipcodesOr(request,s): d=get_list_or_404(Zipcode, Q(kprefecture__regex=s)|Q(kcity__regex=s)|Q(kstreet__regex=s)) return render(request, 'zipcodes/getZipcodes.html', {'s':s, 'x':"都道>府県名あるいは市区町村名あるいは町域名", 'd':d})
15.3.9 zipcodes/templates/zipcodes/getAddress.html を作成
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <title>郵便番号{{zipcode}}を含む住所</title> </head> <body> <h1>郵便番号{{zipcode}}を含む住所</h1> {% for a in d %} <li>{{ a.zip }} {{ a.kprefecture}} {{ a.kcity }} {{ a.kstreet }}</a></li> {% endfor %} </body> </html>
15.3.10 zipcodes/templates/zipcodes/getZipcodes.html を作成
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <title>"{{s}}"を"{{x}}"に含む住所</title> </head> <body> <h1>"{{s}}"を"{{x}}"に含む住所</h1> {% for a in d %} <li>{{ a.zip }} {{ a.kprefecture}} {{ a.kcity }} {{ a.kstreet }}</a></li> {% endfor %} </body> </html>
15.3.11 myzipcodes/urls.py を以下に修正
from django.contrib import admin from django.urls import path, re_path from zipcodes import views as zviews urlpatterns = [ path('admin/', admin.site.urls), re_path(r'^zip/(?P<zipcode>\d{1,7})$', zviews.getAddress, name="getAddress"), re_path(r'^street/(?P<s>.+)$', zviews.getZipcodesStreet, name="getZipcodesStreet"), re_path(r'^city/(?P<s>.+)$', zviews.getZipcodesCity, name="getZipcodesCity"), re_path(r'^prefecture/(?P<s>.+)$', zviews.getZipcodesPrefecture, name="getZipcodesPrefecture"), re_path(r'^address/(?P<s>.+)$', zviews.getZipcodesOr, name="getZipcodesPrefecture"), ]
15.3.12 サーバーを起動しブラウザで確認
15.4 この章でのまとめ
- データベースとの連携機能の利用
- データベースへのデータのインポート
- 今までの章でやってきたテクの利用
16 djangoのshellの活用
- 関係する本家の文書1 はじめての Django アプリ作成、その2 https://docs.djangoproject.com/ja/2.2/intro/tutorial02/
- 関係する本家の文書2 django-admin と manage.py https://docs.djangoproject.com/ja/2.2/ref/django-admin/
- 関係する本家の文書3 QuerySet API reference https://docs.djangoproject.com/ja/2.2/ref/models/querysets/
- 関係する本家の文書4 Field lookups https://docs.djangoproject.com/ja/2.2/ref/models/querysets/#field-lookups
- 関係する本家の文書5 クエリを作成する https://docs.djangoproject.com/ja/2.2/topics/db/queries/
- 関係する本家の文書6 検索 https://docs.djangoproject.com/ja/2.2/topics/db/search/
- 関係する本家の文書7 クエリー式 https://docs.djangoproject.com/ja/2.2/ref/models/expressions/
- 関係する本家の文書8 素の SQL 文の実行 https://docs.djangoproject.com/ja/2.2/topics/db/sql/
- 関係する本家の文書9 Qオブジェクト https://docs.djangoproject.com/ja/2.2/ref/models/querysets/#django.db.models.Q
- 関係する本家の文書10 Q オブジェクトを用いた複雑な検索 https://docs.djangoproject.com/ja/2.2/topics/db/queries/#complex-lookups-with-q
- 関係する本家の文書11 distinct(*fields) https://docs.djangoproject.com/ja/2.2/ref/models/querysets/#django.db.models.query.QuerySet.distinct
16.1 以下の操作を行っている動画
16.2 動画で出てくる操作
- 操作は一つ前の章で使った郵便番号検索アプリで行ってます
16.2.1 dangoのシェルの起動
- 郵便番号アプリのプロジェクトのベースディレクトリ(manage.pyがあるディレクトリ)にはいってから
python manage.py shell
- 現状やると以下の画面に
$ python manage.py shell Python 3.7.5 (default, Nov 20 2019, 09:21:52) Type "copyright", "credits" or "license" for more information. IPython 5.8.0 -- An enhanced Interactive Python. ? -> Introduction and overview of IPython's features. %quickref -> Quick reference. help -> Python's own help system. object? -> Details about 'object', use 'object??' for extra details. In [1]:
16.2.2 モデルクラスのimport
- 郵便番号検索アプリの場合は Zipcode クラスをimport
- import のfromの部分は、アプリ名とmodelsを . で結合し、郵便番号アプリのZipcodeの場合は zipcodes.models になる
from zipcodes.models import Zipcode
16.2.3 モデルクラスで検索
- 全部のデータを取得し、個数を表示
- dに検索結果を入れる
d=Zipcode.objects.all() len(d)
- pk=1のデータっを取得し、zipcodeや色々なデータを表示
- dに検索結果を入れる
d=Zipcode.objects.filter(pk=1) print([ len(d), d[0].zip, d[0].kprefecture, d[0].kcity, d[0].kstreet])
- 県名が”大阪府”で、市名が”大阪市”のデータを取得し数を数え、一番最初のデータの表示
- And条件
d=Zipcode.objects.filter(kprefecture="大阪府",kcity__startswith="大阪市") print([ len(d), d[0].zip, d[0].kprefecture, d[0].kcity, d[0].kstreet])
- Qオブジェクトを利用してORとかAnd
- Q()で条件をくるんで
- ANDは&で結合
- ORは|で結合
- “府”で終わる都道府県名で、市区町村名に”区”が含まれる And条件だと
from django.db.models import Q d=Zipcode.objects.filter(Q(kprefecture__endswith="府")&Q(kcity__contains="区")) print([ len(d), d[0].zip, d[0].kprefecture, d[0].kcity, d[0].kstreet])
- Qオブジェクトを利用しないANDケースだと
d=Zipcode.objects.filter(kprefecture__endswith="府",kcity__contains="区") print([ len(d), d[0].zip, d[0].kprefecture, d[0].kcity, d[0].kstreet])
- “府”で終わる都道府県名か、市区町村名に”区”が含まれる OR条件だと
d=Zipcode.objects.filter(Q(kprefecture__endswith="府")|Q(kcity__contains="区")) print([ len(d), d[0].zip, d[0].kprefecture, d[0].kcity, d[0].kstreet])
16.2.4 ここまでの操作の画面のコピー
$ python manage.py shell Python 3.7.5 (default, Nov 20 2019, 09:21:52) Type "copyright", "credits" or "license" for more information. IPython 5.8.0 -- An enhanced Interactive Python. ? -> Introduction and overview of IPython's features. %quickref -> Quick reference. help -> Python's own help system. object? -> Details about 'object', use 'object??' for extra details. In [1]: from zipcodes.models import Zipcode ...: In [2]: d=Zipcode.objects.all() ...: len(d) ...: Out[2]: 124340 In [3]: d=Zipcode.objects.filter(pk=1) ...: print([ len(d), d[0].zip, d[0].kprefecture, d[0].kcity, d[0].kst ...: reet]) ...: [1, '0600000', '北海道', '札幌市中央区', '以下に掲載がない場合'] In [4]: d=Zipcode.objects.filter(kprefecture="大阪府",kcity__startswith= ...: "大阪市") ...: print([ len(d), d[0].zip, d[0].kprefecture, d[0].kcity, d[0].kst ...: reet]) ...: [966, '5340000', '大阪府', '大阪市都島区', '以下に掲載がない場合'] In [5]: from django.db.models import Q ...: d=Zipcode.objects.filter(Q(kprefecture__endswith="府")&Q(kcity__ ...: contains="区")) ...: print([ len(d), d[0].zip, d[0].kprefecture, d[0].kcity, d[0].kst ...: reet]) ...: [6214, '6030000', '京都府', '京都市北区', '以下に掲載がない場合'] In [6]: d=Zipcode.objects.filter(kprefecture__endswith="府",kcity__conta ...: ins="区") ...: print([ len(d), d[0].zip, d[0].kprefecture, d[0].kcity, d[0].kst ...: reet]) ...: [6214, '6030000', '京都府', '京都市北区', '以下に掲載がない場合'] In [7]: d=Zipcode.objects.filter(Q(kprefecture__endswith="府")|Q(kcity__ ...: contains="区")) ...: print([ len(d), d[0].zip, d[0].kprefecture, d[0].kcity, d[0].kst ...: reet]) ...: [24247, '0600000', '北海道', '札幌市中央区', '以下に掲載がない場合'] In [8]:
16.3 この章でのまとめ
- shell機能を活用することで、インタラクティブに動作確認や機能の確認を行うことができる(デバッグや、アプリ構築の際に非常に便利)
17 MySQLの利用
- 本家で関係する文書1 はじめての Django アプリ作成、その2 https://docs.djangoproject.com/ja/2.2/intro/tutorial02/
- 本家で関係する文書2 複数のデータベース https://docs.djangoproject.com/ja/2.2/topics/db/multi-db/
- 本家で関係する文書3 MySQL notes https://docs.djangoproject.com/ja/2.2/ref/databases/#mysql-notes
- 本家で関係する文書4 レガシーなデータベースと Django の統合 https://docs.djangoproject.com/ja/2.2/howto/legacy-databases/
- MySQLの公式document https://dev.mysql.com/doc/
17.1 以下の操作を行っている動画
17.2 MySQLのインストール
17.2.1 Ubuntuの場合
sudo apt install mysql-client mysql-server
17.2.2 WindowsやMacの場合
- 本家のGetting Startや、「OS名 MySQL インストール」などでネット検索かけて頂ければ、インストール方法みつかります
17.3 MySQLへの最初のログイン
- 最初結構はまりました、/usr/share/doc/mysql-clientにも文書なかったし
- Ubuntuの19.10の場合、インストール時にrootパスワードの設定がでてきません
- 以下のコマンドを実行して、パスワードを設定してください。
- 残りの質問は全部デフォルト(エンターのみ)でOK
sudo mysql_secure_installation
- 設定してる画面は以下の感じ
Securing the MySQL server deployment. Connecting to MySQL using a blank password. VALIDATE PASSWORD COMPONENT can be used to test passwords and improve security. It checks the strength of password and allows the users to set only those passwords which are secure enough. Would you like to setup VALIDATE PASSWORD component? Press y|Y for Yes, any other key for No: Please set the password for root here. New password: Re-enter new password: By default, a MySQL installation has an anonymous user, allowing anyone to log into MySQL without having to have a user account created for them. This is intended only for testing, and to make the installation go a bit smoother. You should remove them before moving into a production environment. Remove anonymous users? (Press y|Y for Yes, any other key for No) : ... skipping. Normally, root should only be allowed to connect from 'localhost'. This ensures that someone cannot guess at the root password from the network. Disallow root login remotely? (Press y|Y for Yes, any other key for No) : ... skipping. By default, MySQL comes with a database named 'test' that anyone can access. This is also intended only for testing, and should be removed before moving into a production environment. Remove test database and access to it? (Press y|Y for Yes, any other key for No) : ... skipping. Reloading the privilege tables will ensure that all changes made so far will take effect immediately. Reload privilege tables now? (Press y|Y for Yes, any other key for No) : ... skipping. All done!
17.4 MySQLへの最初の接続
- 以下のコマンドを実行し、上で設定したパスワードを入力するとプロンプトが表示されます
sudo mysql -u root -p
- ログインが上手くいくと以下の感じに
Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 18 Server version: 8.0.18-0ubuntu0.19.10.1 (Ubuntu) Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
17.5 django用のデータベース作成
- database_nameは好きなデータベース名に
CREATE DATABASE database_name;
- 例えばデータベース名を testdb とすると
CREATE DATABASE testdb;
17.6 ユーザーの作成
- username は希望するユーザー名に
- host はホスト名,ローカルならlocalhost
- passward は 希望するパスワードに
CREATE USER 'user_name'@'host' IDENTIFIED BY 'password';
- 例えば、ユーザー名をtester, ホスト名を localhost, パスワードを how7OjIcus にするなら
CREATE USER 'tester'@'localhost' IDENTIFIED BY 'how7OjIcus';
17.7 ユーザーに権限を付与
- ‘tester’@’localhost’ にdatabase_nameがtestdb への操作を全部許可する場合
GRANT ALL PRIVILEGES ON testdb.* TO 'tester'@'localhost'; FLUSH PRIVILEGES;
17.8 データベース一覧表示
SHOW DATABASES;
17.9 作成したユーザーで作成したデータベースにアクセスできるか確認
- パスワードをきかれたら、設定したパスワードを答える
mysql -u tester -p testdb
17.10 python3-mysqldb(mysqlclient)のインストール
- sudo apt install python3-mysqldb だと以下になってバージョン古すぎメッセージが出て使えないので、pipでインストール
django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 1.3.10.
- mysql_configが必用になるため、mysql_configを含む libmysqlclient-dev をインストール
sudo apt install libmysqlclient-dev
- Ubuntuでローカルにインストールする場合
- windowsとかMacなど他なら、pip3をpipにして -t 以降無しで実行 ( pip install mysqlclient )
pip3 install mysqlclient -t ~/python3/dist-packages
- これらをアップグレードする場合
pip3 install --upgrade Django -t ~/python3/dist-packages pip3 install --upgrade mysqlclient -t ~/python3/dist-packages
17.10.1 UbuntuなどDebian系以外の場合(windowsやmacや他の系統のLinux)
- ローカルじゃなく普通にインストールする場合
pip install mysqlclient
17.11 MySQLをプロジェクトで利用
17.11.1 プロジェクトの作成
- カスタムユーザーアプリの作成と、カスタムユーザーアプリの初期設定は省略します。通常の場合、後でカスタムユーザー追加は操作が大変なので最初に必ず追加しましょう。
django-admin startproject mytest007
cd mytest007
17.11.2 プロジェクト名/setting.pyを変更
- 作成したデータベース名 testdb
- ログインユーザー名が tester@localhost の場合
- 日本語設定や、タイムゾーンの設定は省略します。
DATABASES = { # 'default': { # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), # } 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'testdb', 'USER': 'tester', 'PASSWORD': 'how7OjIcus', 'HOST': '', 'PORT': '', } }
17.11.3 データベースとの連携
python manage.py makemigrations python manage.py migrate
17.11.4 作成されたtableを確認
$ mysql -u tester -p testdb Enter password: Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 25 Server version: 8.0.18-0ubuntu0.19.10.1 (Ubuntu) Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show tables; +------------------------------+ | Tables_in_testdb | +------------------------------+ | auth_group | | auth_group_permissions | | auth_permission | | django_admin_log | | django_content_type | | django_migrations | | django_session | +------------------------------+ 11 rows in set (0.01 sec) mysql> quit Bye
17.11.5 作成したデータベースのバックアップ
- ユーザー名 tester
- パスワードが how7OjIcus
- データベース名が testdb
- バックアップファイル名が dump.sqlの場合
mysqldump -u tester -phow7OjIcus testdb > dump.sql
17.12 この章について
- デフォルトのSqlite3ではなくMySQLをデータベースとして使う方法
- 他MySQLを使うにあたっての最低限の操作例
- ユーザー名やパスワードは同じものを使わないで!
18 実際裏で実行されてるSQLの確認方法
- 本家で関係する文書1 Django が実行している生の SQL クエリを見られますか? https://docs.djangoproject.com/ja/2.2/faq/models/#how-can-i-see-the-raw-sql-queries-django-is-running
- 本家で関係する文書2 FAQ: データベースとモデル https://docs.djangoproject.com/ja/2.2/faq/models/
- 本家で関係する文書3 FAQ https://docs.djangoproject.com/ja/2.2/faq/
- 本家で関係する文書4 モジュールの目次 https://docs.djangoproject.com/ja/2.2/py-modindex/
18.1 以下の操作を行っている動画
18.2 裏で実行されてるSQLの確認方法例
- 以前この文書で作成した 郵便番号検索アプリ を利用して試してみます
- djangoのshell機能を利用します
- DEBUG=Trueの時のみこの方法可能だそうです
18.2.1 djangoのshell起動
- 郵便番号アプリのmanage.pyがあるディレクトリで以下を実行
python manage.py shell
18.2.2 モデルのクラスをimport
from zipcodes.models import Zipcode from django.db.models import Q
18.2.3 実際に調べてみる1
d1=Zipcode.objects.filter(Q(kprefecture__endswith="府")|Q(kcity__contains="区")) str(d1.query)
18.2.4 実際に調べてみる2
d2=Zipcode.objects.filter(Q(kprefecture__endswith="府")&Q(kcity__contains="区")) str(d2.query)
18.2.5 実際に調べてみる3
d3=Zipcode.objects.filter(kprefecture__endswith="府",kcity__contains="区") str(d3.query)
18.2.6 実際に調べてみる4
from django.db import connection connection.queries
18.2.7 実際に操作したときのスクショ
$ python manage.py shell Python 3.7.5 (default, Nov 20 2019, 09:21:52) Type "copyright", "credits" or "license" for more information. IPython 5.8.0 -- An enhanced Interactive Python. ? -> Introduction and overview of IPython's features. %quickref -> Quick reference. help -> Python's own help system. object? -> Details about 'object', use 'object??' for extra details. In [1]: from zipcodes.models import Zipcode In [2]: from django.db.models import Q In [3]: d1=Zipcode.objects.filter(Q(kprefecture__endswith="府")|Q(kcity_ ...: _contains="区")) In [4]: str(d1.query) Out[4]: 'SELECT "zipcodes_zipcode"."id", "zipcodes_zipcode"."jisx", "zipcodes_zipcode"."zipold", "zipcodes_zipcode"."zip", "zipcodes_zipcode"."prefecture", "zipcodes_zipcode"."city", "zipcodes_zipcode"."street", "zipcodes_zipcode"."kprefecture", "zipcodes_zipcode"."kcity", "zipcodes_zipcode"."kstreet", "zipcodes_zipcode"."c1", "zipcodes_zipcode"."c2", "zipcodes_zipcode"."c3", "zipcodes_zipcode"."c4", "zipcodes_zipcode"."c5", "zipcodes_zipcode"."c6" FROM "zipcodes_zipcode" WHERE ("zipcodes_zipcode"."kprefecture" LIKE %府 ESCAPE \'\\\' OR "zipcodes_zipcode"."kcity" LIKE %区% ESCAPE \'\\\')' In [5]: from django.db import connection In [6]: connection.queries Out[6]: [] In [7]: len(d1) Out[7]: 24247 In [8]: connection.queries Out[8]: [{'sql': 'SELECT "zipcodes_zipcode"."id", "zipcodes_zipcode"."jisx", "zipcodes_zipcode"."zipold", "zipcodes_zipcode"."zip", "zipcodes_zipcode"."prefecture", "zipcodes_zipcode"."city", "zipcodes_zipcode"."street", "zipcodes_zipcode"."kprefecture", "zipcodes_zipcode"."kcity", "zipcodes_zipcode"."kstreet", "zipcodes_zipcode"."c1", "zipcodes_zipcode"."c2", "zipcodes_zipcode"."c3", "zipcodes_zipcode"."c4", "zipcodes_zipcode"."c5", "zipcodes_zipcode"."c6" FROM "zipcodes_zipcode" WHERE ("zipcodes_zipcode"."kprefecture" LIKE \'%府\' ESCAPE \'\\\' OR "zipcodes_zipcode"."kcity" LIKE \'%区%\' ESCAPE \'\\\')', 'time': '0.001'}] In [9]: d2=Zipcode.objects.filter(Q(kprefecture__endswith="府")&Q(kcity_ ...: _contains="区")) ...: str(d2.query) ...: Out[9]: 'SELECT "zipcodes_zipcode"."id", "zipcodes_zipcode"."jisx", "zipcodes_zipcode"."zipold", "zipcodes_zipcode"."zip", "zipcodes_zipcode"."prefecture", "zipcodes_zipcode"."city", "zipcodes_zipcode"."street", "zipcodes_zipcode"."kprefecture", "zipcodes_zipcode"."kcity", "zipcodes_zipcode"."kstreet", "zipcodes_zipcode"."c1", "zipcodes_zipcode"."c2", "zipcodes_zipcode"."c3", "zipcodes_zipcode"."c4", "zipcodes_zipcode"."c5", "zipcodes_zipcode"."c6" FROM "zipcodes_zipcode" WHERE ("zipcodes_zipcode"."kprefecture" LIKE %府 ESCAPE \'\\\' AND "zipcodes_zipcode"."kcity" LIKE %区% ESCAPE \'\\\')' In [10]: connection.queries Out[10]: [{'sql': 'SELECT "zipcodes_zipcode"."id", "zipcodes_zipcode"."jisx", "zipcodes_zipcode"."zipold", "zipcodes_zipcode"."zip", "zipcodes_zipcode"."prefecture", "zipcodes_zipcode"."city", "zipcodes_zipcode"."street", "zipcodes_zipcode"."kprefecture", "zipcodes_zipcode"."kcity", "zipcodes_zipcode"."kstreet", "zipcodes_zipcode"."c1", "zipcodes_zipcode"."c2", "zipcodes_zipcode"."c3", "zipcodes_zipcode"."c4", "zipcodes_zipcode"."c5", "zipcodes_zipcode"."c6" FROM "zipcodes_zipcode" WHERE ("zipcodes_zipcode"."kprefecture" LIKE \'%府\' ESCAPE \'\\\' OR "zipcodes_zipcode"."kcity" LIKE \'%区%\' ESCAPE \'\\\')', 'time': '0.001'}] In [11]: len(d2) Out[11]: 6214 In [12]: connection.queries Out[12]: [{'sql': 'SELECT "zipcodes_zipcode"."id", "zipcodes_zipcode"."jisx", "zipcodes_zipcode"."zipold", "zipcodes_zipcode"."zip", "zipcodes_zipcode"."prefecture", "zipcodes_zipcode"."city", "zipcodes_zipcode"."street", "zipcodes_zipcode"."kprefecture", "zipcodes_zipcode"."kcity", "zipcodes_zipcode"."kstreet", "zipcodes_zipcode"."c1", "zipcodes_zipcode"."c2", "zipcodes_zipcode"."c3", "zipcodes_zipcode"."c4", "zipcodes_zipcode"."c5", "zipcodes_zipcode"."c6" FROM "zipcodes_zipcode" WHERE ("zipcodes_zipcode"."kprefecture" LIKE \'%府\' ESCAPE \'\\\' OR "zipcodes_zipcode"."kcity" LIKE \'%区%\' ESCAPE \'\\\')', 'time': '0.001'}, {'sql': 'SELECT "zipcodes_zipcode"."id", "zipcodes_zipcode"."jisx", "zipcodes_zipcode"."zipold", "zipcodes_zipcode"."zip", "zipcodes_zipcode"."prefecture", "zipcodes_zipcode"."city", "zipcodes_zipcode"."street", "zipcodes_zipcode"."kprefecture", "zipcodes_zipcode"."kcity", "zipcodes_zipcode"."kstreet", "zipcodes_zipcode"."c1", "zipcodes_zipcode"."c2", "zipcodes_zipcode"."c3", "zipcodes_zipcode"."c4", "zipcodes_zipcode"."c5", "zipcodes_zipcode"."c6" FROM "zipcodes_zipcode" WHERE ("zipcodes_zipcode"."kprefecture" LIKE \'%府\' ESCAPE \'\\\' AND "zipcodes_zipcode"."kcity" LIKE \'%区%\' ESCAPE \'\\\')', 'time': '0.030'}] In [13]: d3=Zipcode.objects.filter(kprefecture__endswith="府",kcity__con ...: tains="区") ...: str(d3.query) ...: Out[13]: 'SELECT "zipcodes_zipcode"."id", "zipcodes_zipcode"."jisx", "zipcodes_zipcode"."zipold", "zipcodes_zipcode"."zip", "zipcodes_zipcode"."prefecture", "zipcodes_zipcode"."city", "zipcodes_zipcode"."street", "zipcodes_zipcode"."kprefecture", "zipcodes_zipcode"."kcity", "zipcodes_zipcode"."kstreet", "zipcodes_zipcode"."c1", "zipcodes_zipcode"."c2", "zipcodes_zipcode"."c3", "zipcodes_zipcode"."c4", "zipcodes_zipcode"."c5", "zipcodes_zipcode"."c6" FROM "zipcodes_zipcode" WHERE ("zipcodes_zipcode"."kcity" LIKE %区% ESCAPE \'\\\' AND "zipcodes_zipcode"."kprefecture" LIKE %府 ESCAPE \'\\\')' In [14]: len(d3) Out[14]: 6214 In [15]: connection.queries Out[15]: [{'sql': 'SELECT "zipcodes_zipcode"."id", "zipcodes_zipcode"."jisx", "zipcodes_zipcode"."zipold", "zipcodes_zipcode"."zip", "zipcodes_zipcode"."prefecture", "zipcodes_zipcode"."city", "zipcodes_zipcode"."street", "zipcodes_zipcode"."kprefecture", "zipcodes_zipcode"."kcity", "zipcodes_zipcode"."kstreet", "zipcodes_zipcode"."c1", "zipcodes_zipcode"."c2", "zipcodes_zipcode"."c3", "zipcodes_zipcode"."c4", "zipcodes_zipcode"."c5", "zipcodes_zipcode"."c6" FROM "zipcodes_zipcode" WHERE ("zipcodes_zipcode"."kprefecture" LIKE \'%府\' ESCAPE \'\\\' OR "zipcodes_zipcode"."kcity" LIKE \'%区%\' ESCAPE \'\\\')', 'time': '0.001'}, {'sql': 'SELECT "zipcodes_zipcode"."id", "zipcodes_zipcode"."jisx", "zipcodes_zipcode"."zipold", "zipcodes_zipcode"."zip", "zipcodes_zipcode"."prefecture", "zipcodes_zipcode"."city", "zipcodes_zipcode"."street", "zipcodes_zipcode"."kprefecture", "zipcodes_zipcode"."kcity", "zipcodes_zipcode"."kstreet", "zipcodes_zipcode"."c1", "zipcodes_zipcode"."c2", "zipcodes_zipcode"."c3", "zipcodes_zipcode"."c4", "zipcodes_zipcode"."c5", "zipcodes_zipcode"."c6" FROM "zipcodes_zipcode" WHERE ("zipcodes_zipcode"."kprefecture" LIKE \'%府\' ESCAPE \'\\\' AND "zipcodes_zipcode"."kcity" LIKE \'%区%\' ESCAPE \'\\\')', 'time': '0.030'}, {'sql': 'SELECT "zipcodes_zipcode"."id", "zipcodes_zipcode"."jisx", "zipcodes_zipcode"."zipold", "zipcodes_zipcode"."zip", "zipcodes_zipcode"."prefecture", "zipcodes_zipcode"."city", "zipcodes_zipcode"."street", "zipcodes_zipcode"."kprefecture", "zipcodes_zipcode"."kcity", "zipcodes_zipcode"."kstreet", "zipcodes_zipcode"."c1", "zipcodes_zipcode"."c2", "zipcodes_zipcode"."c3", "zipcodes_zipcode"."c4", "zipcodes_zipcode"."c5", "zipcodes_zipcode"."c6" FROM "zipcodes_zipcode" WHERE ("zipcodes_zipcode"."kcity" LIKE \'%区%\' ESCAPE \'\\\' AND "zipcodes_zipcode"."kprefecture" LIKE \'%府\' ESCAPE \'\\\')', 'time': '0.036'}] In [16]: connection.queries4 ------------------------------------------------------------------------ AttributeError Traceback (most recent call last) <ipython-input-16-7e2a5aa2c672> in <module>() ----> 1 connection.queries4 /home/pano/python3/dist-packages/django/db/__init__.py in __getattr__(self, item) 26 """ 27 def __getattr__(self, item): ---> 28 return getattr(connections[DEFAULT_DB_ALIAS], item) 29 30 def __setattr__(self, name, value): AttributeError: 'DatabaseWrapper' object has no attribute 'queries4' In [17]: connection.queries Out[17]: [{'sql': 'SELECT "zipcodes_zipcode"."id", "zipcodes_zipcode"."jisx", "zipcodes_zipcode"."zipold", "zipcodes_zipcode"."zip", "zipcodes_zipcode"."prefecture", "zipcodes_zipcode"."city", "zipcodes_zipcode"."street", "zipcodes_zipcode"."kprefecture", "zipcodes_zipcode"."kcity", "zipcodes_zipcode"."kstreet", "zipcodes_zipcode"."c1", "zipcodes_zipcode"."c2", "zipcodes_zipcode"."c3", "zipcodes_zipcode"."c4", "zipcodes_zipcode"."c5", "zipcodes_zipcode"."c6" FROM "zipcodes_zipcode" WHERE ("zipcodes_zipcode"."kprefecture" LIKE \'%府\' ESCAPE \'\\\' OR "zipcodes_zipcode"."kcity" LIKE \'%区%\' ESCAPE \'\\\')', 'time': '0.001'}, {'sql': 'SELECT "zipcodes_zipcode"."id", "zipcodes_zipcode"."jisx", "zipcodes_zipcode"."zipold", "zipcodes_zipcode"."zip", "zipcodes_zipcode"."prefecture", "zipcodes_zipcode"."city", "zipcodes_zipcode"."street", "zipcodes_zipcode"."kprefecture", "zipcodes_zipcode"."kcity", "zipcodes_zipcode"."kstreet", "zipcodes_zipcode"."c1", "zipcodes_zipcode"."c2", "zipcodes_zipcode"."c3", "zipcodes_zipcode"."c4", "zipcodes_zipcode"."c5", "zipcodes_zipcode"."c6" FROM "zipcodes_zipcode" WHERE ("zipcodes_zipcode"."kprefecture" LIKE \'%府\' ESCAPE \'\\\' AND "zipcodes_zipcode"."kcity" LIKE \'%区%\' ESCAPE \'\\\')', 'time': '0.030'}, {'sql': 'SELECT "zipcodes_zipcode"."id", "zipcodes_zipcode"."jisx", "zipcodes_zipcode"."zipold", "zipcodes_zipcode"."zip", "zipcodes_zipcode"."prefecture", "zipcodes_zipcode"."city", "zipcodes_zipcode"."street", "zipcodes_zipcode"."kprefecture", "zipcodes_zipcode"."kcity", "zipcodes_zipcode"."kstreet", "zipcodes_zipcode"."c1", "zipcodes_zipcode"."c2", "zipcodes_zipcode"."c3", "zipcodes_zipcode"."c4", "zipcodes_zipcode"."c5", "zipcodes_zipcode"."c6" FROM "zipcodes_zipcode" WHERE ("zipcodes_zipcode"."kcity" LIKE \'%区%\' ESCAPE \'\\\' AND "zipcodes_zipcode"."kprefecture" LIKE \'%府\' ESCAPE \'\\\')', 'time': '0.036'}] In [18]: quit
18.3 この章のまとめ
- モデルを利用した時に裏で実行されているSQL文の確認方法を試してみた
- 実際SQL文が実行されるタイミングは必用となってからのケースもある
19 この文書のチェンジログ
- 2019/11/10 初版
- 2019/11/10 修正および、テンプレートファイルを利用する章の追加
- 2019/11/10 足し算アプリ作成する章の追加
- 2019/11/11 一部修正及び、ファイルアップロードする章の追加
- 2019/11/11 urlからパラメーター取り出しする章の追加
- 2019/11/11 カスタムフィルタ作成利用の章追加
- 2019/11/16 セッションの利用の章を追加
- 2019/11/16 python3 と入力していた命令を python に変更(Ubuntu以外はpythonであるため) Ubuntuの場合上で.bash_rcで設定しておらず、python2系と3系をインストールしているならpythonとコマンド入力している部分はpython3と入力すべきかも
- 2019/11/17 カスタムユーザー(AbstractUserを継承タイプ)の章追加
- 2019/11/18 カスタムユーザー(AbstractBaseUserを継承タイプ)の章追加、最初の概要変更
- 2019/11/27 郵便番号検索アプリ作成の章追加
- 2019/11/28 djangoのシェル機能の章追加
- 2019/11/28 MySQLの利用の章追加
- 2019/11/28 実際裏で実行されてるSQLの確認方法の章追加
20 続きを追記してきます。
Created: 2019-11-28 木 07:43