はじめに
Django の最初のプロジェクトを作る方法、毎回ググってやるのがつらいので、備忘録として残したい。
Django Girls Tutorial を通してやることで、備忘録とします。
上記のページは情報が古くなってる可能性があるので、GitHub のリポジトリ を確認したほうが良いかもです。
tutorial/ja at master · DjangoGirls/tutorial · GitHub github.com
Anacondaはインストールされていること前提。Windows 環境です。
Django Girls Tutorial用の仮想環境を作る
デフォルト環境を汚したくないので、専用の仮想環境を作っておきます。
( base ) > conda create -n djangogirls
( base ) > activate djangogirls
( djangogirls ) > conda install django
これ以降、(djangogirls)
は省略します。
プロジェクトを作る
tutorial/ja/django_start_project at master · DjangoGirls/tutorial · GitHub
> mkdir djangogirls
> cd djangodirls
~/djangogirls> django-admin startproject mysite .
settings.pyの設定
mysite/settings.py
の中身を次のように変更する
TIME_ZONE = 'Asia/Tokyo'
LANGUAGE_CODE = 'ja'
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static' )
ALLOWED_HOSTS = ['127.0.0.1' , '.pythonanywhere.com' ]
データベースの設定
sqlite3の設定はmysite/settings.py
の以下に既に設定されている(本番環境ではsqlite は使わないこと)。
DATABASES = {
'default' : {
'ENGINE' : 'django.db.backends.sqlite3' ,
'NAME' : os.path.join(BASE_DIR, 'db.sqlite3' ),
}
}
以下のコマンドでデータベースを作成し、サーバを起動します。
~/djangogirls> python manage.py migrate
~/djangogirls> python manage.py runserver
( ctrl-Cでサーバの停止 )
tutorial/ja/django_models at master · DjangoGirls/tutorial · GitHub
プロジェクト内にアプリケーションを作成します。
~/djangogirls> python manage.py startapp blog
アプリケーションを作ったら、Django にそれを使うように伝えます。
mysite/settings.py
ファイルのINSTALLED_APPSに、'blog'という一行を追加します。
INSTALLED_APPS = (
' django.contrib.admin ' ,
' django.contrib.auth ' ,
' django.contrib.contenttypes ' ,
' django.contrib.sessions ' ,
' django.contrib.messages ' ,
' django.contrib.staticfiles ' ,
' blog ' ,
)
blog post modelの作成
blog/models.pyファイルでModelsと呼ばれる全てのオブジェクトを定義します。これがブログポストを定義する場所です。
blog/models.py
を以下のように書き換えます。
from django.db import models
from django.utils import timezone
class Post (models.Model):
author = models.ForeignKey('auth.User' , on_delete=models.CASCADE)
title = models.CharField(max_length=200 )
text = models.TextField()
created_date = models.DateTimeField(
default=timezone.now)
published_date = models.DateTimeField(
blank=True , null=True )
def publish (self):
self.published_date = timezone.now()
self.save()
def __str__ (self):
return self.title
models.ModelはポストがDjango Modelだという意味で、Django が、これはデータベースに保存すべきものだと分かるようにしています。
(クラス変数をselfでアクセスしてるけどいいのか?)
データベースにモデル用のテーブルを作る
新しいモデルをデータベースに追加します。まず、(今作った)モデルの中で少し変更があったことをDjango に知らせる必要があります。
~/djangogirls> python manage.py makemigrations blog
Django がデータベースに入れる為の移行ファイルを作ってくれているので、migrateする。
~/djangogirls> python manage.py migrate blog
これでPostモデルがデータベースに入りました。
ログインページを作る
今作成したポストを追加、編集、削除するのにDjango adminを使います。
モデルをadminページで見れるようにするために、モデルをadmin.site.register(Post)で登録する必要があります。
blog/admin.py
ファイルを書き換えます。
from django.contrib import admin
from .models import Post
admin.site.register(Post)
ログインして投稿する
~/djangogirls> python manage.py createsuperuser
~/djangogirls> python manage.py migrate blog
~/djangogirls> python manage.py runserver
デプロイ
tutorial/ja/deploy at master · DjangoGirls/tutorial · GitHub
Heroku PythonAnywhereにデプロイするチュートリアル 。飛ばします。
Django でURLはどのように機能する?
tutorial/ja/django_urls at master · DjangoGirls/tutorial · GitHub
mysite/urls.py
内は次のようになっている。
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^admin/' , include(admin.site.urls)),
]
最初のURLを作る
http://127.0.0.1:8000/ はブログの入口ページなので、投稿したブログポストのリストを表示するようにします。
mysite/urls.py ファイルは簡潔なままにしておきたいので、mysite/urls.pyではblogアプリからURLをインポートするだけにしましょう。
from django.urls import path, include
from django.contrib import admin
urlpatterns = [
path('admin/' , admin.site.urls),
path('' , include('blog.urls' )),
]
これでDjango は 'http://127.0.0.1:8000/' に来たリクエス トはblog.urls
へリダイレクトするようになり、それ以降はそちらを参照するようになります。
blogのURL
blog.urls.py
を作ります。
from django.urls import path
from . import views
urlpatterns = [
path('' , views.post_list, name='post_list' ),
]
このURLパターンは空の文字列に一致し、Django はビューを見つけるとき、URLのフルパスの前半にくっつくドメイン 名(つまり、http://127.0.0.1:8000/ の部分)を無視します。 このパターンは誰かがあなたのWebサイトの 'http://127.0.0.1:8000/' というアドレスにアクセスしてきたら views.post_list が正しい行き先だということをDjango に伝えます。
最後の name='post_list' は、ビューを識別するために使われるURL の名前です。 これはビューと同じ名前にすることもできますが、全然別の名前にすることもできます。 プロジェクトでは名前づけされたURLを後で使うことになるので、アプリのそれぞれのURLに名前をつけておくのは重要です。また、URLの名前はユニークで覚えやすいものにしておきましょう。
ビューって何?
tutorial/ja/django_views at master · DjangoGirls/tutorial · GitHub
ビュー はアプリのロジックを書いていくところです。 ビューは、以前あなたが作った モデル に情報を要求し、それを テンプレート に渡します。 テンプレートは、次の章で作ります。 ビューはただのPython の関数です。Python 入門の章で書いたものよりもちょっと複雑なだけですよ。
ビューは、views.py に記述します。私たちの場合 blog/views.py に書くことになります。
ビューを作る
blog/views.py
を作ります。
from django.shortcuts import render
def post_list (request):
return render(request, 'blog/post_list.html' , {})
これは request を引数に取り、blog/post_list.htmlテンプレートを表示する (組み立てる) render 関数を return しています。
テンプレートって何?
tutorial/ja/html at master · DjangoGirls/tutorial · GitHub
テンプレートはhtmlのこと(たぶん)。
テンプレートは、blog/templates/blogディレクト リに保存されています。 それでは、最初に、自分のblogディレクト リの中にtemplatesという名前のディレクト リを作成してください。 次に、自分のtemplatesディレクト リの中にblogという名前のディレクト リを作ります。
blog
└───templates
└───blog
(なぜ、両方ともblogという名前の付いたディレクト リを2つ作成する必要があるのか不思議に思う人もいるかもしれません。あとで分かると思いますが、簡単に言うと、これは、もっと複雑なことをやろうとした時に、それが楽にできるようにしてくれる便利な命名 法なのです。)
テンプレートを作る
blog/templates/blog/post_list.html
を作ります。
< html >
< head >
< title > Django Girls blog</ title >
</ head >
< body >
< p > Hello!</ p >
< p > It works!</ p >
</ body >
</ html >
ここまで来たら、サーバを起動して動作確認します。
~/djangogirls> python manage.py runserver
http://127.0.0.1:8000/ にアクセスして、ページが表示されたら成功です。
クエリセット
データベースへの接続方法と、データストアについて。
tutorial/ja/django_orm at master · DjangoGirls/tutorial · GitHub
クエリセットが何かと言うと、モデルが提供しているオブジェクトのリストのことです。クエリセットは、データベースからデータを読み込んだり、抽出したり、言われた通りにやってくれます。
$ python manage.py shell
>>> from blog.models import Post
>>> Post.objects.all()
< QuerySet [< Post: Alice is god.> , < Post: Bob is good man.> , < Post: Carol is super man.>]>
>>> from django.contrib.auth.models import User
>>> User.objects.all()
< QuerySet [< User: USERNAME>]>
>>> me = User.objects.get( username =' USERNAME ' )
>>> Post.objects.create( author = me, title = ' Sample title ' , text = ' Test ' )
>>> Post.objects.all()
< QuerySet [< Post: Alice is god.> , < Post: Bob is good man.> , < Post: Carol is super man.> , < Post: Sample title>]>
>>> Post.objects.filter( author =me )
>>> Post.objects.filter( title__contains =' title ' )
>>> post = Post.objects.get( id =1 )
>>> post.publish()
>>> from django.utils import timezone
>>> Post.objects.filter( published_date__lte =timezone.now( ) )
>>> Post.objects.order_by( ' created_date ' )
>>> Post.objects.order_by( ' -created_date ' )
>>> Post.objects.filter( published_date__lte =timezone.now( ) ) .order_by( ' published_date ' )
exit ()
クエリセット2
tutorial/ja/dynamic_data_in_templates at master · DjangoGirls/tutorial · GitHub
・投稿内容を保存するためのPostモデルは、models.pyに定義した
・投稿の一覧を表示するpost_listはviews.pyにあり、そこにテンプレートも追加した。
・投稿をどうやってHTMLファイルに出力すればよいか?
大まかなイメージとしては、データベースに保存された記事を取り出して、テンプレートのHTMLファイルの中に行儀よく並べるだけのことですけど。
正確には、 ビュー が モデルとテンプレートの橋渡しをしてくれます。私達が作業している post_list ビュー の場合、表示したいデータを取り出して、テンプレートファイルに渡すことになります。基本的に、どのモデルのデータを、どのテンプレートに表示させるかは、 ビューに 記述します。
blog/views.py
を開き、編集します。
from django.shortcuts import render
from django.utils import timezone
from .models import Post
def post_list (request):
""" 投稿をリスト表示する """
_posts = Post.objects.filter (published_date__lte=timezone.now()).order_by('published_date' )
return render(request, 'blog/post_list.html' , {'posts' : _posts})
クエリセットのAPI リファレンス:QuerySet API reference | Django ドキュメント | Django
テンプレートタグとは?
tutorial/ja/django_templates at master · DjangoGirls/tutorial · GitHub
テンプレートタグとは、HTMLにPyhtonのようなコードを埋め込むためのもの。
HTML内に{{ posts }}
のように書くと、render()関数の第3引数で指定したJSON のpostsキーのデータを表示できる
blog/templates/blog/post_list.html
を次のように編集します。
< html >
< head >
< title > Django Girls blog</ title >
</ head >
< body >
< div >
< h1 >< a href = "/" > Django Girls Blog </ a ></ h1 >
</ div >
{% for post in posts %}
< div >
< p > published: {{ post.published_date }}</ p >
< h1 >< a href = "" > {{ post.title }} </ a ></ h1 >
< p > {{ post.text|linebreaksbr }}</ p >
</ div >
{% endfor %}
</ body >
</ html >
CSS でカワイくしよう
tutorial/ja/css at master · DjangoGirls/tutorial · GitHub
・Django のCSS ファイルはどこに置けば(どう書けば)よいのか?
Bootstrapを使う
Bootstrap は美しいWebサイトを開発するためのHTMLとCSS のフレームワーク
Bootstrapのインストール
blog/templates/blog/post_list.html
の<head>
タグに以下を追加します。
< link rel = "stylesheet" href = "//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" >
< link rel = "stylesheet" href = "//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css" >
これは、あなたのプロジェクトにファイルを追加しているわけではありません。インターネット上にあるファイルを指しているだけです。
jQuery と使い方は同じですね。
静的ファイルとは、CSS ファイルや画像ファイルといった、動的な変更が発生しないファイルのことです。
静的ファイルはプロジェクトのどこに置けばいいの?
知りたいのはこれだよこれ。
Django は、ビルトインの "admin" アプリにより、静的ファイルをどこで探せばいいのかわかっています。私たちがやることは、blog アプリのための静的ファイルを追加することだけです。
そのために、blogアプリの中に static というフォルダを作ります。
djangogirls
├── blog
│ ├── migrations
│ ├── static
│ └── templates
└── mysite
Django は、全てのアプリのフォルダ内の "static" と名づけられた全てのフォルダを自動的に探して、その中身を静的ファイルとして使えるようにします。
すご。
この"static"と名付けられたすべてのフォルダを自動的に探す機能は、mysite/setting.py
の以下の箇所でしているようです。
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/
STATIC_URL = '/static/'
# 後述のCSSがうまく反映されなかったら、以下を追加する
STATIC_ROOT = os.path.join(BASE_DIR, '/')
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
最初のCSS ファイル!
以下のようにファイルを作成します。
djangogirls
└─── blog
└─── static
└─── css
└─── blog.css
blog/static/css/blog.css
は適当に次のようにします。
h1 a {
color : #FCA205 ;
}
・HTMLファイルの先頭に{% load static %}
と書くことで、テンプレートに静的ファイルを読み込むことができる。
・CSS ファイルの読み込みは、<link rel="stylesheet" href="{% static 'css/blog.css' %}">
のように書く
blog/templates/blog/post_list.html
は次のようにします。
{% load static %}
< html >
< head >
< title > Django Girls blog</ title >
< link rel = "stylesheet" href = "//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" >
< link rel = "stylesheet" href = "//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css" >
< link rel = "stylesheet" href = "{% static 'css/blog.css' %}" >
</ head >
(以下略)
フォント
<link href="//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext" rel="stylesheet" type="text/css">
・ Lobster というフォントをGoogle Fonts (https://www.google.com/fonts ) から読み込める
・font-family: 'Lobster';
をCSS に追加することでフォントが適用できる
最終的に次のようになります。
/blog/static/css/blog.css
.page-header {
background-color : #ff9400 ;
margin-top : 0 ;
padding : 20px 20px 20px 40px ;
}
.page-header h1 , .page-header h1 a , .page-header h1 a :visited , .page-header h1 a :active {
color : #ffffff ;
font-size : 36pt ;
text-decoration : none ;
}
.content {
margin-left : 40px ;
}
h1 , h2 , h3 , h4 {
font-family : 'Lobster' , cursive ;
}
.date {
color : #828282 ;
}
.save {
float : right ;
}
.post-form textarea , .post-form input {
width : 100% ;
}
.top-menu , .top-menu :hover , .top-menu :visited {
color : #ffffff ;
float : right ;
font-size : 26pt ;
margin-right : 20px ;
}
.post {
margin-bottom : 70px ;
}
.post h1 a , .post h1 a :visited {
color : #000000 ;
}
/blog/templates/blog/post_list.html
{% load static %}
< html >
< head >
< title > Django Girls blog</ title >
< link rel = "stylesheet" href = "//maxcdn.bootstrapcdn.com/bootstrap/4.3.0/css/bootstrap.min.css" >
< link rel = "stylesheet" href = "//maxcdn.bootstrapcdn.com/bootstrap/4.3.0/css/bootstrap-theme.min.css" >
< link href = "http://fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext" rel = "stylesheet" type = "text/css" >
< link rel = "stylesheet" href = "{% static 'css/blog.css' %}" >
</ head >
< body >
< div class = "page-header" >
< h1 >< a href = "/" > Django Girls Blog </ a ></ h1 >
</ div >
< div class = "content container" >
< div class = "row" >
< div class = "col-md-8" >
{% for post in posts %}
< div class = "post" >
< div class = "date" >
< p > published: {{ post.published_date }}</ p >
</ div >
< h1 >< a href = "" > {{ post.title }} </ a ></ h1 >
< p > {{ post.text|linebreaksbr }}</ p >
</ div >
{% endfor %}
</ div >
</ div >
</ div >
</ body >
</ html >
テンプレートを拡張する
テンプレートを拡張しよう · Django Girls Tutorial
Django のまた別の素敵なところはテンプレート拡張です。これは何を意味するのでしょうか?それはHTMLの共通部分をウェブサイトの異なるページで使えるということです。
基本テンプレートを作成する
・基本テンプレートは各ページを拡張するための最も基本的なテンプレート。
blog/templates/blog/
以下にbase.html
ファイルを作成します。
blog
└───templates
└───blog
base.html
post_list.html
・base.html
を基本的なテンプレート(HTML)
・post_list.html
を「投稿を一覧表示する部分」の拡張テンプレート
として作成し直します。
まず、post_list.html
の内容を丸々コピペしてbase.html
に貼り付け、次のように「投稿を一覧表示する部分」を削除して、代わりにblock
タグで囲みます。
{% load static %}
< html >
< head >
< title > Django Girls blog</ title >
< link rel = "stylesheet" href = "//maxcdn.bootstrapcdn.com/bootstrap/4.3.0/css/bootstrap.min.css" >
< link rel = "stylesheet" href = "//maxcdn.bootstrapcdn.com/bootstrap/4.3.0/css/bootstrap-theme.min.css" >
< link href = "http://fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext" rel = "stylesheet" type = "text/css" >
< link rel = "stylesheet" href = "{% static 'css/blog.css' %}" >
</ head >
< body >
< div class = "page-header" >
< h1 >< a href = "/" > Django Girls Blog </ a ></ h1 >
</ div >
< div class = "content container" >
< div class = "row" >
< div class = "col-md-8" >
{% block content %}
{% endblock %}
</ div >
</ div >
</ div >
</ body >
</ html >
最後に、post_list.html
を以下のように書き換えます。
{% extends 'blog/base.html' %}
{% block content %}
{% for post in posts %}
< div class = "post" >
< div class = "date" >
< p > published: {{ post.published_date }}</ p >
</ div >
< h1 >< a href = "" > {{ post.title }} </ a ></ h1 >
< p > {{ post.text|linebreaksbr }}</ p >
</ div >
{% endfor %}
{% endblock %}
アプリケーションを拡張する
アプリケーションを拡張しよう · Django Girls Tutorial
もう、ウェブサイトを作るのに必要な全ての章は終わりました。どのようにモデル、URL、ビュー、テンプレートを書いたら良いかわかっています(中略)
さあ練習しましょう!
投稿の詳細へのテンプレートリンクを作成する
投稿リストの投稿のタイトルから投稿の詳細ページへのリンクを作るように、post_list.html
にテンプレートリンクを追加します。
・変更前
< h1 >< a href = "" > {{ post.title }} </ a ></ h1 >
・変更後
< h1 >< a href = "{% url 'post_detail' pk=post.pk %}" > {{ post.title }} </ a ></ h1 >
・{% %}という表記はDjango のテンプレートタグを使用していることを意味している
・post_detailの部分は、Django がblog/urls.py
に書かれた name=post_detail のURLを待ち受ける
・pk=post.pkについては、pkはプライマリキーの略で、データベースの各レコードのユニークな名前
・post.pkと書くことによって、Postインスタンス のプライマリキーにアクセスする
投稿の詳細へのURLを作成する
post_detail ビュー用にurls.pyにURLを作成します。
最初の投稿の詳細がこのURLで表示されるようにします:http://127.0.0.1:8000/post/1/
blog/urls.py
のURLパターンを次のようにします。
urlpatterns = [
path('' , views.post_list, name='post_list' ),
path('post/<int:pk>/' , views.post_detail, name='post_detail' ),
]
post/
はURLが post に続けて / で始まることを意味する
<int:pk>
は整数の値を期待し、その値がpkという名前の変数でビューに渡されることを意味する
/
– それからURLの最後に再び / が必要
つまり、ブラウザにhttp://127.0.0.1:8000/post/5/ を入力すると、Django はpost_detailというビューを探していると理解します。そしてpkが5という情報をそのビューに転送します。
投稿の詳細ビューを追加する
ビューに追加のパラメータpkが与えられるようにしたので、ビューにそれを受け取る処理を追加します。
その処理する関数をdef post_detail(request, pk):として定義します。 urls.pyで指定した名前(pk)と同名にする必要があることに注意します。
blog/views.py
に次を追加します。
def post_detail (request, pk):
from django.shortcuts import render, get_object_or_404
post = get_object_or_404(Post, pk=pk)
return render(request, 'blog/post_detail.html' , {'post' : post})
投稿の詳細へのテンプレートリンクを作成する
blog/templates/blog/post_detail.html
を作成します。
{% extends 'blog/base.html' %}
{% block content %}
<div class ="post" >
{% if post.published_date %}
<div class ="date" >
{{ post.published_date }}
</div>
{% endif %}
<h1>{{ post.title }}</h1>
<p>{{ post.text|linebreaksbr }}</p>
</div>
{% endblock %}
{% if ... %} ... {%endif%}
では、公開日(published_date)が空でないかを確認している
Djangoフォーム · Django Girls Tutorial
Django admin
を使わず、記事を追加したり編集したりできるようにします。Django フォームを使えば、考え得る大抵の入力フォームは作れるらしいです。
Django フォームは、フォームをゼロから定義できたり、フォームの結果をモデルに保存できるModelFormを作れたりします。
そのためのblog/forms.py
を作成します。
blog
└── forms.py
from django import forms
from .models import Post
class PostForm (forms.ModelForm):
class Meta :
model = Post
fields = ('title' , 'text' ,)
フォームにおけるページへのリンク
・blog/templates/blog/base.htmlをpage-headerと名付けたdiv中に次のリンク<a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>
を追加します
< div class = "page-header" >
< a href = "{% url 'post_new' %}" class = "top-menu" >< span class = "glyphicon glyphicon-plus" ></ span ></ a >
< h1 >< a href = "/" > Django Girls Blog </ a ></ h1 >
</ div >
URL
blog/urls.py
に、URLパターンを追加します。
urlpatterns = [
path('' , views.post_list, name='post_list' ),
path('post/<int:pk>/' , views.post_detail, name='post_detail' ),
path('post/new/' , views.post_new, name='post_new' ),
]
post_new ビュー
blog/views.py
にpost_newビューを追加します。
from .forms import PostForm
def post_new (request):
form = PostForm()
return render(request, 'blog/post_edit.html' , {'form' : form})
テンプレート
blog/templates/blog/post_edit.html
ファイルを作ります。フォームを動かすにはいくつかやることがあります。
フォームを表示する必要があります。 私たちは(例えば){{ form.as_p }} でこれを行うことができます。
上記の行は HTMLのformタグでラップする必要があります:
Save ボタンが必要です。これをHTMLのbuttonタグで行います:Save
最後に
フォームを保存する
blog/views.py
は今以下のようになっている。
def post_new (request):
form = PostForm()
return render(request, 'blog/post_edit.html' , {'form' : form})
フォームを送信したとき、request.POST にデータが追加されている(
このビュー では、扱わなくてはならない2つの別々のシチュエーションがあります。
1つ目は、最初にページにアクセスしてきた時で空白のフォームが必要な場合
2つ目はすべてのフォームデータが入力された状態でビューに戻ってくる場合です。 したがって条件分岐を追加する必要があります(そのためにifを使います)
if request.method == "POST" :
[...]
else :
form = PostForm()
CSRF verification failed. Request aborted.
エラーが表示されるようなら、settings.py
に以下を追加します。
MIDDLEWARE_CLASSES = (
'django.middleware.csrf.CsrfViewMiddleware' ,
)
フォームのバリデーション(検証)
ブログのポストは title と text のフィールドが必要です。 Post モデルではこれらのフィールドがなくてもよいとは書いておらず (published_date とは対照的に)、Django はその場合、それらのフィールドには何らかの値が設定されることを期待します。title と text を入力せずに保存してみましょう。何が起こるでしょうか?
「このフィールドを入力してください」と表示されます。
フォームの編集
既存のデータを編集するためのページを作成する
編集ボタンを追加するため、blog/templates/blog/post_detail.html
の<div class="post">
部分を次のようにします。
<div class ="post" >
{% if post.published_date %}
<div class ="date" >
{{ post.published_date }}
</div>
{% endif %}
<a class ="btn btn-default" href="{% url 'post_edit' pk=post.pk %}" >編集<span class ="glyphicon glyphicon-pencil" ></span></a>
<h1>{{ post.title }}</h1>
<p>{{ post.text|linebreaksbr }}</p>
</div>
URLパターンを登録するため、blog/urls.py
のurlpatterns
に次を追加します。
path('post/<int:pk>/edit/' , views.post_edit, name='post_edit' ),
テンプレートは blog/templates/blog/post_edit.html
を再利用するのでそのままです。
ビューは、blog/views.py
に次を追加します。
def post_edit (request, pk):
""" 投稿を編集する """
post = get_object_or_404(Post, pk=pk)
if request.method == "POST" :
form = PostForm(request.POST, instance=post)
if form.is_valid():
post = form.save(commit=False )
post.author = request.user
post.published_date = timezone.now()
post.save()
return redirect('post_detail' , pk=post.pk)
else :
form = PostForm(instance=post)
return render(request, 'blog/post_edit.html' , {'form' : form})
これでOK。
セキュリティ
誰でも新しい投稿を作成することができてしまう状態なので、管理者でログインしているユーザのみ新しい投稿ボタンを表示させるようにします。
blog/templates/blog/base.html
のボタン部分を、次のように編集します。
{% if user.is_authenticated %}
< a href = "{% url 'post_new' %}" class = "top-menu" >< span class = "glyphicon glyphicon-plus" ></ span ></ a >
{% endif %}
この{% if %}は、ページをリクエス トしているユーザーがログインしている場合にのみ、リンクがブラウザに送信されるようにします。 これは新しい投稿の作成を完全に保護するものではありませんが、それは良い第一歩です。 私たちは拡張レッスンでより多くのセキュリティをカバーします。
(完全に保護するものではないのか……セキュリティ的に何が問題あるんだろう。)
編集ボタンも同様にします。
blog/templates/blog/post_detail.html
の編集ボタン部分を、次のように編集します。
{% if user.is_authenticated %}
< a class = "btn btn-default" href = "{% url 'post_edit' pk=post.pk %}" >< span class = "glyphicon glyphicon-pencil" ></ span ></ a >
{% endif %}
これでOK。
シークレットウィンドウでページを読み込むと、リンクが表示されず、アイコンも表示されなくなります。
チュートリアル は以上です。
次のステップは?
次のステップは? · Django Girls Tutorial
感想
Django のモデル、ビュー、テンプレート、フォームの概念の説明がわかりやすかった。