django girls tutorialの勉強メモです
https://tutorial.djangogirls.org/ja/
試行環境
PythonAnywhereというPaaSを使ってデプロイするtutorialなので、pythonとgitが入る環境ならどこでも出来ます。環境構築についてもtutorial内にありますので、pythonとgitが入ってない方は以下のリンクを参照してください。
https://tutorial.djangogirls.org/ja/python_installation/
1.プロジェクトを作成して動かしてみる
まず適当な場所にprojectディレクトリを作成します。今回は /home/ユーザ名/django/proj1 にprojectを作成しました。
mkdir django
cd django
django-admin startproject proj1
以下のようなファイルが自動で作成されます。
proj1
├── manage.py
├── mysite
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── myvenv
│ └── ...
└── requirements.txt
設定ファイルであるsettings.pyに必要な設定を書き込んでいきます。
タイムゾーンと言語
以下では日本標準時と日本語に設定しています。
TIME_ZONE = 'Asia/Tokyo'
LANGUAGE_CODE = 'ja'
静的ファイルのPATH
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
読み込みを許容するURL
ALLOWED_HOSTを * にしておくとすべてのURLへの読み込みが可能になりますが、httpインジェクション攻撃に無防備になってしまいます。必要なURLのみlistに追加するようにしましょう。今回は簡易サーバーでlocalhostでテストをした後、pythonanywhere.comにデプロイするので以下の2つを追加しておきます。
ALLOWED_HOSTS = ['127.0.0.1', '.pythonanywhere.com']
データベースの設定
sqlite3を使用する場合は以下のようにします。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
djangoのテストサーバーを起動する
仮サーバーを動かしてみてどうなったか確認します。
python manage.py migrate
python manage.py runserver
http://localhost:8000 をブラウザで開くとdjangoのサンプルページが表示される筈です。
表示内容に関わる部分は変更していないのでデフォルトのサンプルページが表示されます。
2. modelを作成する
プロジェクトの中に複数のアプリを作る事ができるようになっているので、blogというディレクトリにblogアプリを作成していきます。
python manage.py startapp blog
以下のようにblogという名前のディレクトリが追加されます。
proj1
├── blog
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── db.sqlite3
├── manage.py
├── mysite
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── myvenv
│ └── ...
└── requirements.txt
settings.pyのINSTALLED_APPSに追加したアプリを追加してdjangoが読みに来るようにしてやります。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog.apps.BlogConfig',
]
models.pyのMVCモデルのMにあたるmodelの部分を書いていきます。modelはデータベースの読み書きやデータの処理などのバックエンド部分を担当します。
django.db.models.Modelクラスを継承して
from django.conf import settings
from django.db import models
from django.utils import timezone
class Post(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, 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.CharField – 文字数が制限されたテキストを定義するフィールド
models.TextField – これは制限無しの長いテキスト用です。ブログポストのコンテンツに理想的なフィールドでしょ?
models.DateTimeField – 日付と時間のフィールド
models.ForeignKey – これは他のモデルへのリンク
作成したモデルをデータベースに追加します。
python manage.py makemigrations blog
python manage.py migrate blog
Operations to perform:
Apply all migrations: blog
Running migrations:
Applying blog.0001_initial... OK
上のように表示されていればmigrationに成功しています。
3. modelをadminページに追加する
管理画面から先程作ったmodelを見えるようにする為、from .models import Postで先程作ったPostクラスをimportして、admin.site.register(Post)をadmin.pyに追記します。
from django.contrib import admin
from .models import Post
admin.site.register(Post)
管理画面にログインできるdjangoのsuper userを作成します。
python manage.py createsuperuser
管理画面を開きます。
http://localhost:8000/admin/
UsernameとPasswordを入力すると管理画面に入れます。
Postsの右にある追加ボタンを押せばpostを追加出来るようになります。
適当なPostを記入してみます。
どうやらmodelは正常に動いているようです。
ちなみに、まだviewを変更してないのでトップページはロケットのままです。
http://localhost:8000/
4. デプロイする
この章ではgithubにレポジトリを作り、PythonAnywhereにブログをデプロイします。
githubにpushする
まず、githubにログインしてレポジトリを作成します。レポジトリ名はmy-first-blogにしておきます。アカウントがない場合は無料で作れるのでアカウントを作成します。
https://github.com/
terminalを開いてgitをインストールします。
sudo apt install git
インストール出来たらプロジェクトのディレクトリ(今回の場合は/home/ユーザー名/django/proj1/)でgit initしてからユーザー名とemailアドレスを登録します。以下はユーザー名「hoge」、メールアドレス「fuga@gmail.com」の場合です。
git init
git config --global user.name hoge
git config --global user.email fuga@gmail.com
gitに反映しないファイル/ディレクトリを.gitignoreに登録しておきます。
*.pyc
*~
/.vscode
__pycache__
myvenv
db.sqlite3
/static
.DS_Store
.gitignoreが反映されているか確認しておきます。
git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
.gitignore
blog/
manage.py
mysite/
nothing added to commit but untracked files present (use "git add" to track)
無事反映されているようですのでgithubにpushします。
git add --all
git commit -m "first commit"
git remote add origin https://github.com/ユーザー名/my-first-blog.git
git push -u origin master
正常にpush出来ていればgithubのレポジトリにファイルが表示されます。
PythonAnywhereにデプロイする
PythonAnyWhereのアカウントを作成します
https://www.pythonanywhere.com/
アカウントを作ったら右上のメニューからAccountページに移動してAPI Tokenを作成します。
Dashboardの左下のNew consoleを開きます。
開くと下のようにコンソールが開きます。
ヘルパーツールをインストールして、ヘルパーツールによりgithubの内容をデプロイします。
pip3.6 install --user pythonanywhere
pa_autoconfigure_django.py --python=3.6 https://github.com/githubのユーザー名/my-first-blog.git
lsコマンドで同期されたファイルを確認してみましょう。
$ ls
blog db.sqlite3 manage.py proj1 static
$ ls blog/
__init__.py __pycache__ admin.py apps.py migrations models.py tests.py views.py
PythonAnywhereのFilesページから確認することも出来ます。
ヘルパーツールはgithubのコードを使って新規に仮想環境を構築していますので先程作ったdjango superuserはまだ登録されていませんから、下のコマンドで登録してやります。
python manage.py createsuperuser
これでローカルで作ったのと同じものがインターネットに公開された状態になります。PythonAnywhere DashboardからWebAppsページに移動すればサイトのリンクが貼ってありますので、そこから開くことが出来ます。
管理画面に入るとまだPostがないのが分かります。これは.gitignoreに書いてあるのでデータベースがgithubに同期されていないからです。うっかり本番環境のDBを上書きしない為に.gitignoreの設定は非常に重要です。
5. viewを作る
ここでは実際にページを表示する為のviewを作り、viewまでのリンクを書いていきます。
viewまでのリンクを書く
urls.pyを開くと以下のように書かれていて、http://localhost/admin/ に来たらadmin.site.urlsを参照するよう指定されています。まだblogビューへのリンクが指定されていませんのでこれを書いていきます。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('blog.urls')),
]
トップページであるhttp://localhost/ に来たらproj1/blog/urls.pyを参照するように追記します。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('blog.urls')),
]
blog.urls.pyを作成して、http://localhost/ に来たらblog/views.pyからpost_listという名前のviewを参照するように指定します。
from django.urls import path
from . import views
urlpatterns = [
path('', views.post_list, name='post_list'),
]
views.pyに上記で参照するように設定したpost_list関数を記述します。ここではblog/post_list.htmlの内容をそのまま返すようにしています。
from django.shortcuts import render
def post_list(request):
return render(request, 'blog/post_list.html', {})
これで、http://localhost/ に来たらproj1/urls.py → proj1/blog/urls.py → proj1/blog/views.py → proj1/blog/post_list.htmlとリンクが繋がるようになりました。
ここでpython manage.py runserverしてページを開くと、まだproj1/blog/post_list.htmlがないのでエラーページが表示されます。
もしrunserverが失敗してページが表示されないときはここまで書いてきたどこかが間違ってますので確認しましょう。
view templateを作る
proj1/blog/templates/blog/post_list.htmlを作成して再度python manage.py runserverしてページを確認するとようやくエラーなしでページが表示されます。ただし、まだ何も書かれていないので何も表示されてないページになります。
適当にhtmlを書けばそのまま表示されます。
<html>
<body>
<p>Hi there!</p>
<p>It works!</p>
</body>
</html>
<html>
<head>
<title>Django Girls blog</title>
</head>
<body>
<div>
<h1><a href="/">Django Girls Blog</a></h1>
</div>
<div>
<p>published: 14.06.2014, 12:14</p>
<h2><a href="">My first post</a></h2>
<p>Aenean eu leo quam. こんにちは! よろしくお願いします! </p>
</div>
<div>
<p>公開日: 2014/06/14, 12:14</p>
<h2><a href="">2番目の投稿</a></h2>
<p> こんにちは! よろしくお願いします! </p>
</div>
</body>
</html>
デプロイする
ここまでの内容をPythonAnywhereにデプロイしてみます。
git add --all
git commit -m "changed the html for the site"
git push
PythonAnywhere command-lineを開いてpullします。
git pull
PythonAnywhere DashboardからWebのページに移動し、Reloadしてからサイトを開くと同じ内容が表示される筈です。
6. クエリセットの使い方
クエリセットを使えばdjangoがアクセスするのと同じようにデータベースに読み書き出来ます。これにより実際に動かしてみて思ったとおりの動作になった記述をview.pyに書いていくというやり方が出来ます。
django shellでクエリセットを開きます。
python manage.py shell
PostクラスをimportしてPost.objects.all()ですべてのポストデータを表示してみましょう。
>>> from blog.models import Post
>>> Post.objects.all()
<QuerySet [<Post: たいとる1>, <Post: たいとる2>, <Post: たいとる3>]>
Postを追加してみます。
>>> from django.contrib.auth.models import User
>>> me = User.objects.get(username='ユーザ名')
>>> Post.objects.create(author=me, title='Sample title', text='Test')
>>> Post.objects.all()
<QuerySet [<Post: たいとる1>, <Post: たいとる2>, <Post: たいとる3>, <Post: Sample title>]>
足したPostが末尾に追加されていますね。
続いてtitleに'title'が含まれるPostだけ表示してみます。
>>> Post.objects.filter(title__contains='title')
<QuerySet [<Post: Sample title>]>
公開済みのPostを表示してみます。
>>> from django.utils import timezone
>>> Post.objects.filter(published_date__lte=timezone.now())
<QuerySet []>
公開します。
>>> post = Post.objects.get(title="Sample title")
>>> post.publish()
>>> Post.objects.filter(title__contains='title')
<QuerySet [<Post: Sample title>]>
djangoに登録したsuper userの一覧も表示できます。
>>> User.objects.all()
<QuerySet [<User: ユーザ名>]>
投稿順に表示したり、逆順に表示したりもできます。
>>> Post.objects.order_by('created_date')
<QuerySet [<Post: たいとる1>, <Post: たいとる2>, <Post: たいとる3>, <Post: Sample title>]>
>>> Post.objects.order_by('-created_date')
<QuerySet [<Post: Sample title>, <Post: たいとる3>, <Post: たいとる2>, <Post: たいとる1>]>
クエリを連ねて書くことも出来ます。
>>> Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
<QuerySet [<Post: Sample title>]>
クエリセットからはexit()で抜けることが出来ます。
exit()
7. 動的なview templateを作る
データベースに保存されているPostの内容を表示するようにview templateを書いていきます。先程クエリセットでやったように公開済みのPostデータをテンプレートに渡して表示するように書いています。
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})
先程作成したblog/post_list.htmlは静的なhtmlを書いていましたが、データベースから受け取った値を表示するように書き換えます。
{% %}で囲んだ範囲はpythonスクリプトが実行され、{{ }}で囲んだ範囲には受け渡したオブジェクトの値が挿入されますので、postを順番に表示していくという記述になっています。
<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>
<h2><a href="">{{ post.title }}</a></h2>
<p>{{ post.text|linebreaksbr }}</p>
</div>
{% endfor %}
</body>
</html>
これで管理ページで入力したPostの内容が表示されるようになった筈なので、python manage.py runserverで表示を確認します。
無事完成です。
8. CSSでかわいくする
Bootstrapを使ってかわいいデザインを作っていきます。
まず、post_list.htmlのheadにリンクを貼ってBootstrapを使えるようにします。
<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">
これだけでBootstrapのデフォルトCSSが設定されるのでちょっとデザインが変わります。
CSSファイルを作る
djangoはstaticと名付けられたフォルダを静的ファイルだと認識しますので、staticディレクトリ内にcssディレクトリを作って、その中にblog.cssを置いてやります。
proj1
└─── blog
└─── static
└─── css
└─── blog.css
このファイルには普通にCSSを書いていきます。とりあえず見出しのaタグの色を変えてやりましょう。
h1 a, h2 a {
color: #C25100;
}
blog.cssを反映するように {% load static %} と {% static 'css/blog/css' %} を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>
<body>
<div>
<h1><a href="/">Django Girls Blog</a></h1>
</div>
{% for post in posts %}
<div>
<p>published: {{ post.published_date }}</p>
<h2><a href="">{{ post.title }}</a></h2>
<p>{{ post.text|linebreaksbr }}</p>
</div>
{% endfor %}
</body>
</html>
CSSが反映されて見出しのaタグの文字色がオレンジになりました。
色々追加してみる
h1 a, h2 a {
color: #C25100;
font-family: 'Lobster';
}
body {
padding-left: 15px;
}
.page-header {
background-color: #C25100;
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 h2 a, .post h2 a:visited {
color: #000000;
}
{% 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 href="//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>
{% for post in posts %}
<div class="post">
<p>published: {{ post.published_date }}</p>
<h2><a href="">{{ post.title }}</a></h2>
<p>{{ post.text|linebreaksbr }}</p>
</div>
{% endfor %}
</body>
</html>
9. テンプレートの拡張
viewテンプレートは共通する部分を使いまわす事ができます。
例として、先程作ったpost_list.htmlを2つのviewに分けてみましょう。基本デザインを設定する部分をbase.htmlに書いて、Post一覧を表示する部分をpost_list.htmlに書くようにします。
blog
└───templates
└───blog
base.html
post_list.html
{% block content %} から {% endblock %} までのところに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 href="//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側の1行目に {% extends 'blog/base.html' %} と書くことで base.html を拡張して使うように指示しています。
{% extends 'blog/base.html' %}
{% block content %}
{% for post in posts %}
<div class="post">
<div class="date">
{{ post.published_date }}
</div>
<h2><a href="">{{ post.title }}</a></h2>
<p>{{ post.text|linebreaksbr }}</p>
</div>
{% endfor %}
{% endblock %}
サーバーを再起動してページを表示すると先程と同じものが表示される筈です。
10. アプリケーションの拡張
それぞれのblog postを表示するページを追加します。
テンプレートへのリンクを作成する
html://localhost/post/****/ に来たときに view.post_detail()関数を参照するように指定します。int:pk は文字列をint型に変換してpkに代入し、views.post_detail(request, pk) のように引数に与える事を意味しています。
from django.urls import path
from . import views
urlpatterns = [
path('', views.post_list, name='post_list'),
path('post/<int:pk>/', views.post_detail, name='post_detail'),
]
proj1/blog/views.py に post_detail関数を追加します。また、Postオブジェクトに該当する記事がなかった場合に404を返すようにget_object_or_404()を使っています。render関数の第2引数で'blog/post_detail.html'をview templateとして使う事を指定しています。
from django.shortcuts import render, get_object_or_404
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, 'blog/post_detail.html', {'post': post})
記事を表示する為のview templateを追加します。base.htmlを使いまわしているので短く書けます。
{% extends 'blog/base.html' %}
{% block content %}
<div class="post">
{% if post.published_date %}
<div class="date">
{{ post.published_date }}
</div>
{% endif %}
<h2>{{ post.title }}</h2>
<p>{{ post.text|linebreaksbr }}</p>
</div>
{% endblock %}
最後にpost_list.htmlの記事タイトルを表示している
タグにリンクを書き足して完成です。
proj1/blog/templates/blog/post_list.html
<h2><a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a></h2>
<h2><a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a></h2>
デプロイする
ここまでの内容をgitにpushしてデプロイしてみましょう。
git status
git add --all .
git status
git commit -m "Added view and template for detailed blog post as well as CSS for the site."
git push
cd ~/ドメイン名.pythonanywhere.com
git pull
CSSが反映されていませんが、これはPythonAnywhereでは静的ファイルの置き場所が別になっているからです。ツールを使うと自動で配置してくれます。
workon ユーザ名.pythonanywhere.com
python manage.py collectstatic
11-1. 投稿フォームを作る
ここまでの操作ではブログPostを管理画面であるhttp://localhost/admin/ から入力していましたが、もう少し入力しやすいようにフォームを作る事が出来ます。
投稿フォームを作る
blog
└── forms.py
forms.ModelFormクラスを継承して一部だけ追記してフォームを作ってやります。ここではtitleとtextの入力するフォームにしています。
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ('title', 'text',)
投稿フォームへのリンクをbase.htmlに貼る
base.htmlの上部に投稿フォームへのリンクを貼る為、以下の1行を追記します。class="glyphicon glyphicon-plus"にするとBootstrapの機能を使って+を表示します。
<a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>
{% 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 href='//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">
<a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>
<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>
urls.pyに追加
http://localhost:8000/post/new/ に来たらviews.post_new関数を呼ぶようにしてやります。
path('post/new/', views.post_new, name='post_new'),
from django.urls import path
from . import views
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'),
]
urls.pyが呼ぶ関数をviews.pyに追加する
from django.shortcuts import redirect
def post_new(request):
if request.method == "POST":
form = PostForm(request.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()
return render(request, 'blog/post_edit.html', {'form': form})
python manage.py runserver して、http://localhost:8000/post/new/ をブラウザで開くと以下のように新規投稿ページが表示されます。
11-2. 投稿済みPostの編集フォームを作る
先程と同じようにして記事の編集機能を追加してみます。
編集フォーム
フォーム自体は新規投稿フォームと同じものを使います。
編集ボタンを配置する
<a class="btn btn-default" href="{% url 'post_edit' pk=post.pk %}"><span class="glyphicon glyphicon-pencil"></span></a>
{% extends 'blog/base.html' %}
{% block content %}
<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>
<h2>{{ post.title }}</h2>
<p>{{ post.text|linebreaksbr }}</p>
</div>
{% endblock %}
urls.pyにリンクを追加
path('post/<int:pk>/edit/', views.post_edit, name='post_edit'),
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})
11-3. ログイン時のみ編集可能にする
新規投稿ボタン
<a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>
{% if user.is_authenticated %}
<a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>
{% endif %}
記事編集ボタン
<a class="btn btn-default" href="{% url 'post_edit' pk=post.pk %}"><span class="glyphicon glyphicon-pencil"></span></a>
{% if user.is_authenticated %}
<a class="btn btn-default" href="{% url 'post_edit' pk=post.pk %}"><span class="glyphicon glyphicon-pencil"></span></a>
{% endif %}
これでログインしていない場合は編集ボタンが現れなくなりました。
デプロイ
git status
git add --all .
git status
git commit -m "Added view and template for detailed blog post as well as CSS for the site."
git push
cd ~/ドメイン名.pythonanywhere.com
git pull