第１回：Djangoで2つアプリケーションを利用してみる！！

## はじめに
　こんにちは。@toamoku-20220418と申します。現在Djangoを使用したアプリケーションの作成を目標に、勉強を進めております。
　そこで今回はDjangoのアプリケーションを2つ使用して、簡単なサンプルアプリを作成しました。どのようにルーティングをするかなど、大まかな流れを理解できるように気を付けながら進めていきました。長くなると思いますので、全２回で構成しています。
　ぜひ最後までご覧いただき、皆さんの参考になれば幸いです。

## 今回の目標

　アプリケーションを２つ作成し、Djangoの全体像とルーティング方法を理解する。テンプレートの配置方法なども工夫しながら実装して、保守性や再利用性があるソースコードを意識して実装する。
 
## 前提条件
　PCにはpythonがインストールされていることと、GitHubは使用しないことを前提にお話を進めてまいります。SECRET_KEYなどもそのままで進めてまいりますので、GitHubなどでPublicへ公開する予定の方は、私の下記の記事をご覧に頂けると参考になると思いますので、併せてご覧ください。また使用PCはmacです。ご了承ください。

https://qiita.com/toamoku-20220418/items/9419ba85f56c119603ba


## プロジェクトディレクトリの作成

　最初に今回のアプリケーションを作成するプロジェクトディレクトリを作成しましょう。作成場所はどちらでも構いません。
 
 ```bash
 $ mkdir myproject
 ```
 
　続いてプロジェクトディレクトリへ移動し、仮想環境を有効化します。私はvirtualenvを使用しておりますので、それでお話を進めてまいります。
 
 ```bash
 $ cd myproject
 $ virtualenv 仮想環境名(ここではmyprojectenvとします)
 ```
 
　仮想環境を有効化します。
 
 ```bash
 $ source myprojectenv/bin/activate
 ```
 
 これで下記の通り表記されると、仮想環境が起動しています。表記のされ方は環境により若干違うと思いますが、一番右に今いるディレクトリが表示されます。
 
 ```bash
 (myprojectenv) ~/myproject %
 ```
 
 ## Djangoのインストール
　仮想環境を起動してから、pipでDjangoをインストールします。
 
 ```bash
 $ pip install django
 ```
 
 ## Djangoプロジェクトとアプリケーションを作成
　Djangoプロジェクトとアプリケーションを２つ作成します。
 
 ```bash
 $ django-admin startproject myproject .
 ```
 
　続いて２つのアプリケーションを作成します。
 
 ```bash
 $ python manage.py startapp app1
 $ python manage.py startapp app2
 ```
 
 settings.pyのINSTALLED_APPSに追加
 ```python:settings.py
 INSTALLED_APPS = [
    ...
    'app1',
    'app2',
]
```

## ホーム画面の作成
　簡単なホーム画面を作成します。最初にmyprojectディレクトリにtemplatesディレクトリを作成します。
 
```bash
$ mkdir templates
```

　続いてtemplatesディレクトリにhome.htmlとbase.htmlを作成します。
 base.htmlは他のHTMLファイルでも繰り返し使用するために作成し、継承することができます。
 
```html:base.html
<!-- templates/base.html -->

<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}My Site{% endblock %}</title>
</head>
<body>
    <header>
        <h1><a href="#">Authors</a> | <a href="#">Books</a></h1>
    </header>
    <hr>
    <main>
        {% block content %}
        {% endblock %}
    </main>
    <hr>
    <footer>
        <p>&copy; 2024 My Site</p>
    </footer>
</body>
</html>
```

```html
<!-- 繰り返し使用する部分は下記 -->
<title>{% block title %}My Site{% endblock %}</title>
<main>
    {% block content %}
    {% endblock %}
</main>
```

```html:home.html
<!-- templates/home.html -->
<!-- base.htmlを継承する -->
{% extends "base.html" %}

{% block title %}Home{% endblock %}

{% block content %}
  <h1>ようこそ！My Siteへ</h1>
  <p>このサイトは練習サイトです。ご了承ください。</p>
{% endblock %}
```

## myprojectディレクトリにviews.pyファイルを作成する。

```bash
$ touch views.py
```

　続いてviews.pyを編集する。
 
 ```python:views.py
 # myproject/views.py

from django.shortcuts import render
# リクエストを受け取り、home.htmlを返す
def home(request):
    return render(request, 'home.html')
```

　urls.pyを編集
 
 ```python:urls.py
 # myproject/urls.py

from django.contrib import admin
from django.urls import path
from . import views

urlpatterns = [
    path('admin/', admin.site.urls),
    # URLに何も付かない場合、views.pyのhomeメソッドへ遷移する
    path('', views.home, name='home'),  # ここを追加
]
```

## ここまでの作業を確認
　サーバーを起動して、ホーム画面が表示されるかを確認する。
 
```bash
$ python manage.py runserver
```

　マイグレーションをしていないので、警告などがターミナルに表示されると思いますが、
　続いて、PCのブラウザを用いてlocalhost:8000と入力してみます。そこで「ようこそ！My Siteへ」ページが表示されれば成功です。
 
## app1のモデルとフォームを作成
　次にapp1のmodels.pyとforms.pyを作成します。
 
 ```python:models.py
# app1/models.py
 
from django.db import models
# Authorモデルを作成
class Author(models.Model):
    name = models.CharField(max_length=100) # 文字数は最大100まで
    email = models.EmailField(unique=True) # メールアドレスは一意制約

    def __str__(self):
        return self.name
```

　続いてforms.pyを作成します。
 
 ```python:forms.py
# app1/forms.py

from django import forms
from .models import Author

class AuthorForm(forms.ModelForm):
    class Meta:
        model = Author
        fields = ['name', 'email']
```

## app1のviews.pyを作成
　リストと詳細、作成の３種類のみです。
ListView, DetailView, CreateViewを使用することにより、簡単にコードを作成できる。
modelは使用するモデルを指定し、template_nameは使用するテンプレートを指定します。

```python:views.py
# app1/views.py

from django.urls import reverse_lazy
from django.views.generic import ListView, DetailView, CreateView
from .models import Author
from .forms import AuthorForm

class AuthorListView(ListView):
    model = Author
    template_name = 'app1/author_list.html'

class AuthorDetailView(DetailView):
    model = Author
    template_name = 'app1/author_detail.html'

class AuthorCreateView(CreateView):
    model = Author
    form_class = AuthorForm
    template_name = 'app1/author_form.html'
    success_url = reverse_lazy('author-list')
```

## app1のルーティング
　app1のルーティングを作成します。最初にmyprojectのurls.pyを編集します。
 
```python:urls.py
# myproject/urls.py

from django.contrib import admin
from django.urls import path
from . import views

urlpatterns = [
    path('admin/', admin.site.urls),
    # app1から始まるURLはapp1にあるurls.pyを参照する
    path('app1/', include('app1.urls')),　# ここを追加
    path('', views.home, name='home'),
]
```

　続いてapp1のurls.pyファイルを作成し編集します。
 
```python:urls.py
# app1/urls.py

from django.urls import path
from . import views

urlpatterns = [
    # リスト画面を表示するAuthorListViewを参照
    path('authors/', views.AuthorListView.as_view(), name='author-list'),
    # 詳細画面を表示するAuthorDetailViewを参照
    path('authors/<int:pk>/', views.AuthorDetailView.as_view(), name='author-detail'),
    # 作成画面を表示するAuthorCreateViewを参照
    path('authors/new/', views.AuthorCreateView.as_view(), name='author-create'),
]
```

## app1のHTMLファイルを作成

　最初にリストを表示するauthor_list.htmlを作成します。
 DjangoのHTMLで記述しておりますので、その点はご了承ください。
 
```html:author_list.html
<!-- templates/app1/author_list.html -->

{% extends "base.html" %}

{% block content %}
    <h1>Authors</h1>
    <ul>
        <!-- for文を使用し、Authorモデルオブジェクトから１件ずつデータを取り出す -->
        {% for author in object_list %}
        <li><a href="{% url 'author-detail' author.pk %}">{{ author.name }}</a></li>
        {% endfor %}
    </ul>
    <!-- authorを新規登録するAuthorCreateViewへ遷移 -->
    <a href="{% url 'author-create' %}">作者新規登録</a>
{% endblock %}
```

　続いて詳細画面を表示するauthor_detail.htmlを作成します。
 
 ```html:author_detail.html
 <!-- templates/app1/author_detail.html -->

{% extends "base.html" %}

{% block content %}
  <h1>{{ object.name }}</h1>
  <p>Email: {{ object.email }}</p>
  <a href="{% url 'author-list' %}">作者リストへ戻る</a>
{% endblock %}
```

　最後に作成画面を表示するauthor_form.htmlを作成します。
 
```html:author_form.html
<!-- templates/app1/author_form.html -->

{% extends "base.html" %}

{% block content %}
<h1>作者新規登録</h1>
<form method="post">
    <!-- csrf攻撃への対策用トークンを付与 -->
    {% csrf_token %}
    <!-- フォームの項目をPタグで表示 -->
    {{ form.as_p }}
    <button type="submit">登録</button>
</form>
{% endblock %}
```

## Authorモデルのマイグレーション

　Authorモデルをマイグレーションし、データベースに反映します。
 
```bash
$ python manage.py makemigrations
$ python manage.py migrate
```

## app1のadmin.pyを編集

　admin.pyを編集します。
 
```python:admin.py
# app1/admin.py

from django.contrib import admin
from .models import Author

@admin.register(Author)
class AuthorAdmin(admin.ModelAdmin):
    list_display = ('name', 'email')
    search_fields = ('name', 'email')
```

## 管理者を作成
　管理者を作成します。
 
```bash
$ python manage.py createsuperuser
```

　いろいろ入力を求められますので、入力していってください。
 ローカル環境であれば、あまりこだわらずともオッケーだと思います。
 
## base.htmlを修正
　base.htmlを編集し、authorのリスト表示画面へ遷移するようにします。
 
```html:base.html
<header>
    <!-- ここのAuthor部分のaタグを修正 -->
    <h1><a href="{% url 'author-list' %}">Authors</a> | <a href="#">Books</a></h1>
</header>
```

## 動作確認

　ここまで作成したapp1の動作確認を行います。ブラウザに下記を入力してください。
1. localhost:8000でホーム画面を表示
2. Authorリンクからリスト画面へ遷移
3. リストの表示はないが、作者新規登録から作成画面へ遷移
4. 作成画面でauthorを作成するとリストに遷移
5. リストでauthorをクリックし、詳細画面へ

 ここまでうまくいったら、オッケーです。よかったら数人登録しましょう。
 
## いったんまとめ
　ここまでいかがでしたでしょうか。第１回はapp1の編集までを行いました。第２回はapp2を作成していきたいと思います。ぜひ第２回もご覧いただけると幸いです。
　それでは次は第２回でお会いできるのを楽しみにしております。

 https://qiita.com/toamoku-20220418/items/7b23bc48aee5c08be893