[{"data":1,"prerenderedAt":3324},["ShallowReactive",2],{"series-laravel_to_django-2":3},{"doc":4,"prev":1798,"next":1796},{"id":5,"title":6,"body":7,"category":1780,"createdAt":1782,"description":1783,"extension":1784,"index":141,"meta":1785,"navigation":679,"path":1786,"publish":1787,"seo":1788,"series":1789,"seriesTitle":1790,"stem":1791,"tag":1792,"thumbnail":1795,"updatedAt":1796,"__hash__":1797},"series\u002Fseries\u002Flaravel-to-django-2.md","その２：ビューと認証",{"type":8,"value":9,"toc":1754},"minimark",[10,14,22,35,38,43,46,49,53,69,80,90,93,96,101,639,642,645,652,701,718,721,753,761,766,769,775,778,782,785,811,818,841,844,866,869,872,926,928,1000,1007,1010,1013,1176,1182,1185,1192,1219,1225,1247,1254,1264,1268,1277,1283,1294,1300,1303,1306,1313,1316,1398,1403,1406,1420,1627,1636,1687,1693,1696,1718,1721,1725,1732,1735,1739,1742,1744,1747,1750],[11,12,13],"p",{},"こんにちはjunです。この記事はLaravel開発者がDjangoでアプリ作成の学習について解説しています。Laravelでいうこの機能はDjangoのここである、その逆はこうだと「Laravelとリンクさせて学習する」ことを重視しています。",[11,15,16,21],{},[17,18,20],"a",{"href":19},"\u002Fseries\u002Flaravel_to_django\u002F1","前回","は環境構築やアプリの概要、設定ファイルとディレクトリ構成の解説を行いました。今回の記事は",[23,24,25,29,32],"ul",{},[26,27,28],"li",{},"テンプレートを使用したViewの作成",[26,30,31],{},"静的ファイルの使用方法",[26,33,34],{},"認証機能の実装",[11,36,37],{},"以上を行いたいと思います。",[39,40,42],"h2",{"id":41},"viewテンプレートの作成","View（テンプレート）の作成",[11,44,45],{},"ではウェルカムページをカスタムのViewを表示することをやってみましょう。ちなみに、DjangoではMVTというコンセプトで作成され、LaravelのMVCとは少し意味合いが異なるそうです。見た目の部分はMVCではV（View）と定義しますが、MVTではT（Template）でありV（View）はリクエストを受け取り、レスポンスを定義します。",[11,47,48],{},"そのため今後はMVTに則り、見た目の部分の機能に関してはTemplateと呼ぶこととします。",[50,51,52],"h3",{"id":52},"テンプレートの仕組み",[11,54,55,56,60,61,64,65,68],{},"テンプレートとは見た目（htmlレスポンス）を定義するファイルのことで",[57,58,59],"code",{},".html","で定義します。Laravelでは",[57,62,63],{},"resources\u002Fviews\u002F","配下に",[57,66,67],{},"~~.blade.php","というブレードを用いて見た目のhtmlを定義するのと同じです。",[11,70,71,72,75,76,79],{},"ソースのルートディレクトリに",[57,73,74],{},"templates\u002F","ディレクトリ を作成し、",[57,77,78],{},"base.html","をさらに作成します。",[81,82,87],"pre",{"className":83,"code":85,"language":86},[84],"language-text","├── db.sqlite3\n├── djangodemo\n├── manage.py\n└── templates\n    └── base.html\n","text",[57,88,85],{"__ignoreMap":89},"",[11,91,92],{},"このソースルートのtemplatesはすべてのアプリで使用することができます。",[50,94,95],{"id":95},"テンプレートの書き方",[11,97,98,100],{},[57,99,78],{},"を作成します。まず以下の様に作成してみます。",[81,102,106],{"className":103,"code":104,"filename":78,"language":105,"meta":89,"style":89},"language-html shiki shiki-themes material-theme-ocean","\u003Chtml lang=\"ja\">\n    \u003Chead>\n        \u003Cmeta charset=\"utf-8\">\n        \u003Cmeta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n        \u003Cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n        \u003Clink href=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fnpm\u002Fbootstrap@5.0.2\u002Fdist\u002Fcss\u002Fbootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-EVSTQN3\u002FazprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC\" crossorigin=\"anonymous\">\n        \u003Clink rel=\"stylesheet\" href=\"{% static 'style.css' %}\">\n        \u003Ctitle>test\u003C\u002Ftitle>\n    \u003C\u002Fhead>\n    \u003Cbody>\n        \u003Cheader>\n            \u003Cnav class=\"navbar navbar-light bg-info\">\n                \u003Cdiv class=\"container\">\n                    \u003Ca class=\"navbar-brand\" href=\"\u002F\">Navbar\u003C\u002Fa>\n                \u003C\u002Fdiv>\n            \u003C\u002Fnav>\n        \u003C\u002Fheader>\n        \u003Cmain class=\"d-block bg-light\">\n            \u003Cdiv class=\"container p-4 bg-white l-main-area\">\n                test\n            \u003C\u002Fdiv>\n        \u003C\u002Fmain>\n        \u003Cfooter>\u003C\u002Ffooter>\n        \u003Cscript src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fnpm\u002Fbootstrap@5.0.2\u002Fdist\u002Fjs\u002Fbootstrap.bundle.min.js\" integrity=\"sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn\u002FtWtIaxVXM\" crossorigin=\"anonymous\">\u003C\u002Fscript>\n    \u003C\u002Fbody>\n\u003C\u002Fhtml>\n","html",[57,107,108,139,150,173,206,238,296,326,348,358,368,378,401,423,464,474,484,494,515,535,541,550,559,574,621,630],{"__ignoreMap":89},[109,110,113,117,120,124,127,130,134,136],"span",{"class":111,"line":112},"line",1,[109,114,116],{"class":115},"sAklC","\u003C",[109,118,105],{"class":119},"s-wAU",[109,121,123],{"class":122},"sJ14y"," lang",[109,125,126],{"class":115},"=",[109,128,129],{"class":115},"\"",[109,131,133],{"class":132},"sfyAc","ja",[109,135,129],{"class":115},[109,137,138],{"class":115},">\n",[109,140,142,145,148],{"class":111,"line":141},2,[109,143,144],{"class":115},"    \u003C",[109,146,147],{"class":119},"head",[109,149,138],{"class":115},[109,151,153,156,159,162,164,166,169,171],{"class":111,"line":152},3,[109,154,155],{"class":115},"        \u003C",[109,157,158],{"class":119},"meta",[109,160,161],{"class":122}," charset",[109,163,126],{"class":115},[109,165,129],{"class":115},[109,167,168],{"class":132},"utf-8",[109,170,129],{"class":115},[109,172,138],{"class":115},[109,174,176,178,180,183,185,187,190,192,195,197,199,202,204],{"class":111,"line":175},4,[109,177,155],{"class":115},[109,179,158],{"class":119},[109,181,182],{"class":122}," http-equiv",[109,184,126],{"class":115},[109,186,129],{"class":115},[109,188,189],{"class":132},"X-UA-Compatible",[109,191,129],{"class":115},[109,193,194],{"class":122}," content",[109,196,126],{"class":115},[109,198,129],{"class":115},[109,200,201],{"class":132},"IE=edge",[109,203,129],{"class":115},[109,205,138],{"class":115},[109,207,209,211,213,216,218,220,223,225,227,229,231,234,236],{"class":111,"line":208},5,[109,210,155],{"class":115},[109,212,158],{"class":119},[109,214,215],{"class":122}," name",[109,217,126],{"class":115},[109,219,129],{"class":115},[109,221,222],{"class":132},"viewport",[109,224,129],{"class":115},[109,226,194],{"class":122},[109,228,126],{"class":115},[109,230,129],{"class":115},[109,232,233],{"class":132},"width=device-width, initial-scale=1",[109,235,129],{"class":115},[109,237,138],{"class":115},[109,239,241,243,246,249,251,253,256,258,261,263,265,268,270,273,275,277,280,282,285,287,289,292,294],{"class":111,"line":240},6,[109,242,155],{"class":115},[109,244,245],{"class":119},"link",[109,247,248],{"class":122}," href",[109,250,126],{"class":115},[109,252,129],{"class":115},[109,254,255],{"class":132},"https:\u002F\u002Fcdn.jsdelivr.net\u002Fnpm\u002Fbootstrap@5.0.2\u002Fdist\u002Fcss\u002Fbootstrap.min.css",[109,257,129],{"class":115},[109,259,260],{"class":122}," rel",[109,262,126],{"class":115},[109,264,129],{"class":115},[109,266,267],{"class":132},"stylesheet",[109,269,129],{"class":115},[109,271,272],{"class":122}," integrity",[109,274,126],{"class":115},[109,276,129],{"class":115},[109,278,279],{"class":132},"sha384-EVSTQN3\u002FazprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC",[109,281,129],{"class":115},[109,283,284],{"class":122}," crossorigin",[109,286,126],{"class":115},[109,288,129],{"class":115},[109,290,291],{"class":132},"anonymous",[109,293,129],{"class":115},[109,295,138],{"class":115},[109,297,299,301,303,305,307,309,311,313,315,317,319,322,324],{"class":111,"line":298},7,[109,300,155],{"class":115},[109,302,245],{"class":119},[109,304,260],{"class":122},[109,306,126],{"class":115},[109,308,129],{"class":115},[109,310,267],{"class":132},[109,312,129],{"class":115},[109,314,248],{"class":122},[109,316,126],{"class":115},[109,318,129],{"class":115},[109,320,321],{"class":132},"{% static 'style.css' %}",[109,323,129],{"class":115},[109,325,138],{"class":115},[109,327,329,331,334,337,341,344,346],{"class":111,"line":328},8,[109,330,155],{"class":115},[109,332,333],{"class":119},"title",[109,335,336],{"class":115},">",[109,338,340],{"class":339},"s0W1g","test",[109,342,343],{"class":115},"\u003C\u002F",[109,345,333],{"class":119},[109,347,138],{"class":115},[109,349,351,354,356],{"class":111,"line":350},9,[109,352,353],{"class":115},"    \u003C\u002F",[109,355,147],{"class":119},[109,357,138],{"class":115},[109,359,361,363,366],{"class":111,"line":360},10,[109,362,144],{"class":115},[109,364,365],{"class":119},"body",[109,367,138],{"class":115},[109,369,371,373,376],{"class":111,"line":370},11,[109,372,155],{"class":115},[109,374,375],{"class":119},"header",[109,377,138],{"class":115},[109,379,381,384,387,390,392,394,397,399],{"class":111,"line":380},12,[109,382,383],{"class":115},"            \u003C",[109,385,386],{"class":119},"nav",[109,388,389],{"class":122}," class",[109,391,126],{"class":115},[109,393,129],{"class":115},[109,395,396],{"class":132},"navbar navbar-light bg-info",[109,398,129],{"class":115},[109,400,138],{"class":115},[109,402,404,407,410,412,414,416,419,421],{"class":111,"line":403},13,[109,405,406],{"class":115},"                \u003C",[109,408,409],{"class":119},"div",[109,411,389],{"class":122},[109,413,126],{"class":115},[109,415,129],{"class":115},[109,417,418],{"class":132},"container",[109,420,129],{"class":115},[109,422,138],{"class":115},[109,424,426,429,431,433,435,437,440,442,444,446,448,451,453,455,458,460,462],{"class":111,"line":425},14,[109,427,428],{"class":115},"                    \u003C",[109,430,17],{"class":119},[109,432,389],{"class":122},[109,434,126],{"class":115},[109,436,129],{"class":115},[109,438,439],{"class":132},"navbar-brand",[109,441,129],{"class":115},[109,443,248],{"class":122},[109,445,126],{"class":115},[109,447,129],{"class":115},[109,449,450],{"class":132},"\u002F",[109,452,129],{"class":115},[109,454,336],{"class":115},[109,456,457],{"class":339},"Navbar",[109,459,343],{"class":115},[109,461,17],{"class":119},[109,463,138],{"class":115},[109,465,467,470,472],{"class":111,"line":466},15,[109,468,469],{"class":115},"                \u003C\u002F",[109,471,409],{"class":119},[109,473,138],{"class":115},[109,475,477,480,482],{"class":111,"line":476},16,[109,478,479],{"class":115},"            \u003C\u002F",[109,481,386],{"class":119},[109,483,138],{"class":115},[109,485,487,490,492],{"class":111,"line":486},17,[109,488,489],{"class":115},"        \u003C\u002F",[109,491,375],{"class":119},[109,493,138],{"class":115},[109,495,497,499,502,504,506,508,511,513],{"class":111,"line":496},18,[109,498,155],{"class":115},[109,500,501],{"class":119},"main",[109,503,389],{"class":122},[109,505,126],{"class":115},[109,507,129],{"class":115},[109,509,510],{"class":132},"d-block bg-light",[109,512,129],{"class":115},[109,514,138],{"class":115},[109,516,518,520,522,524,526,528,531,533],{"class":111,"line":517},19,[109,519,383],{"class":115},[109,521,409],{"class":119},[109,523,389],{"class":122},[109,525,126],{"class":115},[109,527,129],{"class":115},[109,529,530],{"class":132},"container p-4 bg-white l-main-area",[109,532,129],{"class":115},[109,534,138],{"class":115},[109,536,538],{"class":111,"line":537},20,[109,539,540],{"class":339},"                test\n",[109,542,544,546,548],{"class":111,"line":543},21,[109,545,479],{"class":115},[109,547,409],{"class":119},[109,549,138],{"class":115},[109,551,553,555,557],{"class":111,"line":552},22,[109,554,489],{"class":115},[109,556,501],{"class":119},[109,558,138],{"class":115},[109,560,562,564,567,570,572],{"class":111,"line":561},23,[109,563,155],{"class":115},[109,565,566],{"class":119},"footer",[109,568,569],{"class":115},">\u003C\u002F",[109,571,566],{"class":119},[109,573,138],{"class":115},[109,575,577,579,582,585,587,589,592,594,596,598,600,603,605,607,609,611,613,615,617,619],{"class":111,"line":576},24,[109,578,155],{"class":115},[109,580,581],{"class":119},"script",[109,583,584],{"class":122}," src",[109,586,126],{"class":115},[109,588,129],{"class":115},[109,590,591],{"class":132},"https:\u002F\u002Fcdn.jsdelivr.net\u002Fnpm\u002Fbootstrap@5.0.2\u002Fdist\u002Fjs\u002Fbootstrap.bundle.min.js",[109,593,129],{"class":115},[109,595,272],{"class":122},[109,597,126],{"class":115},[109,599,129],{"class":115},[109,601,602],{"class":132},"sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn\u002FtWtIaxVXM",[109,604,129],{"class":115},[109,606,284],{"class":122},[109,608,126],{"class":115},[109,610,129],{"class":115},[109,612,291],{"class":132},[109,614,129],{"class":115},[109,616,569],{"class":115},[109,618,581],{"class":119},[109,620,138],{"class":115},[109,622,624,626,628],{"class":111,"line":623},25,[109,625,353],{"class":115},[109,627,365],{"class":119},[109,629,138],{"class":115},[109,631,633,635,637],{"class":111,"line":632},26,[109,634,343],{"class":115},[109,636,105],{"class":119},[109,638,138],{"class":115},[11,640,641],{},"bootstrapを入れておきます。変数などは定義していませんが、ひとまずウェルカムページを上記の内容に書き換えましょう。",[50,643,644],{"id":644},"テンプレートをレスポンスで返してみる",[11,646,647,648,651],{},"テンプレート作成したら",[57,649,650],{},"djangodemo\u002Furls.py","を以下の様に変更します。",[81,653,658],{"className":654,"code":655,"filename":656,"language":657,"meta":89,"style":89},"language-python shiki shiki-themes material-theme-ocean","from django.contrib import admin\nfrom django.urls import path\nfrom django.views.generic import TemplateView # わすれずに\n\nurlpatterns = [\n    path('',TemplateView.as_view(template_name='base.html')), # これを追加\n    path('admin\u002F', admin.site.urls),\n]\n","urls.py","python",[57,659,660,665,670,675,681,686,691,696],{"__ignoreMap":89},[109,661,662],{"class":111,"line":112},[109,663,664],{},"from django.contrib import admin\n",[109,666,667],{"class":111,"line":141},[109,668,669],{},"from django.urls import path\n",[109,671,672],{"class":111,"line":152},[109,673,674],{},"from django.views.generic import TemplateView # わすれずに\n",[109,676,677],{"class":111,"line":175},[109,678,680],{"emptyLinePlaceholder":679},true,"\n",[109,682,683],{"class":111,"line":208},[109,684,685],{},"urlpatterns = [\n",[109,687,688],{"class":111,"line":240},[109,689,690],{},"    path('',TemplateView.as_view(template_name='base.html')), # これを追加\n",[109,692,693],{"class":111,"line":298},[109,694,695],{},"    path('admin\u002F', admin.site.urls),\n",[109,697,698],{"class":111,"line":328},[109,699,700],{},"]\n",[11,702,703,705,706,709,710,713,714,717],{},[57,704,656],{},"はLaravelでいう",[57,707,708],{},"routes\u002F","配下のファイルであり、URLに対応する処理やテンプレートを指定する箇所です。上記の記述を用いて、",[57,711,712],{},"http:\u002F\u002Flocalhost:8000\u002F","にアクセスした時に先ほどの、base.htmlを表示する様にしています。テンプレートを直接指定してレスポンスとして返すには",[57,715,716],{},"TemplateView","が必要です。",[11,719,720],{},"Laravel的には以下の様な記述です。",[81,722,727],{"className":723,"code":724,"filename":725,"language":726,"meta":89,"style":89},"language-php shiki shiki-themes material-theme-ocean","use Illuminate\\Support\\Facades\\Route;\n\nRoute::get('\u002F', function () {\n    return view('base');\n});\n","routes\u002Fweb.php","php",[57,728,729,734,738,743,748],{"__ignoreMap":89},[109,730,731],{"class":111,"line":112},[109,732,733],{},"use Illuminate\\Support\\Facades\\Route;\n",[109,735,736],{"class":111,"line":141},[109,737,680],{"emptyLinePlaceholder":679},[109,739,740],{"class":111,"line":152},[109,741,742],{},"Route::get('\u002F', function () {\n",[109,744,745],{"class":111,"line":175},[109,746,747],{},"    return view('base');\n",[109,749,750],{"class":111,"line":208},[109,751,752],{},"});\n",[11,754,755,757,758,760],{},[57,756,656],{},"を編集したら",[57,759,712],{},"にアクセスして以下の様な画面が表示されればひとまず、特定のURLにテンプレートを返すという感覚がわかると思います。",[762,763],"image-render",{":src":764,":width":765},"'laralve_to_django\u002F2\u002Fbase_html.png'","'100%'",[11,767,768],{},"ひとまずカスタムテンプレートを表示できたのでDjangoで使用できる様々なディレクティブを解説します。",[409,770,774],{"className":771},[772,773],"alert","alert-success","\nディレクティブというのはそのプログラム（ここではDjango）が解釈できる文字列の記述のことです。Djandgoでは {% if %}　のような記号を用いて表現します。Laravelのブレードでは @if などです。\n",[50,776,777],{"id":777},"テンプレートで使えるディレクィブ",[779,780,781],"h4",{"id":781},"変数展開",[11,783,784],{},"Viewからはテンプレートにはデータを渡すことができます。渡す時はDictで渡します。",[81,786,789],{"className":654,"code":787,"filename":788,"language":657,"meta":89,"style":89},"from django.shortcuts import render\ndef index(request):\n    context = {'value': 123}\n    return render(request, 'polls\u002Findex.html', context)\n","views.py",[57,790,791,796,801,806],{"__ignoreMap":89},[109,792,793],{"class":111,"line":112},[109,794,795],{},"from django.shortcuts import render\n",[109,797,798],{"class":111,"line":141},[109,799,800],{},"def index(request):\n",[109,802,803],{"class":111,"line":152},[109,804,805],{},"    context = {'value': 123}\n",[109,807,808],{"class":111,"line":175},[109,809,810],{},"    return render(request, 'polls\u002Findex.html', context)\n",[11,812,813,814,817],{},"そして変数を展開する時は",[57,815,816],{},"{{ }}"," を用いて展開をします。値は自動的にエスケープ処理されます。ここはLaravelと同じですね。",[81,819,822],{"className":103,"code":820,"filename":821,"language":105,"meta":89,"style":89},"\u003Cp>{{ value }}\u003C\u002Fp>\n","template.html",[57,823,824],{"__ignoreMap":89},[109,825,826,828,830,832,835,837,839],{"class":111,"line":112},[109,827,116],{"class":115},[109,829,11],{"class":119},[109,831,336],{"class":115},[109,833,834],{"class":339},"{{ value }}",[109,836,343],{"class":115},[109,838,11],{"class":119},[109,840,138],{"class":115},[11,842,843],{},"↓",[81,845,847],{"className":103,"code":846,"filename":821,"language":105,"meta":89,"style":89},"\u003Cp>123\u003C\u002Fp>\n",[57,848,849],{"__ignoreMap":89},[109,850,851,853,855,857,860,862,864],{"class":111,"line":112},[109,852,116],{"class":115},[109,854,11],{"class":119},[109,856,336],{"class":115},[109,858,859],{"class":339},"123",[109,861,343],{"class":115},[109,863,11],{"class":119},[109,865,138],{"class":115},[779,867,868],{"id":868},"for文",[11,870,871],{},"for分は以下の様に使用します。",[81,873,875],{"className":103,"code":874,"language":105,"meta":89,"style":89},"\u003C!-- list = [{'name':'jun'},{'name':'apps'},{'name':'python'}] -->\n\u003Cul>\n{% for item in list %}\n\u003Cli>{{ item.name }}\u003C\u002Fli>\n{% endfor %}\n\u003C\u002Ful>\n",[57,876,877,883,891,896,913,918],{"__ignoreMap":89},[109,878,879],{"class":111,"line":112},[109,880,882],{"class":881},"sC9rS","\u003C!-- list = [{'name':'jun'},{'name':'apps'},{'name':'python'}] -->\n",[109,884,885,887,889],{"class":111,"line":141},[109,886,116],{"class":115},[109,888,23],{"class":119},[109,890,138],{"class":115},[109,892,893],{"class":111,"line":152},[109,894,895],{"class":339},"{% for item in list %}\n",[109,897,898,900,902,904,907,909,911],{"class":111,"line":175},[109,899,116],{"class":115},[109,901,26],{"class":119},[109,903,336],{"class":115},[109,905,906],{"class":339},"{{ item.name }}",[109,908,343],{"class":115},[109,910,26],{"class":119},[109,912,138],{"class":115},[109,914,915],{"class":111,"line":208},[109,916,917],{"class":339},"{% endfor %}\n",[109,919,920,922,924],{"class":111,"line":240},[109,921,343],{"class":115},[109,923,23],{"class":119},[109,925,138],{"class":115},[11,927,843],{},[81,929,931],{"className":103,"code":930,"language":105,"meta":89,"style":89},"\u003Cul>\n\u003Cli>{{ item.jun }}\u003C\u002Fli>\n\u003Cli>{{ item.apps }}\u003C\u002Fli>\n\u003Cli>{{ item.python }}\u003C\u002Fli>\n\u003C\u002Ful>\n",[57,932,933,941,958,975,992],{"__ignoreMap":89},[109,934,935,937,939],{"class":111,"line":112},[109,936,116],{"class":115},[109,938,23],{"class":119},[109,940,138],{"class":115},[109,942,943,945,947,949,952,954,956],{"class":111,"line":141},[109,944,116],{"class":115},[109,946,26],{"class":119},[109,948,336],{"class":115},[109,950,951],{"class":339},"{{ item.jun }}",[109,953,343],{"class":115},[109,955,26],{"class":119},[109,957,138],{"class":115},[109,959,960,962,964,966,969,971,973],{"class":111,"line":152},[109,961,116],{"class":115},[109,963,26],{"class":119},[109,965,336],{"class":115},[109,967,968],{"class":339},"{{ item.apps }}",[109,970,343],{"class":115},[109,972,26],{"class":119},[109,974,138],{"class":115},[109,976,977,979,981,983,986,988,990],{"class":111,"line":175},[109,978,116],{"class":115},[109,980,26],{"class":119},[109,982,336],{"class":115},[109,984,985],{"class":339},"{{ item.python }}",[109,987,343],{"class":115},[109,989,26],{"class":119},[109,991,138],{"class":115},[109,993,994,996,998],{"class":111,"line":208},[109,995,343],{"class":115},[109,997,23],{"class":119},[109,999,138],{"class":115},[11,1001,1002,1003,1006],{},"Laravelでは ",[57,1004,1005],{},"@for","ディレクティブでしたね。ですが基本的に似ています。",[779,1008,1009],{"id":1009},"if文",[11,1011,1012],{},"if文は以下の様に使用します。",[81,1014,1016],{"className":103,"code":1015,"language":105,"meta":89,"style":89},"{% if user.is_authenticated%}\n\u003Cli class=\"nav-item\">\n    \u003Ca class=\"nav-link\" href=\"{% url 'logout' %}\">ログアウト\u003C\u002Fa>\n\u003C\u002Fli>\n{% else %}\n\u003Cli class=\"nav-item\">\n    \u003Ca class=\"nav-link active\" aria-current=\"page\" href=\"{% url 'login' %}\">ログイン\u003C\u002Fa>\n\u003C\u002Fli>\n{% endif %}\n",[57,1017,1018,1023,1042,1081,1089,1094,1112,1163,1171],{"__ignoreMap":89},[109,1019,1020],{"class":111,"line":112},[109,1021,1022],{"class":339},"{% if user.is_authenticated%}\n",[109,1024,1025,1027,1029,1031,1033,1035,1038,1040],{"class":111,"line":141},[109,1026,116],{"class":115},[109,1028,26],{"class":119},[109,1030,389],{"class":122},[109,1032,126],{"class":115},[109,1034,129],{"class":115},[109,1036,1037],{"class":132},"nav-item",[109,1039,129],{"class":115},[109,1041,138],{"class":115},[109,1043,1044,1046,1048,1050,1052,1054,1057,1059,1061,1063,1065,1068,1070,1072,1075,1077,1079],{"class":111,"line":152},[109,1045,144],{"class":115},[109,1047,17],{"class":119},[109,1049,389],{"class":122},[109,1051,126],{"class":115},[109,1053,129],{"class":115},[109,1055,1056],{"class":132},"nav-link",[109,1058,129],{"class":115},[109,1060,248],{"class":122},[109,1062,126],{"class":115},[109,1064,129],{"class":115},[109,1066,1067],{"class":132},"{% url 'logout' %}",[109,1069,129],{"class":115},[109,1071,336],{"class":115},[109,1073,1074],{"class":339},"ログアウト",[109,1076,343],{"class":115},[109,1078,17],{"class":119},[109,1080,138],{"class":115},[109,1082,1083,1085,1087],{"class":111,"line":175},[109,1084,343],{"class":115},[109,1086,26],{"class":119},[109,1088,138],{"class":115},[109,1090,1091],{"class":111,"line":208},[109,1092,1093],{"class":339},"{% else %}\n",[109,1095,1096,1098,1100,1102,1104,1106,1108,1110],{"class":111,"line":240},[109,1097,116],{"class":115},[109,1099,26],{"class":119},[109,1101,389],{"class":122},[109,1103,126],{"class":115},[109,1105,129],{"class":115},[109,1107,1037],{"class":132},[109,1109,129],{"class":115},[109,1111,138],{"class":115},[109,1113,1114,1116,1118,1120,1122,1124,1127,1129,1132,1134,1136,1139,1141,1143,1145,1147,1150,1152,1154,1157,1159,1161],{"class":111,"line":298},[109,1115,144],{"class":115},[109,1117,17],{"class":119},[109,1119,389],{"class":122},[109,1121,126],{"class":115},[109,1123,129],{"class":115},[109,1125,1126],{"class":132},"nav-link active",[109,1128,129],{"class":115},[109,1130,1131],{"class":122}," aria-current",[109,1133,126],{"class":115},[109,1135,129],{"class":115},[109,1137,1138],{"class":132},"page",[109,1140,129],{"class":115},[109,1142,248],{"class":122},[109,1144,126],{"class":115},[109,1146,129],{"class":115},[109,1148,1149],{"class":132},"{% url 'login' %}",[109,1151,129],{"class":115},[109,1153,336],{"class":115},[109,1155,1156],{"class":339},"ログイン",[109,1158,343],{"class":115},[109,1160,17],{"class":119},[109,1162,138],{"class":115},[109,1164,1165,1167,1169],{"class":111,"line":328},[109,1166,343],{"class":115},[109,1168,26],{"class":119},[109,1170,138],{"class":115},[109,1172,1173],{"class":111,"line":350},[109,1174,1175],{"class":339},"{% endif %}\n",[11,1177,1002,1178,1181],{},[57,1179,1180],{},"@if","ディレクティブでした。基本的に似ています。上記の例はユーザーのログイン状態で表示を分岐しています。",[779,1183,1184],{"id":1184},"フィルタ",[11,1186,1187,1188,1191],{},"Laravelは",[57,1189,1190],{},"{{ count($value) }}"," のように変数展開しつつもメソッドを使用することができます。しかし、Djangoの場合は内部にロジックを書くことができません。その代わりフィルタというものを使用して変数の値を変更します。",[81,1193,1195],{"className":103,"code":1194,"language":105,"meta":89,"style":89},"\u003C!-- usersはリスト -->\n\u003Cp>登録者数は{{ users|length }}人です。\u003C\u002Fp>\n",[57,1196,1197,1202],{"__ignoreMap":89},[109,1198,1199],{"class":111,"line":112},[109,1200,1201],{"class":881},"\u003C!-- usersはリスト -->\n",[109,1203,1204,1206,1208,1210,1213,1215,1217],{"class":111,"line":141},[109,1205,116],{"class":115},[109,1207,11],{"class":119},[109,1209,336],{"class":115},[109,1211,1212],{"class":339},"登録者数は{{ users|length }}人です。",[109,1214,343],{"class":115},[109,1216,11],{"class":119},[109,1218,138],{"class":115},[11,1220,1221,1224],{},[57,1222,1223],{},"{{ 変数名|フィルタ名:\u003C引数など>}}","この様な入力規則になっています。",[81,1226,1228],{"className":103,"code":1227,"language":105,"meta":89,"style":89},"\u003Cp>作成日：{{ created_at|date:\"Y年m月d日 H:s:i\" }}\u003C\u002Fp>\n",[57,1229,1230],{"__ignoreMap":89},[109,1231,1232,1234,1236,1238,1241,1243,1245],{"class":111,"line":112},[109,1233,116],{"class":115},[109,1235,11],{"class":119},[109,1237,336],{"class":115},[109,1239,1240],{"class":339},"作成日：{{ created_at|date:\"Y年m月d日 H:s:i\" }}",[109,1242,343],{"class":115},[109,1244,11],{"class":119},[109,1246,138],{"class":115},[11,1248,1249,1250,1253],{},"上記の例は",[57,1251,1252],{},"created_at","を所定の日付フォーマットに変えるフィルタです。",[11,1255,1256,1257,1263],{},"使用可能なフィルタは",[17,1258,1262],{"href":1259,"rel":1260},"https:\u002F\u002Fdocs.djangoproject.com\u002Fja\u002F3.2\u002Fref\u002Ftemplates\u002Fbuiltins\u002F#built-in-filter-reference",[1261],"nofollow","こちらのドキュメントに記載","されています。",[779,1265,1267],{"id":1266},"url","URL",[11,1269,1002,1270,1273,1274,1276],{},[57,1271,1272],{},"route()"," というヘルパーを使用することで",[57,1275,725],{}," などで定義した名前付きルートのURLを出力できます。Djangoにも似た様なものがあり、以下の様に表現します。",[81,1278,1281],{"className":1279,"code":1280,"language":86},[84],"{% url \"index\" %}\n",[57,1282,1280],{"__ignoreMap":89},[11,1284,1285,1286,1289,1290,1293],{},"またキーワード引数がある場合、例えばブログ記事の詳細を",[57,1287,1288],{},"\u002Fblogs\u002F1"," のように示す場合",[57,1291,1292],{},"route('blogs',['blog_id'=>1])","のように引数を指定できます。Djangoも同様に",[81,1295,1298],{"className":1296,"code":1297,"language":86},[84],"{% url \"blogs\" blog_id=1 %}\n",[57,1299,1297],{"__ignoreMap":89},[11,1301,1302],{},"のように表示します。",[779,1304,1305],{"id":1305},"エスケープ解除",[11,1307,1308,1309,1312],{},"リッチテキストを表示したい時などLaravelでは",[57,1310,1311],{},"{!! !!}","とすることでエスケープを解除していました。Djangoの場合は２通りあります。",[11,1314,1315],{},"１つはsafeフィルタを使う方法と、２つ目はエスケープ解除ディレクティブで囲むことです。",[81,1317,1319],{"className":103,"code":1318,"language":105,"meta":89,"style":89},"\u003Cdiv class=\"editor\">\n{{ value|safe }}\n\u003C\u002Fdiv>\n\n{% autoescape off %}\n\u003Cdiv class=\"editor\">\n    {{ value }}\n\u003C\u002Fdiv>\n{% endautoescape %}\n\n",[57,1320,1321,1340,1345,1353,1357,1362,1380,1385,1393],{"__ignoreMap":89},[109,1322,1323,1325,1327,1329,1331,1333,1336,1338],{"class":111,"line":112},[109,1324,116],{"class":115},[109,1326,409],{"class":119},[109,1328,389],{"class":122},[109,1330,126],{"class":115},[109,1332,129],{"class":115},[109,1334,1335],{"class":132},"editor",[109,1337,129],{"class":115},[109,1339,138],{"class":115},[109,1341,1342],{"class":111,"line":141},[109,1343,1344],{"class":339},"{{ value|safe }}\n",[109,1346,1347,1349,1351],{"class":111,"line":152},[109,1348,343],{"class":115},[109,1350,409],{"class":119},[109,1352,138],{"class":115},[109,1354,1355],{"class":111,"line":175},[109,1356,680],{"emptyLinePlaceholder":679},[109,1358,1359],{"class":111,"line":208},[109,1360,1361],{"class":339},"{% autoescape off %}\n",[109,1363,1364,1366,1368,1370,1372,1374,1376,1378],{"class":111,"line":240},[109,1365,116],{"class":115},[109,1367,409],{"class":119},[109,1369,389],{"class":122},[109,1371,126],{"class":115},[109,1373,129],{"class":115},[109,1375,1335],{"class":132},[109,1377,129],{"class":115},[109,1379,138],{"class":115},[109,1381,1382],{"class":111,"line":298},[109,1383,1384],{"class":339},"    {{ value }}\n",[109,1386,1387,1389,1391],{"class":111,"line":328},[109,1388,343],{"class":115},[109,1390,409],{"class":119},[109,1392,138],{"class":115},[109,1394,1395],{"class":111,"line":350},[109,1396,1397],{"class":339},"{% endautoescape %}\n",[409,1399,1402],{"className":1400},[772,1401],"alert-danger","\nエスケープを解除するとXSS脆弱性の元になります。展開する変数のチェックを怠らない様にしましょう。\n",[50,1404,1405],{"id":1405},"テンプレートの共通化と継承",[11,1407,1408,1409,1412,1413,1416,1417,1419],{},"Laravelのテンプレートには ",[57,1410,1411],{},"@extends"," や",[57,1414,1415],{},"@section","をなどを用いて共通化を行うことができます。Djangoでも同じ様な方法で共通化が行えます。例えば",[57,1418,78],{}," に共通のヘッダやメニューなどを書いておき、任意のテンプレートに継承させてコンテンツだけ出力させることができます。",[81,1421,1424],{"className":103,"code":1422,"filename":1423,"language":105,"meta":89,"style":89},"\u003Chtml>\n    \u003Chead>\n        \u003Cmeta charset=\"utf-8\">\n        \u003Cmeta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n        \u003Cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n        \u003Ctitle>{% block title %}{% endblock  %}\u003C\u002Ftitle>\n    \u003C\u002Fhead>\n    \u003Cbody>\n        \u003Cheader>\n            \u003C!-- 省略 -->\n        \u003C\u002Fheader>\n        \u003Cmain>\n            {% block content %}{% endblock  %}\n        \u003C\u002Fmain>\n        \u003Cfooter>\n            \u003C!-- 省略 -->\n        \u003C\u002Ffooter>\n    \u003C\u002Fbody>\n\u003C\u002Fhtml>\n","templates\u002Fbase.html",[57,1425,1426,1434,1442,1460,1488,1516,1533,1541,1549,1557,1562,1570,1578,1583,1591,1599,1603,1611,1619],{"__ignoreMap":89},[109,1427,1428,1430,1432],{"class":111,"line":112},[109,1429,116],{"class":115},[109,1431,105],{"class":119},[109,1433,138],{"class":115},[109,1435,1436,1438,1440],{"class":111,"line":141},[109,1437,144],{"class":115},[109,1439,147],{"class":119},[109,1441,138],{"class":115},[109,1443,1444,1446,1448,1450,1452,1454,1456,1458],{"class":111,"line":152},[109,1445,155],{"class":115},[109,1447,158],{"class":119},[109,1449,161],{"class":122},[109,1451,126],{"class":115},[109,1453,129],{"class":115},[109,1455,168],{"class":132},[109,1457,129],{"class":115},[109,1459,138],{"class":115},[109,1461,1462,1464,1466,1468,1470,1472,1474,1476,1478,1480,1482,1484,1486],{"class":111,"line":175},[109,1463,155],{"class":115},[109,1465,158],{"class":119},[109,1467,182],{"class":122},[109,1469,126],{"class":115},[109,1471,129],{"class":115},[109,1473,189],{"class":132},[109,1475,129],{"class":115},[109,1477,194],{"class":122},[109,1479,126],{"class":115},[109,1481,129],{"class":115},[109,1483,201],{"class":132},[109,1485,129],{"class":115},[109,1487,138],{"class":115},[109,1489,1490,1492,1494,1496,1498,1500,1502,1504,1506,1508,1510,1512,1514],{"class":111,"line":208},[109,1491,155],{"class":115},[109,1493,158],{"class":119},[109,1495,215],{"class":122},[109,1497,126],{"class":115},[109,1499,129],{"class":115},[109,1501,222],{"class":132},[109,1503,129],{"class":115},[109,1505,194],{"class":122},[109,1507,126],{"class":115},[109,1509,129],{"class":115},[109,1511,233],{"class":132},[109,1513,129],{"class":115},[109,1515,138],{"class":115},[109,1517,1518,1520,1522,1524,1527,1529,1531],{"class":111,"line":240},[109,1519,155],{"class":115},[109,1521,333],{"class":119},[109,1523,336],{"class":115},[109,1525,1526],{"class":339},"{% block title %}{% endblock  %}",[109,1528,343],{"class":115},[109,1530,333],{"class":119},[109,1532,138],{"class":115},[109,1534,1535,1537,1539],{"class":111,"line":298},[109,1536,353],{"class":115},[109,1538,147],{"class":119},[109,1540,138],{"class":115},[109,1542,1543,1545,1547],{"class":111,"line":328},[109,1544,144],{"class":115},[109,1546,365],{"class":119},[109,1548,138],{"class":115},[109,1550,1551,1553,1555],{"class":111,"line":350},[109,1552,155],{"class":115},[109,1554,375],{"class":119},[109,1556,138],{"class":115},[109,1558,1559],{"class":111,"line":360},[109,1560,1561],{"class":881},"            \u003C!-- 省略 -->\n",[109,1563,1564,1566,1568],{"class":111,"line":370},[109,1565,489],{"class":115},[109,1567,375],{"class":119},[109,1569,138],{"class":115},[109,1571,1572,1574,1576],{"class":111,"line":380},[109,1573,155],{"class":115},[109,1575,501],{"class":119},[109,1577,138],{"class":115},[109,1579,1580],{"class":111,"line":403},[109,1581,1582],{"class":339},"            {% block content %}{% endblock  %}\n",[109,1584,1585,1587,1589],{"class":111,"line":425},[109,1586,489],{"class":115},[109,1588,501],{"class":119},[109,1590,138],{"class":115},[109,1592,1593,1595,1597],{"class":111,"line":466},[109,1594,155],{"class":115},[109,1596,566],{"class":119},[109,1598,138],{"class":115},[109,1600,1601],{"class":111,"line":476},[109,1602,1561],{"class":881},[109,1604,1605,1607,1609],{"class":111,"line":486},[109,1606,489],{"class":115},[109,1608,566],{"class":119},[109,1610,138],{"class":115},[109,1612,1613,1615,1617],{"class":111,"line":496},[109,1614,353],{"class":115},[109,1616,365],{"class":119},[109,1618,138],{"class":115},[109,1620,1621,1623,1625],{"class":111,"line":517},[109,1622,343],{"class":115},[109,1624,105],{"class":119},[109,1626,138],{"class":115},[11,1628,1629,1631,1632,1635],{},[57,1630,78],{},"では共通のヘッダーなどを定義しておきます。そして",[57,1633,1634],{},"{% block content %}{% endblock  %}","で子テンプレートで入力できる値を定義します。ここではタイトル（title）と内容（content）を入力できる様にします。",[81,1637,1640],{"className":103,"code":1638,"filename":1639,"language":105,"meta":89,"style":89},"{% extends 'base.html' %}\n\n{% block title %}詳細ページ{% endblock  %}\n\n{% block content %}\n\u003Cp> content \u003C\u002Fp>\n{% endblock  %}\n","templates\u002Fdetail.html",[57,1641,1642,1647,1651,1656,1660,1665,1682],{"__ignoreMap":89},[109,1643,1644],{"class":111,"line":112},[109,1645,1646],{"class":339},"{% extends 'base.html' %}\n",[109,1648,1649],{"class":111,"line":141},[109,1650,680],{"emptyLinePlaceholder":679},[109,1652,1653],{"class":111,"line":152},[109,1654,1655],{"class":339},"{% block title %}詳細ページ{% endblock  %}\n",[109,1657,1658],{"class":111,"line":175},[109,1659,680],{"emptyLinePlaceholder":679},[109,1661,1662],{"class":111,"line":208},[109,1663,1664],{"class":339},"{% block content %}\n",[109,1666,1667,1669,1671,1673,1676,1678,1680],{"class":111,"line":240},[109,1668,116],{"class":115},[109,1670,11],{"class":119},[109,1672,336],{"class":115},[109,1674,1675],{"class":339}," content ",[109,1677,343],{"class":115},[109,1679,11],{"class":119},[109,1681,138],{"class":115},[109,1683,1684],{"class":111,"line":298},[109,1685,1686],{"class":339},"{% endblock  %}\n",[11,1688,1689,1690,1692],{},"小テンプレート では上記の様に書くことで、親の",[57,1691,78],{}," に当てはめられた形でレンダリングされます。",[39,1694,1695],{"id":1695},"静的ファイルの呼び出し",[11,1697,1698,1699,1702,1703,1706,1707,1706,1710,1713,1714,1717],{},"プロジェクトで配置しておくcss,js,画像といった静的ファイルをLaraveで扱うときは",[57,1700,1701],{},"public\u002F"," ディレクトリ配下に",[57,1704,1705],{},"css\u002F",",",[57,1708,1709],{},"js\u002F",[57,1711,1712],{},"images\u002F","などを配置して ",[57,1715,1716],{},"{{assets('\u002Fcss\u002Fstyle.css')}}"," とすることで自動的にパスの解決をしてくれます。",[11,1719,1720],{},"Djangoで静的ファイルを利用するためには２つほど設定が必要です。",[50,1722,1724],{"id":1723},"settingpyでの設定","setting.pyでの設定",[11,1726,1727,1728,1731],{},"まず",[57,1729,1730],{},"setting.py"," にて静的ファイルを配置するディレクトリの設定を確認します。",[39,1733,1734],{"id":1734},"認証機能実装",[50,1736,1738],{"id":1737},"djangoの基本機能を使用する","Djangoの基本機能を使用する",[50,1740,1741],{"id":1741},"ユーザー登録",[50,1743,1156],{"id":1156},[50,1745,1746],{"id":1746},"パスワード忘れ",[50,1748,1749],{"id":1749},"メールアドレスに変更する",[1751,1752,1753],"style",{},"html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sC9rS, html code.shiki .sC9rS{--shiki-default:#464B5D;--shiki-default-font-style:italic}",{"title":89,"searchDepth":152,"depth":152,"links":1755},[1756,1770,1773],{"id":41,"depth":141,"text":42,"children":1757},[1758,1759,1760,1761,1769],{"id":52,"depth":152,"text":52},{"id":95,"depth":152,"text":95},{"id":644,"depth":152,"text":644},{"id":777,"depth":152,"text":777,"children":1762},[1763,1764,1765,1766,1767,1768],{"id":781,"depth":175,"text":781},{"id":868,"depth":175,"text":868},{"id":1009,"depth":175,"text":1009},{"id":1184,"depth":175,"text":1184},{"id":1266,"depth":175,"text":1267},{"id":1305,"depth":175,"text":1305},{"id":1405,"depth":152,"text":1405},{"id":1695,"depth":141,"text":1695,"children":1771},[1772],{"id":1723,"depth":152,"text":1724},{"id":1734,"depth":141,"text":1734,"children":1774},[1775,1776,1777,1778,1779],{"id":1737,"depth":152,"text":1738},{"id":1741,"depth":152,"text":1741},{"id":1156,"depth":152,"text":1156},{"id":1746,"depth":152,"text":1746},{"id":1749,"depth":152,"text":1749},[1781],"devstack","2022-02-13","ビューと認証の構築を行います","md",{},"\u002Fseries\u002Flaravel-to-django-2",false,{"title":6,"description":1783},"laravel_to_django","Laravel使いがDjangoでwebアプリを作るよ","series\u002Flaravel-to-django-2",[1793,657,1794,726],"django","laravel","laralve_to_django\u002Fthumbnail.png",null,"TmNXrWmCS1lg0MAxTXzLdzGEE-1FXZWpN43q3D-FCsc",{"id":1799,"title":1800,"body":1801,"category":3315,"createdAt":3316,"description":3317,"extension":1784,"index":112,"meta":3318,"navigation":679,"path":3319,"publish":679,"seo":3320,"series":1789,"seriesTitle":1790,"stem":3321,"tag":3322,"thumbnail":1795,"updatedAt":1796,"__hash__":3323},"series\u002Fseries\u002Flaravel-to-django-1.md","Laravel使いがDjangoでwebアプリを作るよその１：アプリの概要と環境構築",{"type":8,"value":1802,"toc":3295},[1803,1806,1809,1812,1823,1826,1829,1832,1852,1855,1858,1877,1880,1887,1937,1944,1948,1951,1992,1995,1998,2003,2331,2337,2347,2361,2368,2385,2408,2413,2419,2434,2437,2440,2443,2446,2477,2480,2520,2523,2534,2537,2540,2544,2547,2550,2560,2620,2623,2679,2692,2695,2698,2773,2789,2792,2805,3086,3089,3106,3109,3116,3122,3129,3135,3144,3152,3162,3181,3188,3197,3200,3250,3257,3286,3289,3292],[11,1804,1805],{},"こんにちはjunです。最近Laravelでシステムを作る機会が何回かあったので、Laravelによる構築がかなり得意になってきました。しかし会社の方で「pythonを使用した機械学習や統計の機能をwebアプリとして使用できるアプリを開発したい」という企画がでてきました。",[11,1807,1808],{},"pythonで機械学習や統計の処理（モデル）を作成し、UIやロジックの部分をwebフレームワークで作成します。できたらwebフレームワークの処理部分にて統計ロジックをimportして、データの引き渡しを行いたいと思いました。しかしLaravelはPHPなので連携が難しいです。",[11,1810,1811],{},"そのため「Python製のwebフレームワークであるdjangoを利用できないか？」と思い、Djangoの勉強をスタートしました。チュートリアルはひとまず終えましたが、Laravelをやっていたおかげで",[23,1813,1814,1817,1820],{},[26,1815,1816],{},"どんな機能があると便利か？",[26,1818,1819],{},"Laravelのこの機能がDjangoのこの記述にあたるのか？",[26,1821,1822],{},"実務上必要となるこの機能を実装するには何を使えばいいのか？",[11,1824,1825],{},"という視点を用いて学習することができました。このシリーズでは「Laravelを使っていたPHP開発者がDjangoとPythonを使用してアプリを作る」ことを通じてDjangoの学習をしたいと思っています。記事内ではDjangoにおける実装とLaravelにおける実装をリンクしながら解説していきたいと思います。",[11,1827,1828],{},"利用するDjangoのバージョンは3.2で、Laravelは8とします。第１回のこの記事は環境構築とアプリの概要、Djangoの開発コンセプトやディレクトリ説明がメインとなります。",[11,1830,1831],{},"なおシリーズでは以下の内容を押さえていることを前提としています",[23,1833,1834,1837,1840,1843,1846,1849],{},[26,1835,1836],{},"Laravelの実務開発経験があるまたは、完成したアプリを作ったことがある。",[26,1838,1839],{},"Laravelのコンセプトやディレクトリ構成を知っている。",[26,1841,1842],{},"PythonがPCにインストールされ、基本的な記述を理解している。",[26,1844,1845],{},"PHPを触ったことが多いが、Pythonはそれほどない。",[26,1847,1848],{},"Djangoのチュートリアルは行っており、必須の内容は知っている。",[26,1850,1851],{},"MVCの概念を知っている、使える。",[11,1853,1854],{},"それでは早速始めていきましょう。",[11,1856,1857],{},"参考資料",[23,1859,1860,1867,1870],{},[26,1861,1862],{},[17,1863,1866],{"href":1864,"rel":1865},"https:\u002F\u002Fdocs.djangoproject.com\u002Fja\u002F3.2",[1261],"Django ドキュメント3.2",[26,1868,1869],{},"書籍『現場で使える Django の教科書』",[26,1871,1872],{},[17,1873,1876],{"href":1874,"rel":1875},"https:\u002F\u002Fdocs.docker.jp\u002Fcompose\u002Fdjango.html",[1261],"クィックスタート: Compose と Django - Docker ドキュメント",[39,1878,1879],{"id":1879},"環境構築",[11,1881,1882,1883,1886],{},"今回の環境構築はdockerを用いて作成しようと思います。適当なディレクトリ を作成し、",[57,1884,1885],{},"docker-compose.yaml","とビルドファイルを作成します。",[81,1888,1892],{"className":1889,"code":1890,"language":1891,"meta":89,"style":89},"language-bash shiki shiki-themes material-theme-ocean","mkdir laravel_django\ncd laravel_django\n\ntouch Dockerfile\ntouch docker-compose.yaml\nmkdir source\n","bash",[57,1893,1894,1903,1911,1915,1923,1930],{"__ignoreMap":89},[109,1895,1896,1900],{"class":111,"line":112},[109,1897,1899],{"class":1898},"s5Dmg","mkdir",[109,1901,1902],{"class":132}," laravel_django\n",[109,1904,1905,1909],{"class":111,"line":141},[109,1906,1908],{"class":1907},"sdLwU","cd",[109,1910,1902],{"class":132},[109,1912,1913],{"class":111,"line":152},[109,1914,680],{"emptyLinePlaceholder":679},[109,1916,1917,1920],{"class":111,"line":175},[109,1918,1919],{"class":1898},"touch",[109,1921,1922],{"class":132}," Dockerfile\n",[109,1924,1925,1927],{"class":111,"line":208},[109,1926,1919],{"class":1898},[109,1928,1929],{"class":132}," docker-compose.yaml\n",[109,1931,1932,1934],{"class":111,"line":240},[109,1933,1899],{"class":1898},[109,1935,1936],{"class":132}," source\n",[11,1938,1939,1940,1943],{},"まずはDockerfileでDjangoが稼働するpythonの環境を作成します。なお、この環境ではApacheやnginxといったwebサーバーとpythonとの連携設定は行わないものとします。コンテナ内で",[57,1941,1942],{},"run serve","を行います。",[50,1945,1947],{"id":1946},"dockerfile","Dockerfile",[11,1949,1950],{},"Dockerfileを以下の様に記述します。",[81,1952,1955],{"className":1953,"code":1954,"language":1947,"meta":89,"style":89},"language-Dockerfile shiki shiki-themes material-theme-ocean","FROM python:3\nENV PYTHONUNBUFFERED 1\nRUN mkdir \u002Fcode\nWORKDIR \u002Fcode\nADD requirements.txt \u002Fcode\u002F\nRUN pip install -r requirements.txt\nADD . \u002Fcode\u002F\n",[57,1956,1957,1962,1967,1972,1977,1982,1987],{"__ignoreMap":89},[109,1958,1959],{"class":111,"line":112},[109,1960,1961],{},"FROM python:3\n",[109,1963,1964],{"class":111,"line":141},[109,1965,1966],{},"ENV PYTHONUNBUFFERED 1\n",[109,1968,1969],{"class":111,"line":152},[109,1970,1971],{},"RUN mkdir \u002Fcode\n",[109,1973,1974],{"class":111,"line":175},[109,1975,1976],{},"WORKDIR \u002Fcode\n",[109,1978,1979],{"class":111,"line":208},[109,1980,1981],{},"ADD requirements.txt \u002Fcode\u002F\n",[109,1983,1984],{"class":111,"line":240},[109,1985,1986],{},"RUN pip install -r requirements.txt\n",[109,1988,1989],{"class":111,"line":298},[109,1990,1991],{},"ADD . \u002Fcode\u002F\n",[11,1993,1994],{},"python3 イメージをもとにpythonが動く環境を用意します。",[50,1996,1997],{"id":1997},"docker-compose",[11,1999,2000,2002],{},[57,2001,1885],{},"は以下の様に記述します。",[81,2004,2008],{"className":2005,"code":2006,"filename":1885,"language":2007,"meta":89,"style":89},"language-yaml shiki shiki-themes material-theme-ocean","version: '3'\n\nservices:\n  db:\n    image: mysql:5.7\n    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci\n    environment:\n      MYSQL_DATABASE: preform\n      MYSQL_USER: test\n      MYSQL_PASSWORD: testtest\n      MYSQL_ROOT_PASSWORD: rootroot\n      TZ: Asia\u002FTokyo\n    ports: \n      - \"3306:3306\"\n    volumes: \n      - djangodemo:\u002Fvar\u002Flib\u002Fmysql\n  phpmyadmin:\n    image: phpmyadmin\n    ports:\n      - \"8080:80\"\n    environment:\n     - PMA_ARBITRARY=1\n     - PMA_HOST=db:3306\n     - PMA_USER=root\n     - PMA_PASSWORD=rootroot\n  web:\n    build: .\n    command: python3 manage.py runserver 0.0.0.0:8000\n    volumes:\n      - .\u002Fsource:\u002Fcode\n    ports:\n      - \"8000:8000\"\n    depends_on:\n      - db\nvolumes: \n  djangodemo: {}\n","yaml",[57,2009,2010,2027,2031,2039,2046,2056,2066,2073,2083,2093,2103,2113,2123,2133,2147,2156,2163,2170,2179,2185,2196,2202,2210,2217,2224,2231,2238,2250,2260,2267,2275,2282,2294,2302,2310,2320],{"__ignoreMap":89},[109,2011,2012,2015,2018,2021,2024],{"class":111,"line":112},[109,2013,2014],{"class":119},"version",[109,2016,2017],{"class":115},":",[109,2019,2020],{"class":115}," '",[109,2022,2023],{"class":132},"3",[109,2025,2026],{"class":115},"'\n",[109,2028,2029],{"class":111,"line":141},[109,2030,680],{"emptyLinePlaceholder":679},[109,2032,2033,2036],{"class":111,"line":152},[109,2034,2035],{"class":119},"services",[109,2037,2038],{"class":115},":\n",[109,2040,2041,2044],{"class":111,"line":175},[109,2042,2043],{"class":119},"  db",[109,2045,2038],{"class":115},[109,2047,2048,2051,2053],{"class":111,"line":208},[109,2049,2050],{"class":119},"    image",[109,2052,2017],{"class":115},[109,2054,2055],{"class":132}," mysql:5.7\n",[109,2057,2058,2061,2063],{"class":111,"line":240},[109,2059,2060],{"class":119},"    command",[109,2062,2017],{"class":115},[109,2064,2065],{"class":132}," mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci\n",[109,2067,2068,2071],{"class":111,"line":298},[109,2069,2070],{"class":119},"    environment",[109,2072,2038],{"class":115},[109,2074,2075,2078,2080],{"class":111,"line":328},[109,2076,2077],{"class":119},"      MYSQL_DATABASE",[109,2079,2017],{"class":115},[109,2081,2082],{"class":132}," preform\n",[109,2084,2085,2088,2090],{"class":111,"line":350},[109,2086,2087],{"class":119},"      MYSQL_USER",[109,2089,2017],{"class":115},[109,2091,2092],{"class":132}," test\n",[109,2094,2095,2098,2100],{"class":111,"line":360},[109,2096,2097],{"class":119},"      MYSQL_PASSWORD",[109,2099,2017],{"class":115},[109,2101,2102],{"class":132}," testtest\n",[109,2104,2105,2108,2110],{"class":111,"line":370},[109,2106,2107],{"class":119},"      MYSQL_ROOT_PASSWORD",[109,2109,2017],{"class":115},[109,2111,2112],{"class":132}," rootroot\n",[109,2114,2115,2118,2120],{"class":111,"line":380},[109,2116,2117],{"class":119},"      TZ",[109,2119,2017],{"class":115},[109,2121,2122],{"class":132}," Asia\u002FTokyo\n",[109,2124,2125,2128,2130],{"class":111,"line":403},[109,2126,2127],{"class":119},"    ports",[109,2129,2017],{"class":115},[109,2131,2132],{"class":339}," \n",[109,2134,2135,2138,2141,2144],{"class":111,"line":425},[109,2136,2137],{"class":115},"      -",[109,2139,2140],{"class":115}," \"",[109,2142,2143],{"class":132},"3306:3306",[109,2145,2146],{"class":115},"\"\n",[109,2148,2149,2152,2154],{"class":111,"line":466},[109,2150,2151],{"class":119},"    volumes",[109,2153,2017],{"class":115},[109,2155,2132],{"class":339},[109,2157,2158,2160],{"class":111,"line":476},[109,2159,2137],{"class":115},[109,2161,2162],{"class":132}," djangodemo:\u002Fvar\u002Flib\u002Fmysql\n",[109,2164,2165,2168],{"class":111,"line":486},[109,2166,2167],{"class":119},"  phpmyadmin",[109,2169,2038],{"class":115},[109,2171,2172,2174,2176],{"class":111,"line":496},[109,2173,2050],{"class":119},[109,2175,2017],{"class":115},[109,2177,2178],{"class":132}," phpmyadmin\n",[109,2180,2181,2183],{"class":111,"line":517},[109,2182,2127],{"class":119},[109,2184,2038],{"class":115},[109,2186,2187,2189,2191,2194],{"class":111,"line":537},[109,2188,2137],{"class":115},[109,2190,2140],{"class":115},[109,2192,2193],{"class":132},"8080:80",[109,2195,2146],{"class":115},[109,2197,2198,2200],{"class":111,"line":543},[109,2199,2070],{"class":119},[109,2201,2038],{"class":115},[109,2203,2204,2207],{"class":111,"line":552},[109,2205,2206],{"class":115},"     -",[109,2208,2209],{"class":132}," PMA_ARBITRARY=1\n",[109,2211,2212,2214],{"class":111,"line":561},[109,2213,2206],{"class":115},[109,2215,2216],{"class":132}," PMA_HOST=db:3306\n",[109,2218,2219,2221],{"class":111,"line":576},[109,2220,2206],{"class":115},[109,2222,2223],{"class":132}," PMA_USER=root\n",[109,2225,2226,2228],{"class":111,"line":623},[109,2227,2206],{"class":115},[109,2229,2230],{"class":132}," PMA_PASSWORD=rootroot\n",[109,2232,2233,2236],{"class":111,"line":632},[109,2234,2235],{"class":119},"  web",[109,2237,2038],{"class":115},[109,2239,2241,2244,2246],{"class":111,"line":2240},27,[109,2242,2243],{"class":119},"    build",[109,2245,2017],{"class":115},[109,2247,2249],{"class":2248},"sx098"," .\n",[109,2251,2253,2255,2257],{"class":111,"line":2252},28,[109,2254,2060],{"class":119},[109,2256,2017],{"class":115},[109,2258,2259],{"class":132}," python3 manage.py runserver 0.0.0.0:8000\n",[109,2261,2263,2265],{"class":111,"line":2262},29,[109,2264,2151],{"class":119},[109,2266,2038],{"class":115},[109,2268,2270,2272],{"class":111,"line":2269},30,[109,2271,2137],{"class":115},[109,2273,2274],{"class":132}," .\u002Fsource:\u002Fcode\n",[109,2276,2278,2280],{"class":111,"line":2277},31,[109,2279,2127],{"class":119},[109,2281,2038],{"class":115},[109,2283,2285,2287,2289,2292],{"class":111,"line":2284},32,[109,2286,2137],{"class":115},[109,2288,2140],{"class":115},[109,2290,2291],{"class":132},"8000:8000",[109,2293,2146],{"class":115},[109,2295,2297,2300],{"class":111,"line":2296},33,[109,2298,2299],{"class":119},"    depends_on",[109,2301,2038],{"class":115},[109,2303,2305,2307],{"class":111,"line":2304},34,[109,2306,2137],{"class":115},[109,2308,2309],{"class":132}," db\n",[109,2311,2313,2316,2318],{"class":111,"line":2312},35,[109,2314,2315],{"class":119},"volumes",[109,2317,2017],{"class":115},[109,2319,2132],{"class":339},[109,2321,2323,2326,2328],{"class":111,"line":2322},36,[109,2324,2325],{"class":119},"  djangodemo",[109,2327,2017],{"class":115},[109,2329,2330],{"class":115}," {}\n",[11,2332,2333,2336],{},[57,2334,2335],{},"db","ではデータベースを定義しています。DjangoはSQLiteを使用した簡易的なDBが用意されています。ただし実務ではmysqlなどのDBサーバーを使用することが多いので、今回はmysqlを使用できる様にします。",[409,2338,2341,2342],{"className":2339},[772,2340],"alert-info","\nDjangoでmysqlを使用するためにはpythonモジュールのmysqlclientが必要です。この環境にはデフォルトでないので注意してください。他のDBサーバーを使用する場合は適宜ドライバをインストールしてください。\n",[17,2343,2346],{"target":2344,"href":2345},"_blank","https:\u002F\u002Fdocs.djangoproject.com\u002Fja\u002F3.2\u002Ftopics\u002Finstall\u002F#get-your-database-running","本家ドキュメントを参照",[11,2348,2349,2350,2353,2354,2356,2357,2360],{},"DB内部をすぐに確認できる様にphpmyadminを入れておきます。（好みなのでなくてもいいです。）\nそして",[57,2351,2352],{},"web","では同階層にある",[57,2355,1947],{},"をビルドして実行できる様になります。立ち上げ時に",[57,2358,2359],{},"python3 manage.py runserver 0.0.0.0:8000","をしてwebサーバを立ち上げる設定にしています。",[11,2362,2363,2364,2367],{},"このコンテナを起動する前に ",[57,2365,2366],{},"requirements.txt"," をDockerfileと同じ階層に生成しておき、以下の内容を記述します。",[81,2369,2373],{"className":2370,"code":2371,"filename":2366,"language":2372,"meta":89,"style":89},"language-txt shiki shiki-themes material-theme-ocean","Django==3.2\nmysqlclient==2.1.0\n","txt",[57,2374,2375,2380],{"__ignoreMap":89},[109,2376,2377],{"class":111,"line":112},[109,2378,2379],{},"Django==3.2\n",[109,2381,2382],{"class":111,"line":141},[109,2383,2384],{},"mysqlclient==2.1.0\n",[11,2386,2387,2389,2390,2393,2394,2397,2398,2400,2401,2403,2404,2407],{},[57,2388,2366],{}," はpythonライブラリ管理ツールpipの設定ファイルです。npmの",[57,2391,2392],{},"package.json","やcomposerの",[57,2395,2396],{},"composer.json","といったものと同じです。pythonのモジュール管理はpipを使用することが多く、",[57,2399,2366],{}," は環境ないの依存するモジュールとそのバージョンを記述して配置しておきます。そして",[57,2402,2366],{}," がある階層で ",[57,2405,2406],{},"pip install","をすることで自動的に依存関係をインストールしてくれます。Django3.2とmysqlclientを記述しておきます。",[11,2409,2410,2412],{},[57,2411,2366],{},"を記述したら以下のコマンドを実行してDjangoのソースを作成します。",[81,2414,2417],{"className":2415,"code":2416,"language":86},[84],"docker-compose run web django-admin.py startproject djangodemo .\n",[57,2418,2416],{"__ignoreMap":89},[11,2420,2421,2422,2425,2426,2429,2430,2433],{},"すると",[57,2423,2424],{},"source\u002F","配下にDjangoのソースが生成されるはずです。\nそして準備が整ったら",[57,2427,2428],{},"docker-compose up -d --build"," を行って構築を行います。問題なくいった場合はブラウザにて ",[57,2431,2432],{},"localhost:8000"," を閲覧すると、Djangoのウェルカムページが表示されるはずです。",[762,2435],{":src":2436,":width":765},"'laralve_to_django\u002Fwelcome.png'",[39,2438,2439],{"id":2439},"アプリ概要",[11,2441,2442],{},"今回作成するアプリはn○teみたいなブログサービスを作成しようと思います。",[779,2444,2445],{"id":2445},"ユーザー系の特徴",[23,2447,2448,2451,2454,2457,2460,2463],{},[26,2449,2450],{},"利用する際にはユーザーとしてアカウントを作る（今回は全てゲストとする）。",[26,2452,2453],{},"ログインはアドレスとパスワードを使用する。",[26,2455,2456],{},"アプリを利用する一般ユーザーと管理を行う管理ユーザーが存在する。",[26,2458,2459],{},"管理ユーザーは特定の管理用ルートから入る。",[26,2461,2462],{},"退会可能。退会時は関連するデータは削除される。",[26,2464,2465,2466],{},"プロフィールでは以下の項目を持つ\n",[23,2467,2468,2471,2474],{},[26,2469,2470],{},"ユーザー名（仮名）",[26,2472,2473],{},"プロフィール文",[26,2475,2476],{},"アバター写真",[779,2478,2479],{"id":2479},"ブログ機能",[23,2481,2482,2485,2502,2505,2508,2511,2514,2517],{},[26,2483,2484],{},"ブログを作成することができ、公開することができる。",[26,2486,2487,2488],{},"ブログは以下の項目を持つ\n",[23,2489,2490,2493,2496,2499],{},[26,2491,2492],{},"タイトル",[26,2494,2495],{},"内容（リッチテキスト）",[26,2497,2498],{},"タグ（任意）",[26,2500,2501],{},"公開日時",[26,2503,2504],{},"下書きとして保存することができる。更新時も下書き可能。",[26,2506,2507],{},"任意数のタグを添付できる。タグはユーザーが新しく作成できる。",[26,2509,2510],{},"削除可能",[26,2512,2513],{},"画像の添付が可能。",[26,2515,2516],{},"アップロードした画像は管理できる。",[26,2518,2519],{},"公開側からコメント可能",[779,2521,2522],{"id":2522},"一覧検索機能",[23,2524,2525,2528,2531],{},[26,2526,2527],{},"サイトトップは投稿された記事が新着順に並ぶ。",[26,2529,2530],{},"任意のタグを選んで一覧表示することが可能。",[26,2532,2533],{},"部分一致検索も一応可能とする。",[11,2535,2536],{},"一通りユーザーエンティティから、記事のCURD、リレーションの練習はできると思います。すべてのビューはpython側でレンダリングを行い、Vue.jsなどは今回使用しません。違う機会にrest apiを使用した構成を作ってみたいとおおいます。",[11,2538,2539],{},"デザインに関してはいつものbootstrapを使用します。",[39,2541,2543],{"id":2542},"djangoの大まかな解説","Djangoの大まかな解説",[11,2545,2546],{},"詳細なロジックなどは次の記事で解説したいと思います。今回はDjangoのディレクトリ構成やLaravelと似ているとこやリンクしている中核的な機能を解説したいと思います。",[50,2548,2549],{"id":2549},"コマンドによる制御",[11,2551,1002,2552,2555,2556,2559],{},[57,2553,2554],{},"php artisan"," を使用することでコントローラーを作ったり、マイグレーションを実行したりできます。Djangoにも似た様なものがあります。使用する時はソーストップの ",[57,2557,2558],{},"manage.py"," がある箇所で実行します。例えば以下の様な機能があります。",[81,2561,2563],{"className":1889,"code":2562,"language":1891,"meta":89,"style":89},"# 簡易webサーバーを起動\npython3 manage.py runserve\n\n# マイグレーションを実行\npython3 manage.py migrate\n\n# アプリのテンプレートを作成\npython3 manage.py startapp APP_NAME\n\n",[57,2564,2565,2570,2581,2585,2590,2599,2603,2608],{"__ignoreMap":89},[109,2566,2567],{"class":111,"line":112},[109,2568,2569],{"class":881},"# 簡易webサーバーを起動\n",[109,2571,2572,2575,2578],{"class":111,"line":141},[109,2573,2574],{"class":1898},"python3",[109,2576,2577],{"class":132}," manage.py",[109,2579,2580],{"class":132}," runserve\n",[109,2582,2583],{"class":111,"line":152},[109,2584,680],{"emptyLinePlaceholder":679},[109,2586,2587],{"class":111,"line":175},[109,2588,2589],{"class":881},"# マイグレーションを実行\n",[109,2591,2592,2594,2596],{"class":111,"line":208},[109,2593,2574],{"class":1898},[109,2595,2577],{"class":132},[109,2597,2598],{"class":132}," migrate\n",[109,2600,2601],{"class":111,"line":240},[109,2602,680],{"emptyLinePlaceholder":679},[109,2604,2605],{"class":111,"line":298},[109,2606,2607],{"class":881},"# アプリのテンプレートを作成\n",[109,2609,2610,2612,2614,2617],{"class":111,"line":328},[109,2611,2574],{"class":1898},[109,2613,2577],{"class":132},[109,2615,2616],{"class":132}," startapp",[109,2618,2619],{"class":132}," APP_NAME\n",[11,2621,2622],{},"Laravelで例えると",[81,2624,2626],{"className":1889,"code":2625,"language":1891,"meta":89,"style":89},"# 簡易webサーバーを起動\nphp artisan serve\n\n# マイグレーションを実行\nphp artisan migrate\n\n# コントローラーのテンプレートを作成\nphp artisan make:controller CONTROLLER_NAME\n\n",[57,2627,2628,2632,2642,2646,2650,2658,2662,2667],{"__ignoreMap":89},[109,2629,2630],{"class":111,"line":112},[109,2631,2569],{"class":881},[109,2633,2634,2636,2639],{"class":111,"line":141},[109,2635,726],{"class":1898},[109,2637,2638],{"class":132}," artisan",[109,2640,2641],{"class":132}," serve\n",[109,2643,2644],{"class":111,"line":152},[109,2645,680],{"emptyLinePlaceholder":679},[109,2647,2648],{"class":111,"line":175},[109,2649,2589],{"class":881},[109,2651,2652,2654,2656],{"class":111,"line":208},[109,2653,726],{"class":1898},[109,2655,2638],{"class":132},[109,2657,2598],{"class":132},[109,2659,2660],{"class":111,"line":240},[109,2661,680],{"emptyLinePlaceholder":679},[109,2663,2664],{"class":111,"line":298},[109,2665,2666],{"class":881},"# コントローラーのテンプレートを作成\n",[109,2668,2669,2671,2673,2676],{"class":111,"line":328},[109,2670,726],{"class":1898},[109,2672,2638],{"class":132},[109,2674,2675],{"class":132}," make:controller",[109,2677,2678],{"class":132}," CONTROLLER_NAME\n",[11,2680,2681,2682,2685,2686,2691],{},"以上の様になります。この ",[57,2683,2684],{},"python3 manage.py","で実行できる内容は",[17,2687,2690],{"href":2688,"rel":2689},"https:\u002F\u002Fdocs.djangoproject.com\u002Fja\u002F3.2\u002Fref\u002Fdjango-admin\u002F",[1261],"こちらのドキュメント","で知ることができます。",[50,2693,2694],{"id":2694},"ディレクトリとファイルの構成",[11,2696,2697],{},"初期のファイル構成は以下の様になっています。",[81,2699,2701],{"className":1889,"code":2700,"language":1891,"meta":89,"style":89},"├── db.sqlite3\n├── djangodemo\n│   ├── __init__.py\n│   ├── asgi.py\n│   ├── settings.py\n│   ├── urls.py\n│   └── wsgi.py\n├── manage.py\n",[57,2702,2703,2711,2718,2729,2738,2747,2756,2766],{"__ignoreMap":89},[109,2704,2705,2708],{"class":111,"line":112},[109,2706,2707],{"class":1898},"├──",[109,2709,2710],{"class":132}," db.sqlite3\n",[109,2712,2713,2715],{"class":111,"line":141},[109,2714,2707],{"class":1898},[109,2716,2717],{"class":132}," djangodemo\n",[109,2719,2720,2723,2726],{"class":111,"line":152},[109,2721,2722],{"class":1898},"│",[109,2724,2725],{"class":132},"   ├──",[109,2727,2728],{"class":132}," __init__.py\n",[109,2730,2731,2733,2735],{"class":111,"line":175},[109,2732,2722],{"class":1898},[109,2734,2725],{"class":132},[109,2736,2737],{"class":132}," asgi.py\n",[109,2739,2740,2742,2744],{"class":111,"line":208},[109,2741,2722],{"class":1898},[109,2743,2725],{"class":132},[109,2745,2746],{"class":132}," settings.py\n",[109,2748,2749,2751,2753],{"class":111,"line":240},[109,2750,2722],{"class":1898},[109,2752,2725],{"class":132},[109,2754,2755],{"class":132}," urls.py\n",[109,2757,2758,2760,2763],{"class":111,"line":298},[109,2759,2722],{"class":1898},[109,2761,2762],{"class":132},"   └──",[109,2764,2765],{"class":132}," wsgi.py\n",[109,2767,2768,2770],{"class":111,"line":328},[109,2769,2707],{"class":1898},[109,2771,2772],{"class":132}," manage.py\n",[11,2774,2775,2778,2779,2781,2782,2785,2786,2788],{},[57,2776,2777],{},"djangodemo\u002F"," はDjangoのアプリを最初に作成した時に生成されるディレクトリです。",[57,2780,2777],{}," では特に ",[57,2783,2784],{},"settings.py","と",[57,2787,656],{},"が重要です。",[779,2790,2791],{"id":2791},"設定ファイル",[11,2793,2794,2796,2797,2800,2801,2804],{},[57,2795,2784],{}," はLaravelでいう",[57,2798,2799],{},"config\u002F","ディレクトリ配下のファイルたちを一つにまとめた様なものになっています。特に",[57,2802,2803],{},"config\u002Fapp.php","の記述が近いかもしれません。一部抜粋して解説します。",[81,2806,2808],{"className":654,"code":2807,"filename":2784,"language":657,"meta":89,"style":89},"BASE_DIR = Path(__file__).resolve().parent.parent\n\nSECRET_KEY = 'hogehoge'\n\n# SECURITY WARNING: don't run with debug turned on in production!\n# Laravelのapp.debugと同じ\nDEBUG = True\n\n# Application definition\n# Djangoが利用可能なアプリ（モジュール）Laravelにはないかも。\nINSTALLED_APPS = [\n    'django.contrib.admin',\n    'django.contrib.auth',\n    'django.contrib.contenttypes',\n    'django.contrib.sessions',\n    'django.contrib.messages',\n    'django.contrib.staticfiles',\n]\n\n# laravel の app\u002FHttp\u002FKernel.php のmiddlewareみたいなもの\nMIDDLEWARE = [\n    'django.middleware.security.SecurityMiddleware',\n    'django.contrib.sessions.middleware.SessionMiddleware',\n    'django.middleware.common.CommonMiddleware',\n    'django.middleware.csrf.CsrfViewMiddleware',\n    'django.contrib.auth.middleware.AuthenticationMiddleware',\n    'django.contrib.messages.middleware.MessageMiddleware',\n    'django.middleware.clickjacking.XFrameOptionsMiddleware',\n]\n\n# Laravelのroutesみたいなもの。\nROOT_URLCONF = 'djangodemo.urls'\n\n# Laravelのビューテンプレートが resource\u002Fviewであることを決めている様なことと同じ。DjangoないのTemplateの読み込み先を定義している\nTEMPLATES = [\n    # ...\n]\n\nWSGI_APPLICATION = 'djangodemo.wsgi.application'\n\n# Laravelのconfig\u002Fdatabase.phpと同じ。使用するDBドライバやアクセス情報を記述。\nDATABASES = {\n    'default': {\n        'ENGINE': 'django.db.backends.mysql',\n        'NAME': 'preform',\n        'USER': 'root',\n        'PASSWORD': 'rootroot',\n        'HOST': 'db',\n        'PORT': '3306',\n    }\n}\n\n# 静的ファイルを配置する箇所。Laravelのstorageディレクトリ を定義している様なもの。\nSTATIC_URL = '\u002Fstatic\u002F'\n\n",[57,2809,2810,2815,2819,2824,2828,2833,2838,2843,2847,2852,2857,2862,2867,2872,2877,2882,2887,2892,2896,2900,2905,2910,2915,2920,2925,2930,2935,2940,2945,2949,2953,2958,2963,2967,2972,2977,2982,2987,2992,2998,3003,3009,3015,3021,3027,3033,3039,3045,3051,3057,3063,3069,3074,3080],{"__ignoreMap":89},[109,2811,2812],{"class":111,"line":112},[109,2813,2814],{},"BASE_DIR = Path(__file__).resolve().parent.parent\n",[109,2816,2817],{"class":111,"line":141},[109,2818,680],{"emptyLinePlaceholder":679},[109,2820,2821],{"class":111,"line":152},[109,2822,2823],{},"SECRET_KEY = 'hogehoge'\n",[109,2825,2826],{"class":111,"line":175},[109,2827,680],{"emptyLinePlaceholder":679},[109,2829,2830],{"class":111,"line":208},[109,2831,2832],{},"# SECURITY WARNING: don't run with debug turned on in production!\n",[109,2834,2835],{"class":111,"line":240},[109,2836,2837],{},"# Laravelのapp.debugと同じ\n",[109,2839,2840],{"class":111,"line":298},[109,2841,2842],{},"DEBUG = True\n",[109,2844,2845],{"class":111,"line":328},[109,2846,680],{"emptyLinePlaceholder":679},[109,2848,2849],{"class":111,"line":350},[109,2850,2851],{},"# Application definition\n",[109,2853,2854],{"class":111,"line":360},[109,2855,2856],{},"# Djangoが利用可能なアプリ（モジュール）Laravelにはないかも。\n",[109,2858,2859],{"class":111,"line":370},[109,2860,2861],{},"INSTALLED_APPS = [\n",[109,2863,2864],{"class":111,"line":380},[109,2865,2866],{},"    'django.contrib.admin',\n",[109,2868,2869],{"class":111,"line":403},[109,2870,2871],{},"    'django.contrib.auth',\n",[109,2873,2874],{"class":111,"line":425},[109,2875,2876],{},"    'django.contrib.contenttypes',\n",[109,2878,2879],{"class":111,"line":466},[109,2880,2881],{},"    'django.contrib.sessions',\n",[109,2883,2884],{"class":111,"line":476},[109,2885,2886],{},"    'django.contrib.messages',\n",[109,2888,2889],{"class":111,"line":486},[109,2890,2891],{},"    'django.contrib.staticfiles',\n",[109,2893,2894],{"class":111,"line":496},[109,2895,700],{},[109,2897,2898],{"class":111,"line":517},[109,2899,680],{"emptyLinePlaceholder":679},[109,2901,2902],{"class":111,"line":537},[109,2903,2904],{},"# laravel の app\u002FHttp\u002FKernel.php のmiddlewareみたいなもの\n",[109,2906,2907],{"class":111,"line":543},[109,2908,2909],{},"MIDDLEWARE = [\n",[109,2911,2912],{"class":111,"line":552},[109,2913,2914],{},"    'django.middleware.security.SecurityMiddleware',\n",[109,2916,2917],{"class":111,"line":561},[109,2918,2919],{},"    'django.contrib.sessions.middleware.SessionMiddleware',\n",[109,2921,2922],{"class":111,"line":576},[109,2923,2924],{},"    'django.middleware.common.CommonMiddleware',\n",[109,2926,2927],{"class":111,"line":623},[109,2928,2929],{},"    'django.middleware.csrf.CsrfViewMiddleware',\n",[109,2931,2932],{"class":111,"line":632},[109,2933,2934],{},"    'django.contrib.auth.middleware.AuthenticationMiddleware',\n",[109,2936,2937],{"class":111,"line":2240},[109,2938,2939],{},"    'django.contrib.messages.middleware.MessageMiddleware',\n",[109,2941,2942],{"class":111,"line":2252},[109,2943,2944],{},"    'django.middleware.clickjacking.XFrameOptionsMiddleware',\n",[109,2946,2947],{"class":111,"line":2262},[109,2948,700],{},[109,2950,2951],{"class":111,"line":2269},[109,2952,680],{"emptyLinePlaceholder":679},[109,2954,2955],{"class":111,"line":2277},[109,2956,2957],{},"# Laravelのroutesみたいなもの。\n",[109,2959,2960],{"class":111,"line":2284},[109,2961,2962],{},"ROOT_URLCONF = 'djangodemo.urls'\n",[109,2964,2965],{"class":111,"line":2296},[109,2966,680],{"emptyLinePlaceholder":679},[109,2968,2969],{"class":111,"line":2304},[109,2970,2971],{},"# Laravelのビューテンプレートが resource\u002Fviewであることを決めている様なことと同じ。DjangoないのTemplateの読み込み先を定義している\n",[109,2973,2974],{"class":111,"line":2312},[109,2975,2976],{},"TEMPLATES = [\n",[109,2978,2979],{"class":111,"line":2322},[109,2980,2981],{},"    # ...\n",[109,2983,2985],{"class":111,"line":2984},37,[109,2986,700],{},[109,2988,2990],{"class":111,"line":2989},38,[109,2991,680],{"emptyLinePlaceholder":679},[109,2993,2995],{"class":111,"line":2994},39,[109,2996,2997],{},"WSGI_APPLICATION = 'djangodemo.wsgi.application'\n",[109,2999,3001],{"class":111,"line":3000},40,[109,3002,680],{"emptyLinePlaceholder":679},[109,3004,3006],{"class":111,"line":3005},41,[109,3007,3008],{},"# Laravelのconfig\u002Fdatabase.phpと同じ。使用するDBドライバやアクセス情報を記述。\n",[109,3010,3012],{"class":111,"line":3011},42,[109,3013,3014],{},"DATABASES = {\n",[109,3016,3018],{"class":111,"line":3017},43,[109,3019,3020],{},"    'default': {\n",[109,3022,3024],{"class":111,"line":3023},44,[109,3025,3026],{},"        'ENGINE': 'django.db.backends.mysql',\n",[109,3028,3030],{"class":111,"line":3029},45,[109,3031,3032],{},"        'NAME': 'preform',\n",[109,3034,3036],{"class":111,"line":3035},46,[109,3037,3038],{},"        'USER': 'root',\n",[109,3040,3042],{"class":111,"line":3041},47,[109,3043,3044],{},"        'PASSWORD': 'rootroot',\n",[109,3046,3048],{"class":111,"line":3047},48,[109,3049,3050],{},"        'HOST': 'db',\n",[109,3052,3054],{"class":111,"line":3053},49,[109,3055,3056],{},"        'PORT': '3306',\n",[109,3058,3060],{"class":111,"line":3059},50,[109,3061,3062],{},"    }\n",[109,3064,3066],{"class":111,"line":3065},51,[109,3067,3068],{},"}\n",[109,3070,3072],{"class":111,"line":3071},52,[109,3073,680],{"emptyLinePlaceholder":679},[109,3075,3077],{"class":111,"line":3076},53,[109,3078,3079],{},"# 静的ファイルを配置する箇所。Laravelのstorageディレクトリ を定義している様なもの。\n",[109,3081,3083],{"class":111,"line":3082},54,[109,3084,3085],{},"STATIC_URL = '\u002Fstatic\u002F'\n",[779,3087,3088],{"id":3088},"ルーティング",[11,3090,3091,3092,3094,3095,3097,3098,3101,3102,3105],{},"次は",[57,3093,656],{},"です。これはLaravelでいうところの ",[57,3096,708],{},"と内容的には一緒です。ここでHTTPリクエストに対する処理を結びつけています。Urlディスパッチャと言われています。Laravelでは",[57,3099,3100],{},"web.php","や",[57,3103,3104],{},"api.php","などいくらか分かれていますが、Djangoではデフォルトで一つです。詳細な記述は次回説明します。",[779,3107,3108],{"id":3108},"アプリ側のディレクトリ",[11,3110,3111,3112,3115],{},"次にアプリを作成します。Djangoは機能ごとにディレクトリを分割しアプリ(app)と呼んでいます。例としてユーザーのアカウント設定や認証を行う機能を作成するために、",[57,3113,3114],{},"account","というアプリを作成します。",[81,3117,3120],{"className":3118,"code":3119,"language":86},[84],"python3 manage.py startapp account\n",[57,3121,3119],{"__ignoreMap":89},[11,3123,3124,3125,3128],{},"ディレクトリ が一つ増えて、",[57,3126,3127],{},"account\u002F","というのが作成されたはずです。アプリ内には初期では以下の通りテンプレートが作成されます。",[81,3130,3133],{"className":3131,"code":3132,"language":86},[84],"├── account\n│   ├── __init__.py\n│   ├── admin.py\n│   ├── apps.py\n│   ├── migrations\n│   │   └── __init__.py\n│   ├── models.py\n│   ├── tests.py\n│   └── views.py\n├── db.sqlite3\n├── djangodemo\n├── manage.py\n",[57,3134,3132],{"__ignoreMap":89},[11,3136,1187,3137,3140,3141,3143],{},[57,3138,3139],{},"app\u002F","配下にコントローラーやモデル、ジョブなどのクラスファイルを定義します。独立した機能であっても",[57,3142,3139],{},"配下に配置してクラス名などで判別する感じです。",[11,3145,3146,3147,3151],{},"しかしDjangoは",[3148,3149,3150],"strong",{},"機能ごとにディレクトリ を作成し、その機能に関連するモデル、ビュー、テストの設定を記述","します。ここがLaravelとすこし違うところです。",[11,3153,3154,3155,3157,3158,3161],{},"アプリを",[57,3156,1730],{},"の",[57,3159,3160],{},"INSTALLED_APPS","に記述することで、",[81,3163,3165],{"className":654,"code":3164,"language":657,"meta":89,"style":89},"from account.model import Account\n\n# account\u002Fmodel.py のAccountクラスを使用する\n",[57,3166,3167,3172,3176],{"__ignoreMap":89},[109,3168,3169],{"class":111,"line":112},[109,3170,3171],{},"from account.model import Account\n",[109,3173,3174],{"class":111,"line":141},[109,3175,680],{"emptyLinePlaceholder":679},[109,3177,3178],{"class":111,"line":152},[109,3179,3180],{},"# account\u002Fmodel.py のAccountクラスを使用する\n",[11,3182,3183,3184,3187],{},"などそのアプリ内機能をモジュールとして使用できます。Laravel（PHP）風に解説すると、適切な名前空間を定義して任意のファイルで",[57,3185,3186],{},"use","する感じです。",[81,3189,3191],{"className":723,"code":3190,"language":726,"meta":89,"style":89},"use App\\Models\\Account\n",[57,3192,3193],{"__ignoreMap":89},[109,3194,3195],{"class":111,"line":112},[109,3196,3190],{},[11,3198,3199],{},"それぞれのファイルを説明します。",[23,3201,3202,3208,3217,3226,3235,3240],{},[26,3203,3204,3207],{},[57,3205,3206],{},"admin.py",":Djangoが提供する管理者画面でモデルの内容をどう表記するかを定義します。",[26,3209,3210,3213,3214,3216],{},[57,3211,3212],{},"apps.py",":アプリの設定ファイル。アプリの名前やデフォルトのプライマリーキーなどを設定でき、",[57,3215,3160],{},"に必要",[26,3218,3219,3222,3223],{},[57,3220,3221],{},"models.py",": アプリのモデルファイル。テーブルや使用するフィールドの定義などを行う。Laravelでいう",[57,3224,3225],{},"app\u002Fmodels",[26,3227,3228,3231,3232],{},[57,3229,3230],{},"tets.py",": アプリのテストファイル。テストコードを記述する。Laravelでいう",[57,3233,3234],{},"tests\u002F",[26,3236,3237,3239],{},[57,3238,788],{},": アプリのビューファイル。DjangoではビューはLaravelでいうControllerみたいな働きをする。",[26,3241,3242,3245,3246,3249],{},[57,3243,3244],{},"migrations\u002F",": DBに対する変更、マイグレーションファイルが格納されます。Laravelでいう、",[57,3247,3248],{},"database\u002Fmigrations","です。",[11,3251,3252,3253,3256],{},"のこっている ",[57,3254,3255],{},"__init__.py","ですがこれはpythonがディレクトリ をパッケージとして認識して、importできる様にするために必要なファイルです。python2ではこのファイルがないとimportが動作しません。python3からは不要ですが、後方互換性のために作っておいて損はありません。",[81,3258,3260],{"className":654,"code":3259,"language":657,"meta":89,"style":89},"from account.models\n\"\"\"\naccountディレクトリ（パッケージ）のmodels.py（モジュール）を読み込むということが,\n__init__.pyがあるとできる。\n\"\"\"\n",[57,3261,3262,3267,3272,3277,3282],{"__ignoreMap":89},[109,3263,3264],{"class":111,"line":112},[109,3265,3266],{},"from account.models\n",[109,3268,3269],{"class":111,"line":141},[109,3270,3271],{},"\"\"\"\n",[109,3273,3274],{"class":111,"line":152},[109,3275,3276],{},"accountディレクトリ（パッケージ）のmodels.py（モジュール）を読み込むということが,\n",[109,3278,3279],{"class":111,"line":175},[109,3280,3281],{},"__init__.pyがあるとできる。\n",[109,3283,3284],{"class":111,"line":208},[109,3285,3271],{},[39,3287,3288],{"id":3288},"今回はとりあえずここまで",[11,3290,3291],{},"ひとまずこの回ではディレクトリやファイルの説明までとしておきます。次回はユーザーモデルを使用した認証の実装とLaravelと比較したCRUDの一部（記事の作成）を実装します。",[1751,3293,3294],{},"html pre.shiki code .s5Dmg, html code.shiki .s5Dmg{--shiki-default:#FFCB6B}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sx098, html code.shiki .sx098{--shiki-default:#F78C6C}html pre.shiki code .sC9rS, html code.shiki .sC9rS{--shiki-default:#464B5D;--shiki-default-font-style:italic}",{"title":89,"searchDepth":152,"depth":152,"links":3296},[3297,3301,3306,3314],{"id":1879,"depth":141,"text":1879,"children":3298},[3299,3300],{"id":1946,"depth":152,"text":1947},{"id":1997,"depth":152,"text":1997},{"id":2439,"depth":141,"text":2439,"children":3302},[3303,3304,3305],{"id":2445,"depth":175,"text":2445},{"id":2479,"depth":175,"text":2479},{"id":2522,"depth":175,"text":2522},{"id":2542,"depth":141,"text":2543,"children":3307},[3308,3309],{"id":2549,"depth":152,"text":2549},{"id":2694,"depth":152,"text":2694,"children":3310},[3311,3312,3313],{"id":2791,"depth":175,"text":2791},{"id":3088,"depth":175,"text":3088},{"id":3108,"depth":175,"text":3108},{"id":3288,"depth":141,"text":3288},[1781],"2022-02-12","アプリの解説とシリーズの概要",{},"\u002Fseries\u002Flaravel-to-django-1",{"title":1800,"description":3317},"series\u002Flaravel-to-django-1",[1793,657,1794,726],"k4TYlI4xXfHM5YMh4HtklCzEfD1cyqgLf2FCDeypoBY",1780987153369]