Warning: count(): Parameter must be an array or an object that implements Countable in /home/xs638785/agile-software.site/public_html/wp-content/plugins/rich-table-of-content/functions.php on line 490
2カラムレイアウト
2つのカラムを使って構成されたレイアウトが2カラムのレイアウトです。
広い幅のカラムにメインコンテンツを置き、狭い幅のカラムにナビゲーションメニューなどを置きます。
フリーレイアウト
マルチカラムレイアウト
モザイクレイアウト
タイル型レイアウト
requirements.txt作成
Django~=3.1.4
django-widget-tweaks~=1.4.8
django-allauth~=0.41.0
仮想環境にパッケージをインストール
(myvenv) ~$ pip3 install -r requirements.txt
1.プロジェクト作成
mysiteという名前でプロジェクトを作成します。
(myvenv) ~$ django-admin startproject mysite .
各ファイルについては下記記事を参考にしてください。
https://www.agile-software.site/2021/04/04/django/2.アプリの作成
Djangoプロジェクトの中に用意されている「manage.py」というプログラムを使ってアプリを作成します。
アプリ名は好きな名前で大丈夫です。
今回はappという名前にします。
(myvenv) ~$ python3 manage.py startapp app
上記のコマンドを実行した結果以下のファイルが作成されました。
├── app // アプリケーションディレクトリ
│ ├── 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 // インストールファイル
アプリを作成した後はプロジェクトに対して作成したアプリを認識させなければいけません。
そのためプロジェクトのsetting.pyを変更します。
INSTALLED_APPSの中にはほかにたくさんのアプリが書かれていますがこれはユーザーの情報を整理するうえで使われるアプリをDjangoがデフォルトで準備してくれています。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'widget_tweaks', # 追加
'app', # 追加
]
テンプレートでホームをレンダリングするときにCSSクラスや属性を変更できるモジュール。
レンダリング
ある情報を形を変えて表現すること。
Djangoでは、多くの情報を整理してhtmlファイルに上手に表現する仕組みが備わっている。
3.settings.pyの設定変更
ALLOWED_HOSTS = ['*']
LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'
INSTALLED_APPSにwidget_tweaksとappを追加します。
INSTALLED_APPSとはプロジェクトに組み込まれている各種のアプリケーションを登録するものです。
なぜ登録するのかというとDjangoのテンプレート機能がapp内のtemplatesを検索できるようにするためです。もし、登録していないとDjangoのテンプレート機能がapp内にあるtemplateフォルダを検索してくれません。
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'widget_tweaks', # 追加
'app', # 追加
]
4.モデル
https://www.agile-software.site/2021/04/17/%e3%83%a2%e3%83%87%e3%83%ab/インポート
settings、timezone、modelsをインポートします。
クラス
今回ブログに使う情報として筆者、タイトル、本文、作成日とします。
クラスの名前をPostとして6行目以下に具体的に入れていくデータを定義しています。
models.Modelはmodelsモジュールの中のModelクラスを継承させるために書きます。
ForeignKeyはほかのモデルと連携することができます。ここではログインユーザーになります。
CASCADEとすることで一緒に削除されるようにしています。
最後の2行はオブジェクトをタイトルで表現するために書いています。
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)
content = models.TextField("本文")
created = models.DateTimeField("作成日", default=timezone.now)
def __str__(self):
return self.title
マイグレーション
model.pyファイルを変更したらデータベースに変更内容を反映させる必要があります。
それをmakemigrationsとmigrateと呼びます。
makemigrationはmodels.pyファイルの記載内容に基づいてデータベースの設計図のようなファイルを作成します。
こうすることでデータベースにmigrateする前に設計図を作成することでエラーなどがあった場合に反映する前に教えてくれます。
migrateはmakemigrationsコマンドによって作成されたファイルの内容に基づいてデータベースに変更を反映させるコマンドです。
(myvenv) ~$ python3 manage.py makemigrations
(myvenv) ~$ python3 manage.py migrate
管理画面
管理画面でデータの作成、編集、削除を操作できるようにしていきます。
admin.pyファイルに以下のコードを書くことによって管理画面にmodel.pyで作成したPostモデルを認識させることができるようになります。
register関数を使ってモデルを追加します。
from django.contrib import admin
from .models import Post
admin.site.register(Post)
管理ユーザーの作成
管理画面に入るためにはユーザー名とパスワードを入れてログインをしなければいけません。
そのためのユーザーを作成します。
(myvenv) ~$ python3 manage.py createsuperuser
createsuperuserコマンドを実行するとユーザー名とメールアドレス,パスワードの入力が求められます。
管理画面の表示
サーバーを立ち上げます。
DjangoはWebサーバーの機能を持っています。
試験用のWebサーバーを起動し、そこでDjangoプロジェクトのWebアプリケーションを動かせるようになっています。
(myvenv) ~$ python3 manage.py runserver
http://127.0.0.1:8000/adminにアクセスして管理画面を表示させましょう。
先ほど作成したsuperuserのユーザー名とパスワードを入力してログインします。
urls.pyファイルの設定
urls.pyファイルは上から順番にURLの照合が行われていくため127.0.0.1:8000/adminというURLがrequestされた場合にはadmin.site.urlsが呼び出され、それ以外のURLがrequestされた場合はappのurls.pyが呼び出されることになります。
そのアドレスにアクセスしたら指定の処理を実行するようにすることができます。
path(アクセスするアドレス、呼び出す処理)
include関数は引数に指定したモジュールを読み込むものです。
appフォルダ内のurls.pyが読み込まれ’127.0.0.1.8000/’のアドレスに割り当てられるようになります。
path(' ', include('app.urls')),
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path(' ', include('app.urls')),
]
アプリを作成した時にurls.pyファイルは作成されていないのでファイルを作成しましょう。
トップページにアクセスがあった場合、viewのIndexViewにアクセスするようにする。
from django.urls import path
from app import views
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
]
views.pyファイルの中でIndexViewとして定義されたviewを呼び出すようにしています。
as_viewはDjangoが用意した関数を継承するときに必須です。
第三引数のname=’index’とすることで、このpathに名前をつけることができます。
ルーティングに名前をつけることで、名前からURLを逆引きすることができるようになります。
例えば127.0.0.1.8000/hellowworldapp/appというURLがrequestされた場合、上は127.0.0.1.8000/hellowworldapp/appとURLが認識されてブラウザに表示されますが、下は127.0.0.1.8000/hellowworldapp/hellowworldapp/appとなってしまうためエラーとなります。
#プロジェクトのurls.py
urlpatterns = [
path('helloworldapp/', include('helloworldapp.urls')),
]
#アプリのurls.py
urlpatterns = [
path('app/', include('helloworldapp.urls')),
]
#プロジェクトのurls.py
urlpatterns = [
path('helloworldapp/', include('helloworldapp.urls')),
]
#アプリのurls.py
urlpatterns = [
path('helloworldapp/app/', include('helloworldapp.urls')),
]
ビュー
ビューはアプリケーションの司令塔となり、フォーム、モデル、テンプレートとやりとりをします。
ここではViewを継承しています。
モデルはPostを使用します。
View
from django.views.generic import View
from django.shortcuts import render
from .models import Post
class IndexView(View):
def get(self, request, *args, **kwargs):
post_data = Post.objects.order_by("-id")
return render(request, 'app/index.html', {
'post_data': post_data,
})
import文
django.shortcutsというところに用意されているrenderという関数を使えるようにするための記述です。
from django.shortcuts import render
get関数はviewがコールされたら最初に呼び出される関数
def get(self, request, *args, **kwargs):
Postモデルを呼び出し、降順に並び変えています。
post_data = Post.objects.order_by("-id")
変数の指定
post_dataという変数にpost_dataを代入しています。
return render(request, 'app/index.html', {
'post_data': post_data,
})
form
フォーム画面で入力された値をフォームオブジェクトに変換、保持します。
formsをインポートします。
widgetで複数行入力できるようにします。
from django import forms
class PostForm(forms.Form):
title = forms.CharField(max_length=30, label='タイトル')
content = forms.CharField(label='内容', widget=forms.Textarea())
テンプレート
Djangoの利点は表示するHTMLの内容をいろいろ操作することができることです。
appフォルダの下にtemplatesディレクトリ、appディレクトリを作成。
appディレクトリの中にbase.htmlファイルを作成します。
base.htmlにはヘッダーやフッター、ナビゲーションなどどのhtmlファイルにも同じように記載する必要があるものが記載されています。個別のhtmlファイルを修正するより一つにまとまっている方が修正が簡単です。
ブラウザのレイアウトはBootstrapを使って見た目を整えます。
base.htmlで全体の枠組みを作り、{%block content%}などの個別情報を入れています。
ユーザーのログイン状態を判定する
{% if user.is_authenticated %}
CSSの適用
<link rel="stylesheet" href="{% static 'css/style.css' %}">
BASE.html
静的ファイルのロード
テンプレートファイルで静的ファイルを利用する場合、以下のテンプレートタグを実行する必要があります。
{% load static %}
そして<head>タグ内にスタイルシートの読み込みの記述をします。
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<div class="card-footer text-muted">
{{ post.created|date }} by {{ post.author }}
</div>
画像・詳細・著者をクリックした場合記事に飛ぶようにリンクを設定しています。
<a class="stretched-link" href="{% url 'post_detail' post.id %}"></a>
{% url 名前 %}
{%%}はテンプレートタグと呼ばれるものでurlというテンプレートタグを使っています。
こうすることでurlspatternsで指定した名前のURLが書きだされます。
Bootstrapを使う
誰でも簡単にデザインページを作ることができます。
HTMLに<link>タグを1つ追加するだけです。
フッター
©は「©」と表示させる記述です。
{% load static %}
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<title>ブログチュートリアル</title>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="/">ブログ</a>
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="/">ホーム</a>
</li>
{% if user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="">投稿</a>
</li>
<li class="nav-item">
<a class="nav-link" href="">ログアウト</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="">サインアップ</a>
</li>
<li class="nav-item">
<a class="nav-link" href="">ログイン</a>
</li>
{% endif %}
</ul>
</div>
</nav>
<main>
<div class="container">
{% block content %}
{% endblock %}
</div>
</main>
<footer class="py-2 bg-dark">
<p class="m-0 text-center text-white">Copyright © Django Startup 2020</p>
</footer>
{% block extra_js %}
{% endblock %}
</body>
</html>
index.html
動的に変わるエリアのファイルを作成します。
1行目の{% extends “app/base.html” %}はbase.htmlに記載されている内容をベースに広げていくというイメージです。
base.htmlとindex.htmlの連携
{% extends "app/base.html" %}
viewから渡されたデータの取得
{% for post in post_data %}
{% for post in post_data %}
{{変数名}}という形で変数をテンプレート内に埋め込むことができます。
{% extends "app/base.html" %}
{% block content %}
<div class="row my-4">
<div class="col-md-8">
{% for post in post_data %}
<div class="card mb-4">
<div class="card-body">
<h2 class="card-title">{{ post.title }}</h2>
<p class="card-text">{{ post.content|truncatechars:100 }}</p>
<div class="btn btn-warning">詳細</div>
</div>
<div class="card-footer text-muted">
{{ post.created|date }} by {{ post.author }}
</div>
<a class="stretched-link" href=""></a>
</div>
{% endfor %}
</div>
<div class="col-md-4">
<div class="card">
<h5 class="card-header">このチュートリアルについて</h5>
<div class="card-body">
<p>ステップ1</p>
<p class="mb-0">
初めてDjangoを触る方向けのチュートリアルです。
最小限の機能を構築してDjangoを学習しましょう。
</p>
</div>
</div>
</div>
</div>
{% endblock %}
post_form.html
csrf対策について
外部からサイトへのフォーム送信などを行う攻撃に対して正しくフォームから送信されたアクセスかどうかをチェックする仕組みが必要になります。
それを行っているのが下記のテンプレートタグになります。
{% csrf_token %}
{% extends "app/base.html" %}
{% load widget_tweaks %}
{% block content %}
<div class="my-4">
<h2>投稿</h2>
</div>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="formpost">
{% render_field form.title class="form-control" placeholder="タイトルを入力" %}
</div>
<div class="formpost">
{% render_field form.category class="form-control" placeholder="カテゴリを入力" %}
</div>
<div class="formpost">
{{ form.image }}
</div>
<div class="formpost">
{% render_field form.content class="form-control" placeholder="本文を入力" %}
</div>
<button class="btn btn-warning" type="submit">投稿する</button>
</form>
{% endblock %}
CSS
スタイルシートを記述する際にはstaticフォルダを作成します。
staticフォルダ内には静的ファイルを入れていきます。
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #F1F1F1;
display: flex;
flex-flow: column;
min-height: 100vh;
}
main {
flex: 1;
}
各カテゴリーの下にアンダーバーを設定
/* サイドバー */
.list-unstyled{
border-bottom: 2px #0bd solid;
}
ボックスに影を付ける
box-shadow
box-shadow: none;
/* offset-x | offset-y | blur-radius | spread-radius | color */
box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2);
body
body {
background: #F1F1F1;
display: flex;
flex-flow: column;
min-height: 100vh;
}
背景色は白色
横並び
flex-flow:column;とすることでflex-directionをcolumn。つまり縦方向にアイテムを並べることができます。
min-height:で
main
main {
flex: 1;
}