MENU

Django Ninjaチュートリアル③(CRUD処理)

Django-Ninjaチュートリアル③(CRUD処理)

前回までの記事はこちらです。

前回までの続きの記事になりますので、まだ追いついていない方は、こちらをご覧になった後に、読み進めてください。

また、この記事はDjango Ninjaの公式ドキュメントに基づいて作成しています。

詳細はこちらもご確認ください。

目次

CRUD処理について

今回は、前回まで見てきたDjango NinjaによるWebAPIのCRUD処理についてみていきます。

CRUDとは

CRUDとは、Create(作成)、Retrieve(取得)、Update(更新)、Delete(削除)といった4つの基本的なWebアプリケーションにおけるストレージ管理方法をいいます

Django NinjaでこれらのCRUD処理を実装するにはどうしたらよいか、これを今回は見ていきます。

Create(作成)

まずはCRUD処理のうち、Create(作成)処理について見ていきます。
ただし、いきなりCreate処理を書いていくと何に対してCRUD処理をするのかが分からないため、共通のSchemaを定義しておきます。

今回の例では、部署(Department)とそれに紐づく従業員(Employee)のSchemaに基づいて、CRUD処理をする前提で設定します。

models.pyの設定

まずは、Djangoの通常のモデルを作成しますので、以下のようにファイルを作成します。

from django.db import models

class Department(models.Model):
  title = models.CharField(max_length=100)
  
  def __str__(self):
    return self.title

class Employee(models.Model):
  first_name = models.CharField(max_length=100)
  last_name = models.CharField(max_length=100)
  department = models.ForeignKey(Department)
  birthdate = models.DateField(null=True, blank=True)

  def __str__(self):
    return f"{self.first_name} {self.last_name}"

このmodels.pyは通常のDjangoのモデル設定と同じです。

EmployeeのSchemaを定義する

次に、Employeeの登録に関するSchemaを定義します。

from email import message
from ninja import Schema
from datetime import date

class HelloSchema(Schema):
  name: str = "world"
  
class UserSchema(Schema):
  username: str
  is_authenticated: bool
  email: str = None
  first_name: str = None
  last_name: str = None

class ErrorSchema(Schema):
  message: str
  
  # add
class EmployeeIn(Schema):
  first_name: str
  last_name: str
  department_id: int = None
  birthdate: date = None

APIの設定

次に、APIの設定を行います。前回のapi_v1.pyに追記していきます(# add 6参照)。

from ninja import NinjaAPI

from django_app.models.api_v1_schema import HelloSchema, UserSchema, ErrorSchema, EmployeeIn
from .models import Employee

app = NinjaAPI(
  title = "Django Ninja Sample App",
  version = "1.0.0"
  ) # add

~略~

# add 6
@app.post("/employees")
def create_employee(request, payload: EmployeeIn):
  employee = Employee.objects.create(**payload.dict())
  return { "id": employee.id}

payloadとは…
データ送信の内容をひとまとめにしたものを指す(制御情報等は除く)

この設定により、

  1. emplyeeを作る際に必要な情報は、payloadとして渡されるが、その中身は先に設定したEmplyeeInSchemaを参照している
  2. Schemaは、入力内容を辞書型で各項目を受け取り、employeeインスタンスに入れられる
  3. 上記の例では、その中のemployee.idを返す

ということになります。

【ちなみに…】
上記の例で使用している**kwargsについては、EmployeeInが複数の項目を持つ辞書型であることから、「可変長引数」として渡せるように設定したものです。
このように、**をつけてデータを引数として渡すことで、Schemaが持つ辞書型のデータを展開して渡すことが可能になります。
そのため、emplyeeインスタンスにから直接.idを指定することで、employee_idを取り出すことができます。

この状態でhttp://127.0.0.1:8000/api/docs/にアクセス(すでにdocker-compose upがされている場合はリロード)すると、新しく緑色のPOSTが追加になっていると思います。

これまでに設定したAPIの一覧(OpenAPI)

このように表示されていれば成功です。

GET(取得)

employeeを取得するSchema

次に、登録したEmployeeを取得(GETメソッドに該当するが、CRUDではRetriveに対応している)するためのSchemaを設定します。

先ほど設定したEmployeeInと同じSchemaidを加えて、設定します。

これは、登録したEmployeeとの違いがidのみであり、また、idは自動的に付番されるものであるため、登録時には設定をしていなかったものであるためです。

それでは、以下のように記述してください。

from ninja import Schema
from datetime import date

class HelloSchema(Schema):
  name: str = "world"
  
class UserSchema(Schema):
  username: str
  is_authenticated: bool
  email: str = None
  first_name: str = None
  last_name: str = None

class ErrorSchema(Schema):
  message: str
  
class EmployeeIn(Schema):
  first_name: str
  last_name: str
  department_id: int = None
  birthdate: date = None

# add
class EmployeeOut(EmployeeIn):
  id: int

先に設定していたEmployeeInSchemaを継承し、EmployeeOutではEmployeeIn共通する項目以外(ここではidを設定しました。

APIの設定

次に、APIを設定します。

以下のようにGETメソッドを追加します(# add 7を参照)。

from urllib import response

from django.shortcuts import get_object_or_404
from ninja import NinjaAPI

from example.Schema.api_v1_schema import HelloSchema, UserSchema, ErrorSchema, EmployeeIn, EmployeeOut
from .models import Employee

app = NinjaAPI(
  title = "Django Ninja Sample App",
  version = "1.0.0"
  ) # add

~略~

# add 7
@app.get("/employees/{employee_id}", response = EmployeeOut)
def get_employee(request, employee_id: int):
  employee = get_object_or_404(Employee, id = employee_id)
  return employee

上記の例では、Schemaとして先ほど設定したEmployeeOutresponseとして設定しています。

また、URLからパスパラメータとしてemployee_idを受け取るようにしています。
そして、idは基本的に1から付番されるため、int型を設定しています。

そして、get_object_or_404は、Djangoで提供されている「get()メソッドを実行し、オブジェクトが存在しない場合には Http404 を送出するイディオム」です。

employeeインスタンスを生成する場合、オブジェクトが存在すれば、そのオブジェクトを、そうでなければ404_NOT_FOUNDを返すようになります。

ここでは、idがパスパラメータから受け取ったemployee_idに一致する場合を検証していることとなります。

一致するものがあれば、そのオブジェクトを返しています。

Djangoに仮のemployeeを登録

それでは、初めに、通常のDjnagoのadminから管理画面に入り、適当なemployeeを登録しておいてください。

その時に、管理画面にDepartmentEmployeeが表示されないと思いますので、以下を追加しておいてください。

from django.contrib import admin

from .models import Department, Employee

admin.site.register(Department) # add
admin.site.register(Employee) # add

これにより管理画面において、EmployeeDepartmentの登録ができるようになります。

それでは、APIの確認をしていきます。

まずは、id=0のユーザーがいるかどうか確認します。

Try it out」からemployee_idに0を入力し、Exuecuteを押します。
すると、下記のとおり、404_Not_Foundが返されます。

404_Not_Foundのイメージ

次に、先ほど登録したid=1employeeを表示できるか確認します。
同じ要領でid=1Exuecuteしてみてください。
下記のように取得できていれば成功です。

GETメソッドの成功例

以上のようにすることで、登録したレコードを取り出すことができるようになりました。

リスト形式での取得

また登録されているemployeeをリスト形式で取り出すこともできます。
以下のように設定します(「# add 8」参照)。

from urllib import response
from typing import List # add

from django.shortcuts import get_object_or_404
from ninja import NinjaAPI

from example.Schema.api_v1_schema import HelloSchema, UserSchema, ErrorSchema, EmployeeIn, EmployeeOut
from .models import Employee

app = NinjaAPI(
  title = "Django Ninja Sample App",
  version = "1.0.0"
  ) # add

~略~

# add 8
@app.get("/employees", response = List[EmployeeOut])
def employees_list(request):
  employees = Employee.objects.all()
  return employees

まずはtypingからListを読み込み、リスト形式を扱えるようにします。

その後、# add 8のようにresponseとしてリスト形式のEmployeeOutを設定し、関数でEmployeeモデルを全て取得し、employeeインスタンスを生成します。

これにより、下記のようにリスト形式でemployeeを取得することができます。
(登録したemployeeが先ほど追加した1つのみの場合は、事前に他のemployeeを複数追加してから試してみてください)

List形式でのGETメソッドの実行例

このように全ての登録されたレコードをList形式で出力することができます。

Update(更新)

次に見ていくのは、Update、いわゆるデータの更新です。
メソッドでいうとPUTメソッドになります。
今回は、すでに登録されたデータを更新するように設定していきます。

アップデートの方法としてはシンプルで、以下のAPIを設定するのみです。
事前にPOSTGETメソッドで使用したSchemaを使用していきますので、今回は新たなSchemaを設定する必要はありません。

通常のWeb開発でも、内容の更新をする場合は、既存データの更新になると思うので、新たな設定はせず、既存のものを使って更新するということが多いと思います。
それでは、以下のとおり追加していきます。

from urllib import response
from typing import List

from django.shortcuts import get_object_or_404
from ninja import NinjaAPI

from example.Schema.api_v1_schema import HelloSchema, UserSchema, ErrorSchema, EmployeeIn, EmployeeOut
from .models import Employee

app = NinjaAPI(
  title = "Django Ninja Sample App",
  version = "1.0.0"
  )

~略~

# add 9
@app.put("/employees/{employee_id}")
def update_employee(request, employee_id: int, payload: EmployeeIn):
  employee = get_object_or_404(Employee, id = employee_id)
  employee.first_name = payload.first_name
  employee.last_name = payload.last_name
  employee.department = payload.department
  employee.birthdate = payload.birthdate
  employee.save()
  return {"success": True}

流れとしては、以下のとおりです。

  1. パスパラメータとして更新の対象となるemployee_idを渡します。
  2. そのemployee_idからすでに登録されたemployeeのデータを取得します。GETメソッドで用いたget_object_or_404を使用しています。
  3. 更新用の関数により、各項目を受け取り、それぞれの項目に代入していきます。
  4. このとき使っているpayload(受け渡す情報)に対応するSchemaEmployeeInとし、employee_id以外を更新することとします。
  5. それぞれの項目に代入後、新しい情報に更新された内容で保存します(saveメソッドを使用します)。
  6. 結果として、{"success": True}を返すようにしています。

ちなみに、公式ドキュメントでは下記のように記述し、payloadからの情報に対してfor文を用いて、繰り返し処理による代入もできるように書いています。

for attr, value in payload.dict().items():
  setattr(employee, attr, value)

今回は、手間はかかりますが、ひとつひとつの値を代入するように設定しています。
項目が多い場合は、こちらの方法が良いと思います。

以下のような結果が出れば成功です。

PUTメソッドの実行結果

DELETE(削除)

最後に登録済みのデータのDELETE(削除)について見ていきます。

以下のように記述します。

from urllib import response
from typing import List

from django.shortcuts import get_object_or_404
from ninja import NinjaAPI

from example.Schema.api_v1_schema import HelloSchema, UserSchema, ErrorSchema, EmployeeIn, EmployeeOut
from .models import Employee

app = NinjaAPI(
  title = "Django Ninja Sample App",
  version = "1.0.0"
  )

~略~

# add 10
@app.delete("employees/{employee_id}")
def delete_employee(request, employee_id: int):
  employee = get_object_or_404(Employee, id = employee_id)
  employee.delete()
  return {"success": True}

内容はUPDATEとほどんど仕組みは変わりません。
使っているメソッドがsaveメソッドからdeleteメソッドに変わったくらいです。

実際に、動かしてみると、登録済みデータのemployee_idを入力し、executeを押すと、成功していることがわかります。

通常のDjango管理画面に入ってみたり、全てのemployeeを取得すると該当するidのデータが消えていることがわかります。

DELETEの実行結果
Listを取得するとid=2が削除されている
adminの画面でも削除されている

最後に

以上のように、Django NinjaにおけるCRUD処理を設定することができます。
基本はFastAPIとほとんど同じだと思います。
ただ、すでにDjangoのベースがあることから、データベースの設定などを省略したり、簡単に行うことができるなどのメリットはあるかもしれません。

Django Ninjaはもう少しドキュメントがあるので、読み進めながら自分なりに学習し、ブログなどで公開できたら良いかなと思っています。

Django Ninjaの基本のキはこんなところかなと思います。

それでは、また次回もお願いします!

Django-Ninjaチュートリアル③(CRUD処理)

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

はじめまして、ふじです。
Python、Django、FastAPI、React.js、Next.jsを学習している、ずっと文系のプログラミング独学者です。

目次