2023年6月26日 2023年8月5日Python
サンプルプロジェクトのテンプレート
Djangoで簡単なアプリケーションを開発するためのテンプレート
アプリケーション概要
Web画面からデータベースにテキストを登録する
登録するユーザーを管理する
テキスト中の[projectname] [appname]について
それぞれ任意のプロジェクト名、アプリケーション名を付ける
[ ]は視認性のためなのでコマンドや設定ファイルでは不要
ここではsampleproject、sampleappで作業を行う
1.開発環境を構築する
仮想環境を作成する
PythonのvenvコマンドでDjango用の仮想環境を作成する
python -m venv .env_django
ライブラリをインストールする
作成したPythonの仮想環境にDjangoのライブラリをインストールする
pip install django
2.プロジェクトを作成する
django-admin コマンドでプロジェクトを作成する
django-admin startproject [projectname]
Djangoのプロジェクトを作成する
仮想環境に作成するのでvenvが起動している状態で実行する
プロジェクト初期のファイル構成
[projectname] フォルダ
__init__.py
asgi.py
settings.py
urls.py
wsgi.py
manage.py
初期の雛形ファイルを用いてローカルサーバを起動する
コマンドでローカルサーバを起動する
python manage.py runserver
プロジェクト設定を変更する
[projectname]/settings.py
変更箇所
変更前
変更後
LANGUAGE_CODE
en-us
ja
TIME_ZONE
UTC
Asia/Tokyo
3.データベースをセットアップする
テーブルを作成する
コマンドでマイグレーションを実行しテーブルを作成する
python manage.py migrate
実行結果
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
(中略)
Applying sessions.0001_initial... OK
4.アプリケーションを作成する
機能の最小単位となるアプリケーションを作成する
プロジェクトの中にアプリケーションの雛形を作成する
python manage.py startapp [appname]
この時点でのファイル構成
[appname] フォルダ
[projectname] フォルダ
db.sqlite3
manage.py
プロジェクト設定を変更する
[projectname]/settings.py
'[appname].apps.[Appname]Config', の形式でアプリケーション設定を追加する
変更箇所
変更前
変更後
INSTALLED_APPS
(末尾に追加する)
'sampleapp.apps.SampleappConfig',
5.トップページを表示する
ビュー関数を定義する
[appname]/views.py
from django.http import HttpResponse
def top(request):
return HttpResponse(b'Hello World from app/views.py ')
ルーティングを設定する
[projectname]/urls.py
from django.contrib import admin
from django.urls import path
from sampleapp.views import top
urlpatterns = [
path('', top, name='top'),
path('admin/', admin.site.urls),
]
django.urls.path の引数について
HTTPリクエストパス
ここでは '/' へのアクセスに対してtop関数を呼び出す設定
先頭の / は省略するため空白を指定している
ビュー関数(views.py のtop関数)
URLの逆引き時に利用するキーワード引数
ブラウザから確認する
ローカルサーバを起動する
python manage.py runserver
追加のルーティング設定をする
以下のページを作成する想定でルーティングを設定しておく
ページ
内容
top
一覧画面
sample_new
登録画面
sample_edit
編集画面
sample_detail
詳細画面
[appname]/views.py
from django.http import HttpResponse
def top(request):
return HttpResponse(b'Hello World from app/views.py ')
def sample_new(request):
return HttpResponse('登録画面')
def sample_edit(request, sample_id):
return HttpResponse('編集画面')
def sample_detail(request, sample_id):
return HttpResponse('詳細画面')
[appname]/urls.py を新規作成する
from django.urls import path
from sampleapp import views
urlpatterns = [
path('new/', views.sample_new, name='sample_new'),
path('/', views.sample_detail, name='sample_detail'),
path('/edit/', views.sample_edit, name='sample_edit'),
]
[projectname]/urls.py
from django.contrib import admin
from django.urls import path, include
from sampleapp.views import top
urlpatterns = [
path('', top, name='top'),
path('sampleapp/', include('sampleapp.urls')),
path('admin/', admin.site.urls),
]
6.データベースと連携する
モデルを定義する
[appname]/models.py
from django.conf import settings
from django.db import models
class Sample(models.Model):
title = models.CharField('タイトル', max_length=128)
text = models.TextField('テキスト', blank=True)
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='登録者', on_delete=models.CASCADE)
created_at = models.DateTimeField('登録日', auto_now_add=True)
updated_at = models.DateTimeField('更新日', auto_now=True)
def __str__(self):
return self.title
データベースをマイグレーションする
マイグレーションを作成する
python manage.py makemigrations
実行結果
Migrations for 'sampleapp':
sampleapp\migrationsMigrations for 'sampleapp':
sampleapp\migrations\0001_initial.py
- Create model Sample 01_initial.py
- Create model Sample
マイグレーションをテーブルに反映する
python manage.py migrate
実行結果
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sampleapp, sessions
Running migrations:
Applying sampleapp.0001_initial... OK
7.管理画面を利用する
管理画面からのテーブル操作を有効にする
[appname]/admin.py
from django.contrib import admin
from sampleapp.models import Sample
admin.site.register(Sample)
ユーザを作成する
管理者となるadmin権限を持つユーザを作成する
python manage.py createsuperuser
実行結果
Username (leave blank to use 'username'): admin
Email address: admin@sample.com
Password:
Password (again):
Superuser created successfully.
管理画面にログインする
ローカルサーバを起動する
python manage.py runserver
8.データベースを操作する
Pythonのシェルからデータベースを操作する
シェルを起動する
python manage.py shell
データを取得する
作成したユーザ情報を取得する
from django.contrib.auth.models import User
users = User.objects.all()
users
実行結果
<QuerySet [<User: admin>]>
IDを指定してユーザデータを取得する
User.objects.get(id=1)
実行結果
<User: admin>
ユーザ名を指定してユーザデータを取得する
User.objects.get(username='admin')
実行結果
<User: admin>
データを作成する
モデル定義に合わせてデータを作成する
from sampleapp.models import Sample
admin_user = User.objects.get(id=1)
sample = Sample(title='コマンドからのテスト入力',
text='コマンドからのテスト入力です',
created_by=admin_user)
作成された項目を表示する
sample.title
実行結果
'コマンドからのテスト入力'
自動採番項目はsaveメソッドを実行しないと反映されない
sample.id
実行結果
>>>(表示なし)
saveを実行して再度確認する
sample.save()
sample.id
実行結果
1
データを更新する
id=1のtitle属性を更新する
sample = Sample.objects.get(id=1)
sample.title = 'コマンドからの更新テスト'
sample.save()
Sample.objects.all()
実行結果
<QuerySet [<Sample: コマンドからの更新テスト>]>
データを削除する
deleteメソッドでデータを削除する
sample.delete()
実行結果
(1, {'sampleapp.Sample': 1})
削除の確認をする
Sample.objects.all()
実行結果
<QuerySet []>
9.トップページをHTMLファイルで表示する
HTMLファイルを作成する
[appname]フォルダ配下にHTMLファイル用のフォルダを作成する
[appname]/templates/[appname]
sampleapp/templates/sampleapp/top.html
<html>
<head>
<meta charset="utf-8">
<title>sampleappのトップページ</title>
</head>
<body>
<p>Hello World from sampleapp/templates/sampleapp/top.html</p>
</body>
</html>
ルーティングの設定をする
[appname]/views.py
from django.http import HttpResponse
from django.shortcuts import render
def top(request):
return render(request, 'sampleapp/top.html')
def sample_new(request):
return HttpResponse('登録画面')
def sample_edit(request, sample_id):
return HttpResponse('編集画面')
def sample_detail(request, sample_id):
return HttpResponse('詳細画面')
ブラウザから確認する
ローカルサーバを起動する
python manage.py runserver
10.トップページにデータベースの情報を表示する
ビュー関数を設定する
[appname]/views.py
from django.http import HttpResponse
from django.shortcuts import render
from sampleapp.models import Sample
def top(request):
sampleapp = Sample.objects.all()
context = {'sampleapp': sampleapp}
return render(request, 'sampleapp/top.html', context)
def sample_new(request):
return HttpResponse('登録画面')
def sample_edit(request, sample_id):
return HttpResponse('編集画面')
def sample_detail(request, sample_id):
return HttpResponse('詳細画面')
top.htmlファイルを編集する
[appname]/templates/[appname]/top.html
<html>
<head>
<meta charset="utf-8">
<title>sampleappのトップページ</title>
</head>
<body>
<h1>Django sampleproject のトップページ</h1>
<h2>DB登録情報</h2>
{% if sampleapp %}
<table class="table">
<thead>
<tr>
<th>登録者</th>
<th>登録日</th>
<th>タイトル</th>
</tr>
</thead>
<tbody>
{% for sample in sampleapp %}
<tr>
<th>{{ sample.created_by.username }}</th>
<th>{{ sample.created_at }}</th>
<th><a href="{% url 'sample_detail' sample.id %}">{{ sample.title }}</a></th>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>登録情報がありません</p>
{% endif %}
</body>
</html>
ブラウザから確認する
ローカルサーバを起動する
python manage.py runserver
11.詳細画面を表示する
ビュー関数を設定する
[appname]/views.py
from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404
from sampleapp.models import Sample
def top(request):
sampleapp = Sample.objects.all()
context = {'sampleapp': sampleapp}
return render(request, 'sampleapp/top.html', context)
def sample_new(request):
return HttpResponse('登録画面')
def sample_edit(request, sample_id):
return HttpResponse('編集画面')
def sample_detail(request, sample_id):
sample = get_object_or_404(Sample, pk=sample_id)
return render(request, 'sampleapp/sample_detail.html', {'sample': sample})
htmlファイルを作成する
[appname]/templates/[appname]/sample_detail.html
<html>
<head>
<meta charset="utf-8">
<title>sampleappの詳細画面</title>
</head>
<body>
<div>
<h1>{{ sample.title }} by {{ sample.created_by.username }}</h1>
<h2>登録日: {{ sample.created_at }}</h2>
<h2>{{ sample.text }}</h2>
</div>
</body>
</html>
ブラウザから確認する
ローカルサーバを起動する
python manage.py runserver
12.登録・編集画面を表示する
HTML検証用のフォームファイルを作成する
[appname]/forms.py
from django import forms
from sampleapp.models import Sample
class SampleForm(forms.ModelForm):
class Meta:
model = Sample
fields = ('title', 'text')
ビュー関数を設定する
[appname]/views.py
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseForbidden
from django.shortcuts import render, redirect, get_object_or_404
from sampleapp.forms import SampleForm
from sampleapp.models import Sample
def top(request):
sampleapp = Sample.objects.all()
context = {'sampleapp': sampleapp}
return render(request, 'sampleapp/top.html', context)
@login_required
def sample_new(request):
if request.method == 'POST':
form = SampleForm(request.POST)
if form.is_valid():
sample = form.save(commit=False)
sample.created_by = request.user
sample.save()
return redirect(sample_detail, sample_id=sample.pk)
else:
form = SampleForm()
return render(request, 'sampleapp/sample_new.html', {'form': form})
@login_required
def sample_edit(request, sample_id):
sample = get_object_or_404(Sample, pk=sample_id)
if sample.created_by_id != request.user.id:
return HttpResponseForbidden("このテキストの編集は許可されていません。")
if request.method == "POST":
form = SampleForm(request.POST, instance=sample)
if form.is_valid():
form.save()
return redirect('sample_detail', sample_id=sample_id)
else:
form = SampleForm(instance=sample)
return render(request, 'sampleapp/sample_edit.html', {'form': form})
def sample_detail(request, sample_id):
sample = get_object_or_404(Sample, pk=sample_id)
return render(request, 'sampleapp/sample_detail.html', {'sample': sample})
[appname]/templates/[appname]/sample_new.html
<html>
<head>
<meta charset="utf-8">
<title>sampleappの登録画面</title>
</head>
<body>
<h1>登録フォーム</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">登録</button>
</form>
</body>
</html>
[appname]/templates/[appname]/sample_edit.html
<html>
<head>
<meta charset="utf-8">
<title>sampleappの編集画面</title>
</head>
<body>
<h1>編集フォーム</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">保存</button>
</form>
</body>
</html>
ブラウザから確認する
ローカルサーバを起動する
python manage.py runserver
13.見た目を整える
CSSを適用する
Bootstrapをインストールする
pip install django-bootstrap5
プロジェクト設定を変更する
[projectname]/settings.py
変更箇所
変更前
変更後
INSTALLED_APPS
(末尾に追加する)
'django_bootstrap5',
TEMPLATES
[],
[BASE_DIR / 'templates'],
HTMLファイルを変更する
[appname]/templates/[appname]/top.html
{% load django_bootstrap5 %}
<html>
<head>
<meta charset="utf-8">
<title>sampleappのトップページ</title>
{% bootstrap_css %}
{% bootstrap_javascript %}
</head>
<body>
<nav class="navbar-expand flex-md-row navbar-dark bg-dark">
<div class="container justify-content-between">
<a href="/" class="navbar-brand">sampleapp</a>
</div>
</nav>
<main>
<div class="container">
<div class="welcome">
<h1>Django sampleproject のページ</h1>
<a class="btn btn-primary" href="{% url 'sample_new' %}">テキストの新規登録</a>
</div>
<h3>DB登録情報</h3>
{% if sampleapp %}
<table class="table">
<thead>
<tr>
<th>登録者</th>
<th>登録日</th>
<th>タイトル</th>
</tr>
</thead>
<tbody>
{% for sample in sampleapp %}
<tr>
<th>{{ sample.created_by.username }}</th>
<th>{{ sample.created_at }}</th>
<th><a href="{% url 'sample_detail' sample.id %}">{{ sample.title }}</a></th>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>登録情報がありません</p>
{% endif %}
</div>
</main>
</body>
</html>
CSSファイルを適用する
[appname]/static/[appname]/css/style.css
main {
padding: 2rem 0;
}
.welcome {
padding: 3rem 0;
margin-bottom: 2rem;
background-color: #eee;
align-items: center;
display: flex;
flex-direction: column;
}
.snippet-date {
margin-bottom: 1rem;
}
.source-code>.highlight {
padding: 1rem;
margin-bottom: 1rem;
}
14.HTMLの部品を共通化する
ベースとなるHTMLファイルを作成する
[projectname]/templates/base.html
templates フォルダは [appname] [projectname] と同じ階層
{% load static %}
{% load django_bootstrap5 %}
<html>
<head>
<meta charset="utf-8">
<title>sampleapp</title>
{% bootstrap_css %}
{% bootstrap_javascript %}
<link rel="stylesheet" href="{% static 'sampleapp/css/style.css' %}">
{% block extraheader %}{% endblock %}
</head>
<body>
<nav class="navbar navbar-expand flex-md-row navbar-dark bg-dark">
<div class="container justify-content-between">
<a href="/" class="navbar-brand">sampleapp</a>
</div>
</nav>
<main>
<div class="container">
{% block main %}{% endblock %}
</div>
</main>
</body>
</html>
base.htmlを継承するようにHTMLファイルを変更する
[appname]/templates/[appname]/top.html
{% extends "base.html" %}
{% block main %}
<div class="welcome">
<h1 class="title">Django sampleproject のページ</h1>
<a class="btn btn-primary" href="{% url 'sample_new' %}">テキストの新規登録</a>
</div>
<h3>DB登録情報</h3>
{% if sampleapp %}
<table class="table">
<thead>
<tr>
<th>登録者</th>
<th>登録日</th>
<th>タイトル</th>
</tr>
</thead>
<tbody>
{% for sample in sampleapp %}
<tr>
<th>{{ sample.created_by.username }}</th>
<th>{{ sample.created_at }}</th>
<th><a href="{% url 'sample_detail' sample.id %}">{{ sample.title }}</a></th>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>登録情報がありません</p>
{% endif %}
{% endblock %}
[appname]/templates/[appname]/sample_new.html
{% extends "base.html" %}
{% load django_bootstrap5 %}
{% block main %}
<h2>sampleappの登録画面</h2>
<form method="post">
{% csrf_token %}
{% bootstrap_form form %}
{% bootstrap_button button_type="submit" content="登録" %}
</form>
{% endblock %}
[appname]/templates/[appname]/sample_edit.html
{% extends "base.html" %}
{% load django_bootstrap5 %}
{% block main %}
<h2>sampleappの編集画面</h2>
<form method="post">
{% csrf_token %}
{% bootstrap_form form %}
{% bootstrap_button button_type="submit" content="保存" %}
</form>
{% endblock %}
ブラウザから確認する
ローカルサーバを起動する
python manage.py runserver
ログイン状態で以下の画面にアクセスし見た目を確認する
15.アカウント管理機能を実装する
アプリケーションを作成する
コマンドの実行
python manage.py startapp accounts
ルーティングの設定をする
[projectname]/settings.py
変更箇所
変更前
変更後
INSTALLED_APPS
(末尾に追加する)
'accounts.apps.AccountsConfig',
accounts/urls.py を新規作成する
from django.contrib.auth.views import LoginView, LogoutView
from django.urls import path
urlpatterns = [
path('login/', LoginView.as_view(
redirect_authenticated_user=True,
template_name='accounts/login.html'
), name='login'),
path('logout/', LogoutView.as_view(), name='logout'),
]
Django提供のクラスベースビュー(LoginView, LogoutView)を利用してビューの実装を省略する
[projectname]/urls.py
from django.contrib import admin
from django.urls import path, include
from sampleapp.views import top
urlpatterns = [
path('', top, name='top'),
path('sampleapp/', include('sampleapp.urls')),
path('admin/', admin.site.urls),
path('accounts/', include('accounts.urls')),
]
ログイン用のページを作成する
accounts/templates/accounts/login.html を新規作成する
{% extends "base.html" %}
{% load django_bootstrap5 %}
{% block main %}
<h2>ログイン</h2>
<form method="post">
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}" />
{% bootstrap_form form %}
{% bootstrap_button button_type="submit" content="ログイン" %}
</form>
{% endblock %}
ログイン・ログアウト用のリンクを追加する
[projectname]/templates/base.html
{% load static %}
{% load django_bootstrap5 %}
<html>
<head>
<meta charset="utf-8">
<title>sampleapp</title>
{% bootstrap_css %}
{% bootstrap_javascript %}
<link rel="stylesheet" href="{% static 'sampleapp/css/style.css' %}">
{% block extraheader %}{% endblock %}
</head>
<body>
<nav class="navbar navbar-expand flex-md-row navbar-dark bg-dark">
<div class="container justify-content-between">
<a href="/" class="navbar-brand">sampleapp</a>
<ul class="navbar-nav mr-md-2">
{% if user.is_authenticated %}
<li class="nav-item"><a class="nav-link" href="{% url 'logout' %}">ログアウト</a></li>
{% else %}
<li class="nav-item"><a class="nav-link" href="{% url 'login' %}">ログイン</a></li>
{% endif %}
</ul>
</div>
</nav>
<main>
<div class="container">
{% block main %}{% endblock %}
</div>
</main>
</body>
</html>
プロジェクト設定を変更する
[projectname]/settings.py
# ユーザー認証
#
LOGIN_URL = '/accounts/login/'
LOGIN_REDIRECT_URL = '/'
LOGOUT_REDIRECT_URL = '/'
ブラウザから確認する
ローカルサーバを起動する
python manage.py runserver
16.ユーザー登録機能の実装
パスを設定する
accounts/urls.py
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.views import LoginView, LogoutView
from django.urls import path
from django.views.generic import CreateView
urlpatterns = [
path('signup/', CreateView.as_view(
template_name='accounts/signup.html',
form_class=UserCreationForm,
success_url='/',
), name='signup'),
path('login/', LoginView.as_view(
redirect_authenticated_user=True,
template_name='accounts/login.html'
), name='login'),
path('logout/', LogoutView.as_view(), name='logout'),
]
ユーザー登録用のページを作成する
accounts/templates/accounts/signup.html を新規作成する
{% extends "base.html" %}
{% load django_bootstrap5 %}
{% block main %}
<h2>ユーザー登録</h2>
<form method="post">
{% csrf_token %}
{% bootstrap_form form %}
{% bootstrap_button button_type="submit" content="登録" %}
</form>
{% endblock %}
ユーザー登録用のリンクを追加する
[projectname]/templates/base.html
{% load static %}
{% load django_bootstrap5 %}
<html>
<head>
<meta charset="utf-8">
<title>sampleapp</title>
{% bootstrap_css %}
{% bootstrap_javascript %}
<link rel="stylesheet" href="{% static 'sampleapp/css/style.css' %}">
{% block extraheader %}{% endblock %}
</head>
<body>
<nav class="navbar navbar-expand flex-md-row navbar-dark bg-dark">
<div class="container justify-content-between">
<a href="/" class="navbar-brand">sampleapp</a>
<ul class="navbar-nav mr-md-2">
{% if user.is_authenticated %}
<li class="nav-item"><a class="nav-link" href="{% url 'logout' %}">ログアウト</a></li>
{% else %}
<li class="nav-item"><a class="nav-link" href="{% url 'login' %}">ログイン</a></li>
<li class="nav-item"><a class="nav-link" href="{% url 'signup' %}">ユーザー登録</a></li>
{% endif %}
</ul>
</div>
</nav>
<main>
<div class="container">
{% block main %}{% endblock %}
</div>
</main>
</body>
</html>
ブラウザから確認する
ローカルサーバを起動する
python manage.py runserver