Django, 多対多関係モデルを用いて簡易アプリケーションを作る

#はじめに
最近個人的にアプリケーション開発していて一つ詰まった箇所として、**models.py**で作成したモデルを**templates**に表示させることがありました。多対多のリレーショナルデータベースのモデルの作成に関する解説は多く見かけ参考にさせていただきましたが、それを**htmlファイル**に表示する方法に関する情報がどうしても**Django初心者**の自分には分かりにくく、理解に時間がかかりました。今回はDjangoの初心者の方でも分かりやすく、**一つの簡易アプリケーション**を開発しながら**多対多関係モデル**の作成、表示方法について解説していきたいと思います。

##今回作成する簡易アプリについて
今回のテーマとして**多対多関係モデル**を扱いますので、まずはモデルを作る前にどのような**アプリ**を作るか書いていきます。分かりやすい例としてパッと出てきたものが**動物園**（上野動物園、旭川動物園など）のリンクを押すと**その動物園にいる動物**（象、キリン、アルパカなど）を表示してくれるアプリケーションだったので、簡易的なものになりますが、そのような**アプリ**を作っていきたいと思います。

##多対多関係モデルとは
Djangoにおける**多対多関係モデル**とはリレーショナルデータベースにおいて多対多の**リレーション（関係）**をもつ**モデル**のことです。もう少し噛み砕いて説明するため、今回作成するアプリケーションを例にして説明します。
下の図のように動物園は様々な種類の動物を管理しています。図を用いて説明すると一つの動物園は同時に何種類の動物と**繋がっています**。また動物に関しても同じことが言え、例えば象を見てみると**動物園A**と**動物園B**にいます。このように、お互い（今回の場合だと**動物園**、**動物**）が一つのオブジェクトではなく複数のオブジェクトに存在している場合、モデル同士が**多対多の関係にある**と言えます。
![スクリーンショット 2019-10-30 13.31.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513383/097d2200-5124-a9b6-cdca-a2279c74cf57.png)



(補足情報)
**Django**は**データベース**として**リレーショナルデータベース**を採用しています。**リレーショナルデータベース**とは**自身とは異なるテーブルのカラム**を参照して、**自身のテーブルのカラム**として関連付けができるデータベースです。

##モデルを作成する前に
**DBモデル**を作成する前にアプリケーションとして最低限の機能を果たせるよう、**settings.py**の設定、**urlの繋ぎこみ**と**views**の記述を軽くやっておきたいと思います。

```python:settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app_name', #startappでつけたアプリ名を入れる
]
```
urls.pyも今回は要らないが**projectのurl** --> **appのurl** --> **htmlファイル**の形を作る。

```python:project_name/urls.py
from django.urls import include

urlpatterns = [
    path('', include('app_name.urls')),
]
```
```python:app_name/urls.py
from django.urls import path
from .views import displayfunc

urlpatterns = [
    path('', displayfunc),
]
```
urls.pyの繋ぎこみを確かめるために**views**も記述しておきます。

```python:views.py
from django.shortcuts import render

def displayfunc(request):
    return render(request, 'home.html')
```
templatesフォルダを作成しhome.htmlをその下に作り、適当な単語（自分はDisplayと入れときました）を入れ、runserverしてみましょう。
![スクリーンショット 2019-10-31 10.20.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513383/99805aed-7ad0-9c53-8fc1-280c5eb75fbf.png)
このように表示されれば、繋ぎこみが成功と分かりますね！では早速モデルを作っていきましょう！

##モデルの作成、データの入力
多対多関係モデルをDjangoにおいて作るには**ManyToManyField**を使います。使い方としては参照したいモデルを**ManyToManyFields**に渡してあげることで参照したカラムを作ることができます。下のコードを見ると分かりやすいかと思います。

```python:models.py
from django.db import models

class Animal(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Zoo(models.Model):
    name = models.CharField(max_length=100)
    keeping = models.ManyToManyField(Animal) #Animalを渡す

    def __str__(self):
        return self.name
```
これでモデルは完成しましたので次はこのモデルにデータを入れていきたいと思います。いきなり**adminページ**でデータを入力するのではなく**Django shell**でテストしてから**adminページ**に行く形が一般的なので今回もそのようにしていきます。以下のコードでDjangoから**shellコマンド**が打てるようになります。

`$ python manage.py shell`

まずは**models.py**のモデルをターミナル上で扱うために**インポート**していきます。
次に二つのモデルにデータを追加していきます。

`>>> from app_name.models import *`
`>>> a1 = Animal.objects.create(name="elephant")`
`>>> z1 = Zoo.objects.create(name="Ueno Zoo")`

次に二つのモデルの関連付けを行います。

`>>> a1 = Animal.objects.get(name="elephant")`
`>>> z1 = Zoo.objects.get(name="Ueno Zoo")`
`>>> z1.keeping.add(a1)`

関連付けが上手くいっているか確認。上手く表示されれば成功です！

`>>> z1.keeping.all()`

##htmlファイルにデータを表示する
それでは**models.py**のデータを表示させていきましょう。ここのパートはコードを載せた方が分かりやすいかと思うので載せていきます。まずは**views**を書き換えます。

```python:views.py
from .models import Zoo

def displayfunc(request):
    object = Zoo.objects.all()
    return render(request, 'home.html', {'object': object})

def detailfunc(request, pk):
    zoo = Zoo.objects.get(pk=pk)
    return render(request, 'detail.html', {'zoo': zoo})
```
続いて**urls**で繋ぎこみをしていきます。あとで使うのでnameも設定。

```python:urls.py
    path('detail/<int:pk>', detailfunc, name="detail") #追加する
```

最後にhtmlファイルです。

```html:home.html
<body>
    {% for zoo in object %}
        <p><a href="{% url 'detail' zoo.pk %}">{{ zoo.name }}</a></p>
    {% endfor %}
</body>
```

```html:detail.html
<body>
    {% for animal in zoo.keeping.all %}
        <p>{{ animal }}</p>
    {% endfor %}
</body>

```
これで完成です！runserverして確認してみましょう。
![スクリーンショット 2019-10-31 10.07.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513383/0cdfbd6e-7ecd-df4b-a66e-746dbf9e1f76.png)
例えば動物園 'Ueno Zoo'をクリックすると
![スクリーンショット 2019-10-31 10.09.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513383/987138bd-d1ae-b73a-2a06-1e457b7f7092.png)
このように**動物園にいる動物**が（装飾もなしで非常にお粗末なWebページですが）動きます。今回のテーマとしては多対多関係モデルを扱うことですので、これ以上のデータの追加やCSSなどの装飾はしません。とりあえずはアプリは完成です！

##最後に
読んでくださった方はありがとうございます！
もし何かしらのミス、誤りがあれば連絡お願いいたします。