Agile育成ブログ
未来を変える喜びを
Django

Django(ブログアプリケーション設定)


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カラムのレイアウトです。
広い幅のカラムにメインコンテンツを置き、狭い幅のカラムにナビゲーションメニューなどを置きます。

フリーレイアウト

マルチカラムレイアウト

モザイクレイアウト

タイル型レイアウト

https://sankoudesign.com/category/2column/

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ファイルに上手に表現する仕組みが備わっている。

https://www.agile-software.site/2021/04/24/django-render%e3%83%a1%e3%82%bd%e3%83%83%e3%83%89/

3.settings.pyの設定変更

ALLOWED_HOSTS = ['*']

LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'
https://www.agile-software.site/2021/04/24/django-mysite-setting-py/

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
https://www.agile-software.site/2021/04/17/django%e3%83%95%e3%82%a3%e3%83%bc%e3%83%ab%e3%83%89/

マイグレーション

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が呼び出されることになります。

urlpatterns

そのアドレスにアクセスしたら指定の処理を実行するようにすることができます。

path(アクセスするアドレス、呼び出す処理)
include

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を逆引きすることができるようになります。

ここで注意していただきたいのがプロジェクトのurls.pyファイルに書かれたURL以下の部分がアプリのurls.pyファイルのurlpatternsに書かれるということです。

例えば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,
        })
https://www.agile-software.site/2021/04/17/django_view/ https://www.agile-software.site/2021/04/24/django-render%e3%83%a1%e3%82%bd%e3%83%83%e3%83%89/

form

フォーム画面で入力された値をフォームオブジェクトに変換、保持します。
formsをインポートします。

https://www.agile-software.site/2021/06/26/django-widget/ https://www.agile-software.site/2021/04/24/django-form/

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つ追加するだけです。

https://www.agile-software.site/2021/04/08/bootstrap/

フッター

&copy;は「©」と表示させる記述です。

{% 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
body {
    background: #F1F1F1;
    display: flex;
    flex-flow: column;
    min-height: 100vh;
}

背景色は白色
横並び
flex-flow:column;とすることでflex-directionをcolumn。つまり縦方向にアイテムを並べることができます。
min-height:で

main

main
main {
    flex: 1;
}

main

You cannot copy content of this page