Djangoでapiを作ってみた

# はじめに
API作成を行ってみたいと思ったので、`DjangoRestFramework`を使って、とても簡単なapiを作成してみました。

>`API`とは
`Application Programing Interface`の略称で、ソフトウェアアプリケーションを連携させ、データや機能を共有させるためのインターフェイス（接続手段）をプログラムしたものです。

>`DjangoRestFramework`とは
>djangoで`Restful`なAPIを作成するためのライブラリです。

>`Restful`とは
`REST`と呼ばれるwebアプリケーションで持ちられる設計（アーキテクチャ）原則をのこと。`Restful`とは、RESTというアーキテクチャで実装したwebアプリケーション等のことを指す（らしい、形容詞として使われている）




## 開発環境
- IDE:pycharm
- python：3.9
- フレームワーク：django
- DB：sqlite(djangoのデフォルトであるsqliteにしました。）
- docker


最終的なディレクトリは下のようになりました。
```
.
├── ApiTest
│   ├── ApiTest
│   │   ├── __init__.py
│   │   ├── asgi.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   ├── db.sqlite3
│   ├── manage.py
│   └── storage
│       ├── __init__.py
│       ├── admin.py
│       ├── apps.py
│       ├── migrations
│       │   ├── 0001_initial.py
│       │   └── __init__.py
│       ├── models.py
│       ├── serializers.py
│       ├── tests.py
│       ├── urls.py
│       └── views.py
├── Dockerfile
├── docker-compose.yml
└── requirements.txt
```

:::note
今回は、まず仮想環境で開発をし、最後にdocker環境に移行してみました。
:::

## 開発環境の準備

仮装環境を作ります。
```
python3 -m venv venv
```

仮装環境に入ります。
```
source -m venv venv
```

仮装環境に入った状態で`django`をインストールします。
```
pip install django
```
次に`djangorestframework`をインストールします。
```
pip install djangorestframework
```

以下のコマンドでプロジェクトを立ち上げます。
```
django-admin startproject ApiTest
```
以下のコマンドでアプリを立ち上げます。
```
python manage.py startapp storage
```

### プロジェクトファイルの設定
クライアントからリクエストを受け取るサーバーを指定するために、プロジェクトディレクトリの`setting.py`を記述します。
```ApiTest/setting.py
ALLOWED_HOSTS = ['*']
```
同じファイルで、`djangorestframework`を使うために`rest_framework`を登録します。

```ApiTest/setting.py
INSTALLED_APPS = [
    'storage.apps.StorageConfig',#追加
    'rest_framework',#追加
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
```

同じファイルでの日本語設定、標準の時刻を日本語に設定します。
こうすることで管理画面が日本語になり、レコード登録した際のタイムログが日本の標準時間になります。
```ApiTest/setting.py
LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'
```

### アプリでの設定
`model.py`でモデルを作成します。今回は、Itemというモデルを作成しました。
```models.py
from django.db import models

class Item(models.Model):
    name = models.CharField(max_length=255)
    cost = models.IntegerField()
```

`admin.py`で管理者画面からレコードを操作できるようにします。
```admin.py
from django.contrib import admin
from .models import Item #追加

admin.site.register(Item)＃追加

```
下のコマンドでマイグレーションを行います。
```
python manage.py makemigrations storage
```
>マイグレーションとは、データベースに対して、変更を加えるための仕組みです。

マイグレーションをデータベースに適応します。（マイグレート）
```
python manage.py migrate
```
以下のコマンドでローカルサーバーを起動します。
```
python manage.py runserver
```

`http://localhost:8000`をブラウザで検索します。

![スクリーンショット 2024-05-26 23.32.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766230/879ec5a8-9a53-b887-7291-d43617265aa0.png)


## 管理画面でレコードを入れる

スーパーユーザーを作成して、レコードを作成、編集してみます。
```
python manage.py createsuperuser
```

`http://localhost:8000/admin`で管理者画面に入ります。


![スクリーンショット 2024-05-26 23.36.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766230/111f049d-ddd3-d67a-68f2-08401b957ec8.png)

`Items`のとこを選択して、以下のようにレコードを追加してみます。

![スクリーンショット 2024-05-26 23.39.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766230/f0116770-0662-03ed-f16c-fd5a122e8645.png)

![スクリーンショット 2024-05-26 23.39.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766230/b131ddb8-ffa0-f97e-3fdf-df810a0f6ae0.png)

登録はできましたが、レコードの判別が一覧でできないようになっていました。
![スクリーンショット 2024-05-26 23.40.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766230/bdc67df6-8a78-d372-9326-8dcf8774e760.png)

これは、レコードを判別するための名前を設定していないからでした。
なので、`models.py`で以下のコードを追加して、レコードを名前で判別できるにしました。

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

class Item(models.Model):
    name = models.CharField(max_length=255)
    cost = models.IntegerField()

    #追加
    def __str__(self):
        return self.name
```

![スクリーンショット 2024-05-26 23.42.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766230/0fc6fe70-846d-fed0-e82f-1a08538b94f9.png)

## API作成
ここからAPIを作成していこうと思います。
アプリケーションのディレクトリに、`serializer.py`を書きます
```serializer.py
from rest_framework import serializer
from .models import Item

class ItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = Item
        fields = '__all__'
```
>シリアライザーとは、データを適切な形に変換して、入出力を行うためのクラスです。pythonがデータを扱うための橋渡し的な存在になります。


ここから、ItemモデルのAPIエンドポイントを指定させるために`views.py`を指定します。
```views.py
from rest_framework import viewsets
from .models import Item
from .serializers import ItemSerializer

class ItemViewSet(viewsets.ModelViewSet):

    queryset = Item.objects.all()
    serializer_class = ItemSerializer

```
>`viewsets`モジュールは、モデルに対するCURD機能を一括で設定できます。
`queryset`は、モデルのデータ一覧のことです。
`serializer_class`の部分は、モデルのデータの受け渡しを適切な形にするために設定しています。


`urls.py`でルーティングを設定します。
```storage/urls.py
from django.urls import path,include
from rest_framework.routers import DefaultRouter
from .views import ItemViewSet

router = DefaultRouter()
router.register('Item',ItemViewSet)

urlpatterns = [
    path('api/',include(router.urls))
]
```

>ルーティングとは、http等のリクエストに対して、どのように処理をさせるか経路を指定することです。
`DefaultRouter`でapiに対するリクエストのルーティング設定が行えます。


プロジェクトディレクトリ側で、アプリのエンドポイントを指定します。
```Apitest/urls.py

from django.contrib import admin
from django.urls import path,include#includeを追加

urlpatterns = [
    path('admin/', admin.site.urls),
    path('storage/',include('storage.urls')),#追加
]
```

`http://localhost:8000/storage/`を検索して、が出てきたらapi作成は完了です!

![スクリーンショット 2024-05-26 23.55.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766230/40084793-ece0-ecef-73b7-ab0ea8ab0812.png)

`http://localhost:8000/storage/Item/`を指定することでモデルのデータ一覧を見ることができます。

![スクリーンショット 2024-05-27 0.10.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766230/b7a1123e-3122-e8aa-f3de-fceaa9cd0758.png)

## おまけ

### dockerに環境を移行

以下のコマンドで、`requiremets.txt`を生成

```
pip freeze > requirements.txt
```

```requirements.txt
asgiref==3.8.1
Django==4.2.13
djangorestframework==3.15.1
sqlparse==0.5.0
typing_extensions==4.12.0
```
次に`Dockerfile`を書きます。
```Dockerfile
FROM python:3.9

ENV PYTHONUNBUFFERED=1

ENV PYTHONDONTWRITEBYTECODE=1

WORKDIR /code/

COPY requirements.txt /code/

RUN pip install --no-cache-dir -r requirements.txt

COPY . /code/

#CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

```
>CMDの部分は、今回ymlファイルを使うためコメントアウトしました。

`docker-compose.yml`を記述します。
```docker-compose.yml
version: '3'

services:
  web:
    build: .
    volumes:
      - .:/code
    working_dir: /code/ApiTest/
    ports:
      - 8000:8000
    command: python manage.py runserver 0.0.0.0:8000
```

コンテナに含めたくないものを`.dockerignore`に記述します。
```.dockerignore
venv
__pycache__
*.pyc
*.pyo
*.pyd
*.sqlite3
*.log
```

以下のコマンドでイメージとコンテナを同時に作成します。
```
docker compose up --build
```

ここでvenvファイルを消しても大丈夫です。

>一応`deactivate`をコマンドで打ってディアクティベートしとくとスムーズに消せるかもしれません。

# 最後に
次はなんかしらのアプリケーションで連携させるようにしようと思います。