[Django3.0]mysqlのデータをviewに表示

前提: MySQLの中にデータが入っています。

mysql> select * from sales_master;
+—-+————————————–+——–+———-+————+—————————-+————–+————–+——————–+————–+—————–+—————————-+—————————-+
| id | name | office | zipcode | prefecture | address | tel | fax | mail | name_top | position_top | created_at | updated_at |
+—-+————————————–+——–+———-+————+—————————-+————–+————–+——————–+————–+—————–+—————————-+—————————-+
| 1 | 東京テクノロジー株式会社 | 本社 | 100-6321 | 東京都 | 千代田区丸の内2-4-1 | 03-1234-5678 | 03-1234-5679 | info@tokyotech.com | 山田太郎 | 代表取締役 | 2020-08-22 15:00:00.000000 | 2020-08-22 15:00:00.000000 |
+—-+————————————–+——–+———-+————+—————————-+————–+————–+——————–+————–+—————–+—————————-+—————————-+
1 row in set (0.00 sec)

### template側
まず、データを表示させるtemplateを作成します。

/sales/urls.py

urlpatterns = [
	// 省略
	path('master/edit', views.master, name='master'),
	path('master/detail', views.master_detail, name='master_detail'),
	// 省略
]

/sales/views.py

def master_detail(request):
	return render(request, 'sales/master_detail.html')

/templates/sales/master_detail.html

{% extends 'sales/layout.html' %}
{% load static %}

{% block title %}自社基本情報 | hanbai - 自社基本情報を表示しています{% endblock %}

{% block description %}<meta name="Description" content="見積管理、在庫管理、販売管理はhanbai">{% endblock %}

{% block header_script %}
	// 省略
{% endblock %}

	
{% block content %}
			<div class="client">

				<nav aria-label="パンくずリスト">
					<ol class="breadcrumb">
	  					<li class="breadcrumb-item" aria-current="page">得意先詳細:○○株式会社</li>
					</ol>
				</nav>

				<table class="table">
					<tr>
						<td class="bg">会社名</td>
						<td>ABC商事株式会社</td>
						<td class="bg">事業所</td>
						<td>本社</td>
					</tr>
					<tr>
						<td class="bg">郵便番号</td>
						<td>100-0001</td>
						<td class="bg">都道府県</td>
						<td>東京都</td>
					</tr>
					<tr>
						<td class="bg">住所</td>
						<td colspan="3">千代田区大手町1-1-1</td>
					</tr>
					<tr>
						<td class="bg">電話番号</td>
						<td>03-1234-5678</td>
						<td class="bg">FAX</td>
						<td>03-1234-5679</td>
					</tr>
					<tr>
						<td class="bg">会社メールアドレス</td>
						<td colspan="3">info@abc.co.jp</td>
					</tr>
					<tr>
						<td class="bg">代表者</td>
						<td>山田太郎</td>
						<td class="bg">代表者役職</td>
						<td>代表取締役</td>
					</tr>
					<tr>
						<td class="bg">登録日時</td>
						<td>2020/08/20</td>
						<td class="bg">更新日時</td>
						<td>2020/08/20</td>
					</tr>
				</table>

			<br>
			</div>
{% endblock %}

{% block script %}
{% endblock %}

ここにmysqlからデータを引っ張ってくる

### views.pyの編集
/sales/views.py

from django.shortcuts import render
from django.http import HttpResponse
from .models import Master

def master_detail(request):
	data = Master.objects.get(id=1)
	params = {
		'data' : data
	}
	return render(request, 'sales/master_detail.html', params)

### template側
/templates/sales/master_detail.html

<table class="table">
					<tr>
						<td class="bg">会社名</td>
						<td>{{data.name}}</td>
						<td class="bg">事業所</td>
						<td>{{data.office}}</td>
					</tr>
					<tr>
						<td class="bg">郵便番号</td>
						<td>{{data.zipcode}}</td>
						<td class="bg">都道府県</td>
						<td>{{data.prefecture}}</td>
					</tr>
					<tr>
						<td class="bg">住所</td>
						<td colspan="3">{{data.address}}</td>
					</tr>
					<tr>
						<td class="bg">電話番号</td>
						<td>{{data.tel}}</td>
						<td class="bg">FAX</td>
						<td>{{data.fax}}</td>
					</tr>
					<tr>
						<td class="bg">会社メールアドレス</td>
						<td colspan="3">{{data.mail}}</td>
					</tr>
					<tr>
						<td class="bg">代表者</td>
						<td>{{data.name_top}}</td>
						<td class="bg">代表者役職</td>
						<td>{{data.position_top}}</td>
					</tr>
					<tr>
						<td class="bg">登録日時</td>
						<td>{{data.created_at}}</td>
						<td class="bg">更新日時</td>
						<td>{{data.updated_at}}</td>
					</tr>
				</table>

おおおお、何事もなく表示できました。割と簡単すぎた。
1件だけ取得した場合はforループで回す必要がない為、html側では{{data.${カラム名}}}とするだけですね。
created_atとupdate_atは、mysql側では”2020-08-22 15:00:00.000000″で入っているのに、view側では”2020年8月23日0:00″で表示されているので、ここを直したい。

[Django3.0]レイアウト用テンプレートでインクルード

layout.htmlを作成し、編集箇所を{% block * %}{% endblock %}で囲む。
includeする側は{% extends ‘sales/layout.html’ %}で読み込む。
{% load static %}は、読み込むhtml側に記載しないとErrorになる

sales/templates/sales/layout.html

{% load static %}
<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<title>{% block title %}{% endblock %}</title>
	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
	{% block description %}{% endblock %}
	<meta name="Description" content="見積管理、在庫管理、販売管理はhanbai">

	{% block header_script %}{% endblock %}
</head>
<body>
	<div class="wrapper">

		<nav class="navbar navbar-expand-md navbar-dark fixed-top" style="background-color:#1e90ff">
			<a class="navbar-brand" href="/top.html">Hanbai</a>
			<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
				<span class="navbar-toggler-icon"></span>
			</button>
			<div class="collapse navbar-collapse" id="navbarCollapse">
				<ul class="navbar-nav mr-auto">
					<li class="nav-item dropdown  active">
						<a class="nav-link dropdown-toggle" href="/estimate" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">見積管理</a>
						<div class="dropdown-menu" aria-labelledby="navbarDropdown">
							<a class="dropdown-item" href="/estimate">見積一覧</a>
							<hr>
							<a class="dropdown-item" href="/estimate/input">見積登録</a>
						</div>
					</li>
					<li class="nav-item dropdown active">
						<a class="nav-link dropdown-toggle" href="/order" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">受注管理</a>
						<div class="dropdown-menu" aria-labelledby="navbarDropdown">
							<a class="dropdown-item" href="/order">受注一覧</a>
							<hr>
							<a class="dropdown-item" href="/order/input">受注登録</a>
						</div>
					</li>
					<li class="nav-item dropdown active">
						<a class="nav-link dropdown-toggle" href="/stock" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">在庫管理</a>
						<div class="dropdown-menu" aria-labelledby="navbarDropdown">
							<a class="dropdown-item" href="/stock">在庫一覧</a>
							<hr>
							<a class="dropdown-item" href="/stock/input">在庫登録</a>
						</div>
					</li>
					<li class="nav-item dropdown active">
						<a class="nav-link dropdown-toggle" href="/client" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">得意先管理</a>
						<div class="dropdown-menu" aria-labelledby="navbarDropdown">
							<a class="dropdown-item" href="/client">得意先一覧</a>
							<hr>
							<a class="dropdown-item" href="/client/input">得意先登録</a>
						</div>
					</li>
					<li class="nav-item dropdown active">
						<a class="nav-link dropdown-toggle" href="/master" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">その他</a>
						<div class="dropdown-menu" aria-labelledby="navbarDropdown">
							<a class="dropdown-item" href="/master">自社基本情報</a>
						</div>
					</li>
				</ul>
				<ul class="navbar-nav">
					<li class="nav-item">
						<a class="nav-link" href="">ログアウト</a>
					</li>
				</ul>
			</div>
		</nav>

		<div class="container">
			{% block content %}{% endblock %}
				
		</div>
		<footer>
			<p>&copy; Hanbai All Right Reserved.</p>
		</footer>
	</div>

	{% block script %}{% endblock %}
	
</body>
</html>

sales/templates/sales/index.html

{% extends 'sales/layout.html' %}
{% load static %}

{% block title %}Top | hanbai - トップページを表示しています{% endblock %}

{% block description %}<meta name="Description" content="見積管理、在庫管理、販売管理はhanbai">{% endblock %}

{% block header_script %}
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

	<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>

	<link rel="stylesheet" href="{% static 'sales/css/styles.css' %}">
	<script src="/js/main.js"></script>
{% endblock %}

	
{% block content %}
			<div class="top">
				<nav aria-label="パンくずリスト">
					<ol class="breadcrumb">
	  					<li class="breadcrumb-item active" aria-current="page">ホーム</li>
					</ol>
				</nav>
				// 省略
{% endblock %}

{% block script %}
	// 省略
{% endblock %}

Sugeeeeeeeee 上手く表示されています。

これをログイン以外のページも、block, endblockの中に流し込んでいきます。

{% extends 'sales/layout.html' %}
{% load static %}

{% block title %}{% endblock %}

{% block description %}{% endblock %}

{% block header_script %}
{% endblock %}

	
{% block content %}
{% endblock %}

{% block script %}
{% endblock %}

なかなか面白い。

[Django3.0]urls.pyとviews.py

フロントに沿って、urls.py、views.py、*.htmlを作ってきます。
editはパラメータの書き方が異なるので、モデルを作った後に作ります。

/sales/urls.py

urlpatterns = [
	path('login/', views.login, name='login'),
	path('', views.index, name='index'),
	path('client/', views.client, name='client'),
	path('client/input', views.client_input, name='client_input'),
	path('client/detail', views.client_detail, name='client_detail'),
	path('master/edit', views.master, name='master'),
	path('estimate/', views.estimate, name='estimate'),
	path('estimate/input', views.estimate_input, name='estimate_input'),
	path('order/', views.order, name='order'),
	path('order/input', views.order_input, name='order_input'),
	path('stock', views.stock, name='stock'),
	path('stock/input', views.stock_input, name='stock_input'),
]

/sales/views.py

from django.shortcuts import render
from django.http import HttpResponse

def login(request):
	return render(request, 'sales/login.html')

def index(request):
	return render(request, 'sales/index.html')

def client(request):
	return render(request, 'sales/client.html')

def client_input(request):
	return render(request, 'sales/client_input.html')

def client_detail(request):
	return render(request, 'sales/client_detail.html')

def master(request):
	return render(request, 'sales/master.html')

def estimate(request):
	return render(request, 'sales/estimate.html')

def estimate_input(request):
	return render(request, 'sales/estimate_input.html')

def order(request):
	return render(request, 'sales/order.html')

def order_input(request):
	return render(request, 'sales/order_input.html')

def stock(request):
	return render(request, 'sales/stock.html')

def stock_input(request):
	return render(request, 'sales/stock_input.html')

ヘッダとログインページ以外のナビゲーションは共通なので、続いて、共通箇所をインクルードにして一括管理したい。

[Django]templatesを一気に作る

### 画面遷移図

### URL一覧

まずtemplateのhtmlを流し込む前に、urls.pyとviews.pyの一覧を作ってからhtmlを流し込めば良いのか?
いや、urls.pyに記載してもviews.pyに記載がないとAttributeErrorになるので、urls.py -> views.py -> *.html をループさせた方が作業効率は良さそうである。

/sales/urls.py

urlpatterns = [
	path('login/', views.login, name='login'),
	path('', views.index, name='index'),
]

/sales/views.py

def index(request):
	return render(request, 'sales/index.html')

/sales/templates/sales/index.html

// 省略

load staticを毎ページ修正するのは面倒ではある。

[Django]staticフォルダにstyle.cssを置こう

まずsales配下にstaticフォルダ、その配下にsalesフォルダ、更にその下にcssフォルダを作成します。

/sales/static/sales/css/style.css
// 省略 ※webpackでsassから作ったcssを置く

/templates/sales/login.html

{% load static %}
<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<title>ログイン | hanbai - メールアドレス、パスワードを入力してください</title>
	// 省略

	<link rel="stylesheet" href="{% static 'sales/css/styles.css' %}">
	<script src="/js/main.js"></script>
</head>
// 省略

imgフォルダも作ります。

<img id="profile-img" class="profile-img-card" src="{% static 'sales/img/avatar.png' %}">

Wow!! なるほど、Djangoオモロイ!
取り敢えずこれはモデルの前に先に全部のurlspatternとtemplate嵌め込みをやれば良いのかな。順番がよくわからないが、フロント部分から手を付けた方が効率的そう。

djangoでテンプレートにはめ込もう

/hanbai/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'sales',
]

/sales/templates/sales/login.html

<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<title>ログイン | hanbai - メールアドレス、パスワードを入力してください</title>
	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
	<meta name="Description" content="見積管理、在庫管理、販売管理はhanbai">

	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

	<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>

	<link rel="stylesheet" href="css/style.css">
	<script src="/js/main.js"></script>
</head>
<body>
	<div class="wrapper">

		<nav class="navbar navbar-expand-md navbar-dark fixed-top" style="background-color:#1e90ff">
			<a class="navbar-brand disabled" href="">Hanbai</a>
		</nav>

		<div class="container">
			<div class="login">
				<div class="row">
					<div class="card card-container">
						<h1 class="text-center login-title">Hanbai</h1>
						<img id="profile-img" class="profile-img-card" src="/img/avatar.png">
						<div class="account-wall">
							<form class="form-signin">
								<input type="email" id="inputEmail" class="form-control" placeholder="Email" required autofocus>
								<input type="password" id="inputPassword" class="form-control" placeholder="Password" required>
								<button class="btn btn-lg btn-primary btn-block btn-signin" type="submit">
								ログイン</button>
								・ログインパスワードをお忘れの方は
								<a href="#">こちら</a><span class="clearfix"></span>
								・アカウントをお持ちでない方は
								<a href="#">こちら</a><span class="clearfix"></span>
							</form>
						</div>
					</div>
				</div>
			</div>
		</div>
		<footer>
			<p>&copy; Hanbai All Right Reserved.</p>
		</footer>
	</div>
</body>
</html>

/sales/urls.py

from django.urls import path
from . import views

urlpatterns = [
	path('/login', views.login, name='login'),
]

/sales/views.py

from django.shortcuts import render
from django.http import HttpResponse

def login(request):
	return render(request, 'sales/login.html')

cssと画像が効いていませんが、基本型はできました。

djangoでappを始めよう

$ python -V
Python 3.8.0
$ django-admin startproject hanbai
$ python manage.py runserver 192.168.33.10:8000

### アプリケーションの作成
$ python manage.py startapp sales
$ git init

/sales/views.py

from django.shortcuts import render
from django.http import HttpResponse

def index(request):
	return HttpResponse("Hello Django!")

/hanbai/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('sales.urls')),
]

/sales/urls.py

from django.urls import path
from . import views

urlpatterns = [
	path('', views.index, name='index'),
]

urlパターンはpath(‘/’)とするとエラーになるので、path(”)とする必要があります。
これからfrontで作成したviewを組み込んで行きます。

[Django]フォームの送信

### index.html
/hello/templates/hello/index.html

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>{{title}}</title>
	<link rel="stylesheet" type="text/css" href="{% static 'hello/css/styles.css' %}">
</head>
<body>
	<h1>{{title}}</h1>
	<p>{{msg}}</p>
	<form action="{% url 'form' %}" method="post">
		{% csrf_token %}
		<label for="msg">message: </label>
		<input id="msg" type="text" name="msg">
		<input type="submit" value="click">
	</form>
</body>
</html>

– urls.pyにnameの’form’を追加する
– {% csrf_token %}はCSRF対策

### views.py
/hello/views.py

def index(request):
	params = {
		'title':'Hello/Index',
		'msg':'what is your name?',
		'goto':'next',
	}
	return render(request, 'hello/index.html', params)

def form(request):
	msg = request.POST['msg']
	params = {
		'title':'Hello/Form',
		'msg':'hello ' + msg + '!',
	}
	return render(request, 'hello/index.html', params)

### urls.py
/hello/urls.py

urlpatterns = [ 
	path('', views.index, name='index'),
	path('form', views.form, name='form'),
]

### Bootstrap
– bootstrapを使ったデザイン

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>{{title}}</title>
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" crossoorigin="anonymous">
</head>
<body class="container">
	<h1 class="display-4 text-primary">{{title}}</h1>
	<p class="h5 mt-4">{{msg}}</p>
	<form action="{% url 'form' %}" method="post">
		{% csrf_token %}
		<div class="form-group">
			<label for="msg">message: </label>
			<input id="msg" type="text" class="form-control" name="msg">
		</div>
		<input class="btn btn-primary" type="submit" value="click">
	</form>
</body>
</html>

ほう

[Django]静的ファイルの利用

### staticフォルダ
– 静的ファイルは各アプリケーションのstaticフォルダに配置する
– ここではstatic, hello, cssフォルダ配下にcssファイルを作成する

/hello/static/hello/css/styles.css

body {
	color: gray;
	font-size: 16pt;
}
h1 {
	color: red;
	opacity: 0.2;
	font-size: 60pt;
	margin-top: -20px;
	margin-bottom: 0px;
	text-align: right;
}
p {
	margin: 10px;
}
a {
	color: blue;
	text-decoration: none;
}

### index.html
/hello/templates/hello/index.html

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>{{title}}</title>
	<link rel="stylesheet" type="text/css" href="{% static 'hello/css/styles.css' %}">
</head>
<body>
	<h1>{{title}}</h1>
	<p>{{msg}}</p>
	<p><a href="{% url goto %}">{{goto}}</a></p>
</body>
</html>

– 静的ファイルをロードする際にはテンプレートファイルで{% load static %}と書く
– staticファイルの読み込みは{% static ‘hello/css/styles.css’ %}と書く

なんじゃこりゃ

[Django]複数ページの移動

### テンプレート側
/hello/templates/hello/index.html

<body>
	<h1>{{title}}</h1>
	<p>{{msg}}</p>
	<p><a href="{% url goto %}">{{goto}}</a></p>
</body>
</html>

– {% %}はテンプレートタグ
– {% url ${name} %}で、urls.pyで指定しているnameのパスに遷移する

### views.py
/hello/views.py

def index(request):
	params = {
		'title':'Hello/Index',
		'msg':'this is sample page.',
		'goto':'next',
	}
	return render(request, 'hello/index.html', params)

def next(request):
	params = {
		'title':'Hello/Index',
		'msg':'this is another page.',
		'goto':'index',
	}
	return render(request, 'hello/index.html', params)

### urls.py
/hello/urls.py

urlpatterns = [ 
	path('', views.index, name='index'),
	path('next', views.next, name='next'),
]

http://192.168.33.10:8000/hello/

http://192.168.33.10:8000/hello/next

{% %}のテンプレートタグがやや特殊な動きをします。