導入
人々はインターネットに接続し、ウェブを閲覧するために様々なデバイスを使用します。そのため、アプリケーションは様々な場所からアクセス可能でなければなりません。従来のウェブサイトであれば、レスポンシブなユーザーインターフェースがあれば通常は十分ですが、より複雑なアプリケーションでは、他の技術やアーキテクチャの使用が必要になることがよくあります。これには、クライアントサイドウェブアプリケーション、プログレッシブウェブアプリケーション(PWA)、またはネイティブモバイルアプリとして実行できる、バックエンドとフロントエンドに別々のRESTアプリケーションを持つことが含まれます。.
より複雑なアプリケーションを構築するときに使用できるツールには次のようなものがあります。
- React は、開発者が REST API バックエンド用の Web ページとネイティブ ページを構築できるようにする JavaScript フレームワークです。.
- Django は、モデル - ビュー - コントローラ (MVC) ソフトウェア アーキテクチャ パターンに準拠した、無料のオープン ソース Python Web フレームワークです。.
- Django REST フレームワークは、Django で REST API を構築するための強力かつ柔軟なツールキットです。.
このチュートリアルでは、React、Django、そしてDjango RESTフレームワークを用いて、REST APIバックエンドとフロントエンドが分離したモダンなウェブアプリケーションを構築します。ReactをDjangoと併用することで、JavaScriptとフロントエンド開発の最新技術を活用できます。Djangoに組み込まれたテンプレートエンジンを使用するDjangoアプリケーションを構築する代わりに、Reactを仮想ドキュメントオブジェクトモデル(DOM)、宣言型アプローチ、そしてデータの変更を迅速にレンダリングするコンポーネントを備えたUIライブラリとして使用します。.
これから構築するウェブアプリケーションは、顧客レコードをデータベースに保存します。これをCRMアプリケーションの出発点として利用できます。完成したら、Bootstrap 4でスタイル設定されたReactインターフェースを使用して、データの読み取り、更新、削除を行うことができます。.
前提条件
このチュートリアルを完了するには、次のものが必要です。
- Ubuntu 18.04 を搭載した開発マシン。.
- 「Ubuntu 18.04 に Python 3 をインストールしてローカル開発環境をセットアップする方法」の手順 1 と 2 に従って、Python 3、pip、および venv がマシンにインストールされます。.
- Node.js 6以降とnpm 5.2以降がマシンにインストールされています。PPAからのインストールの「Ubuntu 18.04にNode.jsをインストールする方法」の手順に従って、両方をインストールできます。.
ステップ1 – Python仮想環境を作成し、依存関係をインストールする
このステップでは、仮想環境を作成し、Django、Django REST フレームワーク、django-cors-headers など、アプリケーションに必要な依存関係をインストールします。.
このアプリケーションでは、DjangoとReact用にそれぞれ異なる開発サーバーを使用します。これらのサーバーは異なるポートで動作し、別々のドメインとして機能します。そのため、ブラウザにブロックされることなくReactからDjangoにHTTPリクエストを送信するために、クロスリソース共有(CORS)を有効にする必要があります。.
ホームディレクトリに移動し、Python 3 venv モジュールを使用して仮想環境を作成します。
cd ~
python3 -m venv ./envソースを使用して、作成した仮想環境をアクティブ化します。
source env/bin/activate次に、pipを使ってプロジェクトの依存関係をインストールします。これには以下のものが含まれます。
- Django: プロジェクト用の Web フレームワーク。.
- Django REST フレームワーク: Django を使用して REST API を構築するサードパーティ アプリケーション。.
- django-cors-headers: CORS を有効にするパッケージ。.
Django フレームワークをインストールします。
pip install django djangorestframework django-cors-headersプロジェクトの依存関係をインストールすることで、Django プロジェクトと React フロントエンドを作成できます。.
ステップ2 – Djangoプロジェクトを作成する
このステップでは、次のコマンドとツールを使用して Django プロジェクトを生成します。
django-admin startproject-name: django-admin は、Django でタスクを実行するためのコマンドラインツールです。startproject コマンドは新しい Django プロジェクトを作成します。.
python manager.py startapp myapp: manager.py は、すべての Django プロジェクトに自動的に追加されるユーティリティスクリプトで、新しいアプリケーションの作成、データベースの移行、Django プロジェクトのローカルでの提供など、様々な管理タスクを実行します。startapp コマンドは、Django プロジェクト内に Django アプリケーションを作成します。Django では、「アプリケーション」という用語は、プロジェクトに一連の機能を提供する Python パッケージを指します。.
まず、 django-admin startproject でDjangoプロジェクトを作成します。プロジェクト名は djangoreactproject とします。
django-admin startproject djangoreactproject先に進む前に、tree コマンドを使用して Django プロジェクトのディレクトリ構造を見てみましょう。.
プロジェクトのルートにある djangoreactproject フォルダに移動し、tree コマンドを実行します。
cd ~/djangoreactproject
tree次の出力が表示されます。
Output
├── djangoreactproject
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py~/djangoreactproject フォルダはプロジェクトのルートです。このフォルダには、作業に重要なファイルがいくつかあります。
- manager.py: さまざまな管理タスクを実行するユーティリティ スクリプト。.
- settings.py: Djangoプロジェクトのメイン設定ファイルで、プロジェクト設定を変更できます。これらの設定には、プロジェクトでアクティブなアプリケーションを指定する文字列のリストであるINSTALLED_APPSなどの変数が含まれます。利用可能な設定の詳細については、Djangoのドキュメントをご覧ください。.
- urls.py: このファイルには、URLパターンとそれに対応するビューのリストが含まれています。各パターンは、URLとそのURLに対して呼び出される関数の関係をマッピングします。URLとビューの詳細については、Djangoビューの作成方法に関するチュートリアルをご覧ください。.
プロジェクトで作業を始める最初のステップは、前のステップでインストールしたパッケージ(Django RESTフレームワークとDjango CORSパッケージを含む)をsettings.pyに追加して設定することです。nanoまたはお好みのエディタでファイルを開いてください。
nano ~/djangoreactproject/djangoreactproject/settings.pyINSTALLED_APPS 設定に移動し、rest_framework および corsheaders アプリケーションをリストの最後に追加します。
...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'corsheaders'
]次に、先ほどインストールしたCORSパッケージのcorsheaders.middleware.CorsMiddlewareミドルウェアをMIDDLEWARE設定に追加します。この設定はミドルウェアのリストです。ミドルウェアは、Webアプリケーションがリクエストまたはレスポンスを送信するたびに処理されるコードを含むPythonクラスです。
...
MIDDLEWARE = [
...
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'corsheaders.middleware.CorsMiddleware'
]次に、CORSを有効にします。CORS_ORIGIN_ALLOW_ALL設定は、すべてのドメインでCORSを許可するかどうかを指定します。CORS_ORIGIN_WHITELISTは、許可するURLを含むPythonタプルです。今回の場合、React開発サーバーはhttp://localhost:3000で実行されるため、settings.pyファイルに新しいCORS_ORIGIN_ALLOW_ALL = FalseとCORS_ORIGIN_WHITELIST('localhost:3000',)設定を追加します。これらの設定は、ファイル内の任意の場所に追加してください。
...
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = (
'localhost:3000',
)
...より多くの設定オプションについては、django-cors-headers のドキュメントをご覧ください。.
完了したらファイルを保存し、エディターを終了します。.
引き続き ~/djangoreactproject ディレクトリで、customers という新しい Django アプリケーションを作成します。
python manage.py startapp customersこれには、クライアント管理モデルとビューが含まれます。モデルはアプリケーションのデータのフィールドと動作を定義し、ビューはアプリケーションがWebリクエストを適切に処理し、必要なレスポンスを返すことを可能にします。.
次に、このアプリケーションをプロジェクトのsettings.pyファイルのインストール済みアプリケーションリストに追加し、Djangoがプロジェクトの一部として認識できるようにします。settings.pyをもう一度開きます。
nano ~/djangoreactproject/djangoreactproject/settings.py顧客アプリケーションを追加します。
...
INSTALLED_APPS = [
...
'rest_framework',
'corsheaders',
'customers'
]
...次に、データベースをマイグレーションし、ローカル開発サーバーを起動します。マイグレーションとは、Djangoがモデルに加えた変更をデータベーススキーマに反映させる方法です。これらの変更には、フィールドの追加やモデルの削除などが含まれます。モデルとマイグレーションの詳細については、「Djangoモデルの作成方法」をご覧ください。.
データベース転送:
python manage.py migrateローカル開発サーバーを起動します。
python manage.py runserver次のような出力が表示されます。
Output
Performing system checks...
System check identified no issues (0 silenced).
October 22, 2018 - 15:14:50
Django version 2.1.2, using settings 'djangoreactproject.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.ウェブアプリケーションはhttp://127.0.0.1:8000から実行されます。ウェブブラウザでこのアドレスにアクセスすると、次のページが表示されます。
この時点で、プログラムを実行したまま新しいターミナルを開いてプロジェクトの開発を続行します。.
ステップ3 – Reactフロントエンドを作成する
このセクションでは、React を使用してプロジェクトのフロントエンド アプリケーションを作成します。.
Reactには、Webpackを直接設定することなくReactプロジェクトを素早く生成できる公式ツールがあります。Webpackは、JavaScriptコード、CSS、画像などのウェブアセットをバンドルするためのモジュールバンドラーです。通常、Webpackを使用するには様々な設定オプションを設定する必要がありますが、Create-react-appツールを使えば、より詳細な制御が必要でない限り、Webpackを直接操作する必要はありません。Create-react-appを実行するには、npmでパッケージ化されたバイナリを実行するツールであるnpxを使用できます。.
2 番目のターミナルで、プロジェクト ディレクトリにいることを確認します。
cd ~/djangoreactprojectcreate-react-app と npx を使用して、frontend という React プロジェクトを作成します。
npx create-react-app frontend次に、React アプリ内を移動し、開発サーバーを起動します。
cd ~/djangoreactproject/frontend
npm startアプリケーションは http://localhost:3000/ から実行されます。
React 開発サーバーを実行したまま、別のターミナル ウィンドウを開いて続行します。.
この時点でプロジェクト全体のディレクトリ構造を確認するには、ルート フォルダーに移動してツリーを再度実行します。
cd ~/djangoreactproject
tree次のような構造が表示されます。
Output
├── customers
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── djangoreactproject
│ ├── __init__.py
│ ├── __pycache__
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── frontend
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ └── manifest.json
│ ├── README.md
│ ├── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── App.test.js
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── logo.svg
│ │ └── registerServiceWorker.js
│ └── yarn.lock
└── manage.pyこのアプリはReactインターフェースのスタイル設定にBootstrap 4を使用しているため、CSS設定を担うfrontend/src/App.cssファイルに記述します。ファイルを開いてください。
nano ~/djangoreactproject/frontend/src/App.cssファイルの先頭に次のエントリを追加します。ファイルの既存の内容は削除しても構いませんが、削除する必要はありません。
@import 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css';ここで、@import は他のスタイルシートからスタイル ルールをインポートするために使用される CSS ディレクティブです。.
バックエンド アプリケーションとフロントエンド アプリケーションの両方を作成したので、顧客モデルとデモ データを作成しましょう。.
ステップ4 – 顧客モデルと初期データを作成する
DjangoアプリケーションとReactインスタンスを作成したら、次のステップは顧客モデルを作成することです。顧客モデルは、顧客情報を保持するデータベーステーブルを表します。Djangoのオブジェクトリレーショナルマッパー(ORM)は、Pythonのクラスと変数をSQLのテーブルと列にマッピングすることでデータベース操作を実行するため、SQLは必要ありません。このように、Django ORMはPythonインターフェースを通じてデータベースとのSQLのやり取りを抽象化します。.
仮想環境を再度有効にします。
cd ~
source env/bin/activateクライアント ディレクトリに移動し、アプリケーションのモデルを保持する Python ファイルである models.py を開きます。
cd ~/djangoreactproject/customers/
nano models.pyファイルには次の内容が含まれます。
from django.db import models
# Create your models here.CustomerモデルAPIは、import import models from django.db文によって既にファイルに含まれています。次に、models.Modelを拡張するCustomerクラスを追加します。Djangoのすべてのモデルは、django.db.models.Modelを拡張するPythonクラスです。.
Customer モデルには次のデータベース フィールドがあります。
ファーストネーム– 顧客の名。.苗字– 顧客の姓。.メール– 顧客のメールアドレス。.電話– 顧客の電話番号。.住所– 顧客の住所。.説明– 顧客の説明。.作成時– 顧客が追加された日付。.
また、モデルの表示方法を指定する __str__() 関数も追加します。今回の場合は、顧客のファーストネームを使用します。クラスの作成とオブジェクトの定義の詳細については、「Python 3 でクラスを作成し、オブジェクトを定義する方法」を参照してください。.
ファイルに次のコードを追加します。
from django.db import models
class Customer(models.Model):
first_name = models.CharField("First name", max_length=255)
last_name = models.CharField("Last name", max_length=255)
email = models.EmailField()
phone = models.CharField(max_length=20)
address = models.TextField(blank=True, null=True)
description = models.TextField(blank=True, null=True)
createdAt = models.DateTimeField("Created At", auto_now_add=True)
def __str__(self):
return self.first_name次に、データベースを移行してデータベーステーブルを作成します。makemigrationsコマンドは、モデルの変更が追加された移行ファイルを作成し、 migrate コマンドは移行ファイルの変更をデータベースに適用します。.
プロジェクトのルート フォルダーに戻ります。
cd ~/djangoreactproject移行ファイルを作成するには、次のコマンドを実行します。
python manage.py makemigrations次のような出力が得られます。
Output
customers/migrations/0001_initial.py
- Create model Customer次の変更をデータベースに適用します。
python manage.py migrate転送が成功したことを示す出力が表示されます。
Output
Operations to perform:
Apply all migrations: admin, auth, contenttypes, customers, sessions
Running migrations:
Applying customers.0001_initial... OK次に、データ転送ファイルを使用して初期顧客データを作成します。データ転送ファイルとは、データベースにデータを追加または変更する移行処理です。Customersアプリケーション用の空のデータ転送ファイルを作成します。
python manage.py makemigrations --empty --name customers customers移行ファイルの名前とともに次の確認が表示されます。
Output
Migrations for 'customers':
customers/migrations/0002_customers.py移行ファイルの名前は 0002_customers.py であることに注意してください。.
次に、クライアント アプリケーションの移行フォルダーに移動します。
cd ~/djangoreactproject/customers/migrations作成された移行ファイルを開きます。
nano 0002_customers.pyこれはファイルの初期内容です:
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('customers', '0001_initial'),
]
operations = [
]import ステートメントは、データベースを操作するためのクラスを含む組み込みパッケージである django.db から、移行を作成するための Django API である Migrations API をインポートします。.
Migrationクラスは、データベースの移行時に実行される操作を記述するPythonクラスです。このクラスはmigrations.Migrationを拡張し、2つのリストを持ちます。
依存関係: 依存する移行が含まれます。.操作: 移行を適用することによって実行される操作が含まれます。.
次に、テスト用の顧客データを作成するメソッドを追加します。Migrationクラスを定義する前に、以下のメソッドを追加してください。
...
def create_data(apps, schema_editor):
Customer = apps.get_model('customers', 'Customer')
Customer(first_name="Customer 001", last_name="Customer 001", email="[email protected]", phone="00000000", address="Customer 000 Address", description= "Customer 001 description").save()
...このメソッドでは、顧客アプリケーションの Customer クラスを取得し、データベースに挿入するテスト顧客を作成します。.
新しい顧客を作成できるCustomerクラスを取得するには、appsオブジェクトのget_model()メソッドを使用します。appsオブジェクトは、インストールされたアプリケーションとそのデータベースモデルのレジストリを表します。.
RunPython() メソッドを使用して create_data() を実行すると、apps オブジェクトが渡されます。空の操作リストに、migrations.RunPython() メソッドを追加します。
...
operations = [
migrations.RunPython(create_data),
]RunPython() は、マイグレーション内でカスタム Python コードを実行できる Migrations API の一部です。操作リストでは、マイグレーションを適用するときにこのメソッドが実行されることを指定しています。.
完全なファイルは次のとおりです。
from django.db import migrations
def create_data(apps, schema_editor):
Customer = apps.get_model('customers', 'Customer')
Customer(first_name="Customer 001", last_name="Customer 001", email="[email protected]", phone="00000000", address="Customer 000 Address", description= "Customer 001 description").save()
class Migration(migrations.Migration):
dependencies = [
('customers', '0001_initial'),
]
operations = [
migrations.RunPython(create_data),
]データ移行の詳細については、Django データ移行のドキュメントを参照してください。
データベースを移動するには、まずプロジェクトのメイン フォルダーに戻ります。
cd ~/djangoreactprojectデータベースを移行してテスト データを作成します。
python manage.py migrate移行を確認する出力が表示されます。
Output
Operations to perform:
Apply all migrations: admin, auth, contenttypes, customers, sessions
Running migrations:
Applying customers.0002_customers... OK顧客モデルと表現データを作成したら、REST API の構築に進むことができます。.
ステップ5 – REST APIを作成する
このステップでは、Django RESTフレームワークを使用してREST APIを作成します。いくつかの異なるAPIビューを作成します。APIビューはAPIリクエストまたは呼び出しを処理する関数であり、APIエンドポイントはRESTシステムとの接点を表す一意のURLです。例えば、ユーザーがAPIエンドポイントにGETリクエストを送信すると、Djangoは対応する関数またはAPIビューを呼び出してリクエストを処理し、可能な結果を返します。.
シリアライザーも使用します。Django RESTフレームワークのシリアライザーは、複雑なモデルインスタンスやクエリセットをAPIで使用できるようにJSON形式に変換します。シリアライザークラスは逆方向にも機能し、Djangoモデルやクエリセット内のデータを解析および分離するためのメカニズムを提供します。.
当社の API エンドポイントには以下が含まれます。
- api/customers: このエンドポイントは、顧客を作成し、ページ分けされた顧客のコレクションを返すために使用されます。.
- api/顧客/ : このエンドポイントは、主キーまたは ID によって個々の顧客を取得、更新、削除するために使用されます。.
また、プロジェクトのurls.pyファイルに、関連するエンドポイント(api/customersとapi/customers/など)のURLを作成します。 )。.
まず、クライアント モデルのシリアライザー クラスを作成しましょう。.
シリアライザクラスを追加する
Customer モデルのシリアライザークラスを作成することは、Customer インスタンスとクエリセットを JSON 形式に変換するために不可欠です。シリアライザークラスを作成するには、まず Customers アプリケーション内に serializers.py ファイルを作成します。
cd ~/djangoreactproject/customers/
nano serializers.pyAPI シリアルとクライアント モデルをインポートするには、次のコードを追加します。
from rest_framework import serializers
from .models import Customer次に、Serializers.ModelSerializer を拡張し、シリアル化するフィールドを指定するシリアライザー クラスを作成します。
...
class CustomerSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = ('pk','first_name', 'last_name', 'email', 'phone','address','description')Meta クラスは、シリアル化のモデルとフィールド (pk、first_name、last_name、email、phone、address、description) を指定します。.
ファイルの全内容は次のとおりです。
from rest_framework import serializers
from .models import Customer
class CustomerSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = ('pk','first_name', 'last_name', 'email', 'phone','address','description')シリアライザー クラスを作成したので、API ビューを追加できます。.
APIビューの追加
このセクションでは、ユーザーがビュー関数に対応するエンドポイントにアクセスしたときに Django によって呼び出される、アプリケーションの API ビューを作成します。.
~/djangoreactプロジェクト/顧客/ビュー.py 開ける:
nano ~/djangoreactproject/customers/views.py既存のものを削除し、次のインポートを追加します。
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import status
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from .models import Customer
from .serializers import *作成したシリアル化を、クライアント モデルと Django REST フレームワーク API とともにインポートします。.
次に、POST および GET HTTP リクエストを処理するビューを追加します。
...
@api_view(['GET', 'POST'])
def customers_list(request):
"""
List customers, or create a new customer.
"""
if request.method == 'GET':
data = []
nextPage = 1
previousPage = 1
customers = Customer.objects.all()
page = request.GET.get('page', 1)
paginator = Paginator(customers, 10)
try:
data = paginator.page(page)
except PageNotAnInteger:
data = paginator.page(1)
except EmptyPage:
data = paginator.page(paginator.num_pages)
serializer = CustomerSerializer(data,context={'request': request} ,many=True)
if data.has_next():
nextPage = data.next_page_number()
if data.has_previous():
previousPage = data.previous_page_number()
return Response({'data': serializer.data , 'count': paginator.count, 'numpages' : paginator.num_pages, 'nextlink': '/api/customers/?page=' + str(nextPage), 'prevlink': '/api/customers/?page=' + str(previousPage)})
elif request.method == 'POST':
serializer = CustomerSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)まず、@api_view(['GET', 'POST']) デコレータを使用して、GET リクエストと POST リクエストを受け入れる API ビューを作成します。デコレータとは、別の関数を受け取り、それを動的に拡張する関数です。.
メソッド本体では、request.method 変数を使用して現在の HTTP メソッドを確認し、リクエストの種類に応じて適切なロジックを実行します。
- リクエストがGETの場合、このメソッドはDjango Paginatorを使用してデータをページ分割し、シリアル化後の最初のデータページ、利用可能な顧客数、利用可能なページ数、および前後のページへのリンクを返します。Paginatorは、データリストをページにページ分割し、各ページの項目にアクセスするためのメソッドを提供する組み込みのDjangoクラスです。.
- リクエストがPOSTの場合、このメソッドは受信したクライアントデータをシリアル化し、シリアライザーオブジェクトのsave()メソッドを呼び出します。その後、HttpResponseのインスタンスであるResponseオブジェクトをステータスコード201とともに返します。作成する各プロファイルは、HttpResponseオブジェクトを返す必要があります。save()メソッドは、シリアル化されたデータをデータベースに保存します。.
HttpResponse とビューの詳細については、ビュー関数の作成に関するこのディスカッションを参照してください。.
ここで、pk (主キー) で顧客を取得、更新、削除するための GET、PUT、および DELETE リクエストの処理を担当する API ビューを追加します。
...
@api_view(['GET', 'PUT', 'DELETE'])
def customers_detail(request, pk):
"""
Retrieve, update or delete a customer by id/pk.
"""
try:
customer = Customer.objects.get(pk=pk)
except Customer.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
serializer = CustomerSerializer(customer,context={'request': request})
return Response(serializer.data)
elif request.method == 'PUT':
serializer = CustomerSerializer(customer, data=request.data,context={'request': request})
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
customer.delete()
return Response(status=status.HTTP_204_NO_CONTENT)このメソッドは、GET、PUT、および DELETE リクエストを受け入れることができる API ビューであることを示すために、@api_view(['GET', 'PUT', 'DELETE']) で装飾されています。.
request.method フィールドのチェックはリクエスト メソッドを検証し、その値に応じて正しいロジックを呼び出します。
- リクエストが GET の場合、クライアント データはシリアル化され、Response オブジェクトを使用して送信されます。.
- PUTリクエストの場合、このメソッドは新しいクライアントデータ用のシリアライザーを作成します。次に、save()メソッドは作成されたシリアライザーオブジェクトを呼び出します。最後に、更新されたクライアントデータを含むレスポンスオブジェクトを送信します。.
- DELETE 要求の場合、delete() メソッドはクライアント オブジェクトの delete() メソッドを呼び出してそれを削除し、データのない Response オブジェクトを返します。.
完成したファイルは次のようになります。
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import status
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from .models import Customer
from .serializers import *
@api_view(['GET', 'POST'])
def customers_list(request):
"""
List customers, or create a new customer.
"""
if request.method == 'GET':
data = []
nextPage = 1
previousPage = 1
customers = Customer.objects.all()
page = request.GET.get('page', 1)
paginator = Paginator(customers, 5)
try:
data = paginator.page(page)
except PageNotAnInteger:
data = paginator.page(1)
except EmptyPage:
data = paginator.page(paginator.num_pages)
serializer = CustomerSerializer(data,context={'request': request} ,many=True)
if data.has_next():
nextPage = data.next_page_number()
if data.has_previous():
previousPage = data.previous_page_number()
return Response({'data': serializer.data , 'count': paginator.count, 'numpages' : paginator.num_pages, 'nextlink': '/api/customers/?page=' + str(nextPage), 'prevlink': '/api/customers/?page=' + str(previousPage)})
elif request.method == 'POST':
serializer = CustomerSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(['GET', 'PUT', 'DELETE'])
def customers_detail(request, pk):
"""
Retrieve, update or delete a customer by id/pk.
"""
try:
customer = Customer.objects.get(pk=pk)
except Customer.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
serializer = CustomerSerializer(customer,context={'request': request})
return Response(serializer.data)
elif request.method == 'PUT':
serializer = CustomerSerializer(customer, data=request.data,context={'request': request})
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
customer.delete()
return Response(status=status.HTTP_204_NO_CONTENT)これでエンドポイントの作成を続行できます。.
APIエンドポイントの追加
ここで、APIエンドポイントを作成します: api/customers/ (顧客の問い合わせと作成用)、および api/customers/ 、PK によって個々の顧客を取得、更新、または削除します。.
~/djangoreactproject/djangoreactproject/urls.py を開きます:
nano ~/djangoreactproject/djangoreactproject/urls.py既存のものはそのままにして、ファイルの先頭にある Customers ビューにインポートを追加します。
from django.contrib import admin
from django.urls import path
from customers import views
from django.conf.urls import url次に、URL api/customers/ と api/customers/アプリケーション URL を含む URL パターンのリストに追加します。
...
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^api/customers/$', views.customers_list),
url(r'^api/customers/(?P<pk>[0-9]+)$', views.customers_detail),
]REST エンドポイントが作成されたので、それをどのように使用できるかを見てみましょう。.
ステップ6 – AxiosでREST APIを使用する
このステップでは、API呼び出しに使用するHTTPクライアントであるAxiosをインストールします。また、作成したAPIエンドポイントを利用するためのクラスも作成します。.
まず、仮想環境を非アクティブ化します。
deactivate次に、フロントエンド フォルダーに移動します。
cd ~/djangoreactproject/frontend次を使用して npm から axios をインストールします。
npm install axios --save–save オプションは、アプリケーションの package.json ファイルに axios 依存関係を追加します。.
次に、REST APIを呼び出すコードを含むCustomersService.jsというJavaScriptファイルを作成します。このファイルは、プロジェクトのアプリケーションコードがあるsrcフォルダに作成します。
cd src
nano CustomersService.jsDjango REST API に接続するためのメソッドを含む次のコードを追加します。
import axios from 'axios';
const API_URL = 'http://localhost:8000';
export default class CustomersService{
constructor(){}
getCustomers() {
const url = `${API_URL}/api/customers/`;
return axios.get(url).then(response => response.data);
}
getCustomersByURL(link){
const url = `${API_URL}${link}`;
return axios.get(url).then(response => response.data);
}
getCustomer(pk) {
const url = `${API_URL}/api/customers/${pk}`;
return axios.get(url).then(response => response.data);
}
deleteCustomer(customer){
const url = `${API_URL}/api/customers/${customer.pk}`;
return axios.delete(url);
}
createCustomer(customer){
const url = `${API_URL}/api/customers/`;
return axios.post(url,customer);
}
updateCustomer(customer){
const url = `${API_URL}/api/customers/${customer.pk}`;
return axios.put(url,customer);
}
}CustomersService クラスは、次の Axios メソッドを呼び出します。
- getCustomers(): 顧客の最初のページを取得します。.
- getCustomersByURL(): URLで顧客を取得します。これにより、/api/customers/?page=2のようなリンクを渡すことで、後続の顧客ページにアクセスできるようになります。.
- getCustomer(): 主キーで顧客を取得します。.
- createCustomer(): 顧客を作成します。.
- updateCustomer(): 顧客を更新します。.
- deleteCustomer(): 顧客を削除します。.
CustomersList コンポーネントを作成することで、React UI に API データを表示できるようになりました。.
ステップ7 – ReactアプリでAPIからのデータを表示する
このステップでは、CustomersList Reactコンポーネントを作成します。Reactコンポーネントはユーザーインターフェースの一部を表します。また、UIを独立した再利用可能な部分に分割することもできます。.
まず、frontend/src に CustomersList.js を作成します。
nano ~/djangoreactproject/frontend/src/CustomersList.jsまず、React と Component をインポートして、React コンポーネントを作成します。
import React, { Component } from 'react';次に、前の手順で作成した CustomersService モジュールをインポートしてインスタンス化します。このモジュールは、バックエンド REST API と通信するメソッドを提供します。
...
import CustomersService from './CustomersService';
const customersService = new CustomersService();次に、REST APIを呼び出すためにComponentクラスを拡張するCustomersListコンポーネントを作成します。ReactコンポーネントはComponentクラスを拡張またはサブクラス化する必要があります。E6クラスと継承の詳細については、JavaScriptのクラスを理解するためのチュートリアルをご覧ください。.
react.Component を拡張する React コンポーネントを作成するには、次のコードを追加します。
...
class CustomersList extends Component {
constructor(props) {
super(props);
this.state = {
customers: [],
nextPageURL: ''
};
this.nextPage = this.nextPage.bind(this);
this.handleDelete = this.handleDelete.bind(this);
}
}
export default CustomersList;コンストラクター内で、状態オブジェクトを初期化します。このオブジェクトは、空の顧客配列を使用してコンポーネントの状態変数を保持します。この配列には、顧客と、バックエンドAPIから取得する次のページのURLを保持する nextPageURL が格納されます。また、HTMLコードからアクセスできるように、 nextPage() メソッドと handleDelete() メソッドをこのオブジェクトにアタッチします。.
次に、閉じ中括弧の前に、CustomersList クラスの componentDidMount() メソッドと getCustomers() の呼び出しを追加します。.
componentDidMount() メソッドは、コンポーネントが作成され DOM に挿入されるときに呼び出されるコンポーネント ライフサイクル メソッドです。getCustomers() は、Customer Service オブジェクトを呼び出して、Django バックエンドから最初のページのデータと次のページ リンクを取得します。
...
componentDidMount() {
var self = this;
customersService.getCustomers().then(function (result) {
self.setState({ customers: result.data, nextPageURL: result.nextlink})
});
}次に、クライアントの削除を処理する handleDelete() メソッドを componentDidMount() の下に追加します。
...
handleDelete(e,pk){
var self = this;
customersService.deleteCustomer({pk : pk}).then(()=>{
var newArr = self.state.customers.filter(function(obj) {
return obj.pk !== pk;
});
self.setState({customers: newArr})
});
}handleDeleteメソッドはdeleteCustomer()メソッドを呼び出し、pk(主キー)を使用して顧客を削除します。操作が成功すると、顧客配列は削除された顧客でフィルタリングされます。.
次に、次のページのデータを取得し、次のページへのリンクを更新するための nextPage() メソッドを追加します。
...
nextPage(){
var self = this;
customersService.getCustomersByURL(this.state.nextPageURL).then((result) => {
self.setState({ customers: result.data, nextPageURL: result.nextlink})
});
}nextPage() メソッドは、状態オブジェクト this.state.nextPageURL から次のページの URL を取得する getCustomersByURL() メソッドを呼び出し、返されたデータで顧客配列を更新します。.
最後に、コンポーネントの状態から顧客のテーブルをレンダリングするコンポーネントの render() メソッドを追加します。
...
render() {
return (
<div className="customers--list">
<table className="table">
<thead key="thead">
<tr>
<th>#</th>
<th>First Name</th>
<th>Last Name</th>
<th>Phone</th>
<th>Email</th>
<th>Address</th>
<th>Description</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{this.state.customers.map( c =>
<tr key={c.pk}>
<td>{c.pk} </td>
<td>{c.first_name}</td>
<td>{c.last_name}</td>
<td>{c.phone}</td>
<td>{c.email}</td>
<td>{c.address}</td>
<td>{c.description}</td>
<td>
<button onClick={(e)=> this.handleDelete(e,c.pk) }> Delete</button>
<a href={"/customer/" + c.pk}> Update</a>
</td>
</tr>)}
</tbody>
</table>
<button className="btn btn-primary" onClick= { this.nextPage }>Next</button>
</div>
);
}ファイルの全内容は次のとおりです。
import React, { Component } from 'react';
import CustomersService from './CustomersService';
const customersService = new CustomersService();
class CustomersList extends Component {
constructor(props) {
super(props);
this.state = {
customers: [],
nextPageURL: ''
};
this.nextPage = this.nextPage.bind(this);
this.handleDelete = this.handleDelete.bind(this);
}
componentDidMount() {
var self = this;
customersService.getCustomers().then(function (result) {
console.log(result);
self.setState({ customers: result.data, nextPageURL: result.nextlink})
});
}
handleDelete(e,pk){
var self = this;
customersService.deleteCustomer({pk : pk}).then(()=>{
var newArr = self.state.customers.filter(function(obj) {
return obj.pk !== pk;
});
self.setState({customers: newArr})
});
}
nextPage(){
var self = this;
console.log(this.state.nextPageURL);
customersService.getCustomersByURL(this.state.nextPageURL).then((result) => {
self.setState({ customers: result.data, nextPageURL: result.nextlink})
});
}
render() {
return (
<div className="customers--list">
<table className="table">
<thead key="thead">
<tr>
<th>#</th>
<th>First Name</th>
<th>Last Name</th>
<th>Phone</th>
<th>Email</th>
<th>Address</th>
<th>Description</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{this.state.customers.map( c =>
<tr key={c.pk}>
<td>{c.pk} </td>
<td>{c.first_name}</td>
<td>{c.last_name}</td>
<td>{c.phone}</td>
<td>{c.email}</td>
<td>{c.address}</td>
<td>{c.description}</td>
<td>
<button onClick={(e)=> this.handleDelete(e,c.pk) }> Delete</button>
<a href={"/customer/" + c.pk}> Update</a>
</td>
</tr>)}
</tbody>
</table>
<button className="btn btn-primary" onClick= { this.nextPage }>Next</button>
</div>
);
}
}
export default CustomersList;顧客リストを表示するための CustomersList コンポーネントを作成したので、顧客の作成と更新を処理するコンポーネントを追加できます。.
ステップ8 – React Createコンポーネントを追加してクライアントを更新する
このステップでは、顧客の作成と更新を処理するCustomerCreateUpdateコンポーネントを作成します。このコンポーネントは、ユーザーが新しい顧客データを入力したり、既存のエントリを更新したりするためのフォームを提供することでこれを実現します。.
frontend/src に CustomerCreateUpdate.js ファイルを作成します。
nano ~/djangoreactproject/frontend/src/CustomerCreateUpdate.jsReact と Component をインポートして React コンポーネントを作成するには、次のコードを追加します。
import React, { Component } from 'react';前の手順で作成した、バックエンド REST API と通信するメソッドを提供する CustomersService クラスをインポートしてインスタンス化することもできます。
...
import CustomersService from './CustomersService';
const customersService = new CustomersService();次に、顧客を作成および更新するために Component を拡張する CustomerCreateUpdate コンポーネントを作成します。
...
class CustomerCreateUpdate extends Component {
constructor(props) {
super(props);
}
}
export default CustomerCreateUpdate;クラス定義に、顧客情報を取得する HTML フォームをレンダリングするコンポーネントの render() メソッドを追加します。
...
render() {
return (
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label>
First Name:</label>
<input className="form-control" type="text" ref='firstName' />
<label>
Last Name:</label>
<input className="form-control" type="text" ref='lastName'/>
<label>
Phone:</label>
<input className="form-control" type="text" ref='phone' />
<label>
Email:</label>
<input className="form-control" type="text" ref='email' />
<label>
Address:</label>
<input className="form-control" type="text" ref='address' />
<label>
Description:</label>
<textarea className="form-control" ref='description' ></textarea>
<input className="btn btn-primary" type="submit" value="Submit" />
</div>
</form>
);
}メソッドは、フォーム入力要素ごとに ref 属性を追加し、フォーム要素の値にアクセスして設定します。.
次に、ユーザーが送信ボタンをクリックしたときに適切な動作を実行するために、render() メソッドの上に handleSubmit(event) メソッドを定義します。
...
handleSubmit(event) {
const { match: { params } } = this.props;
if(params && params.pk){
this.handleUpdate(params.pk);
}
else
{
this.handleCreate();
}
event.preventDefault();
}
...handleSubmit(event) メソッドはフォームの送信を処理し、ルートに応じて、渡された pk でクライアントを更新する handleUpdate(pk) メソッド、または新しいクライアントを作成する handleCreate() メソッドのいずれかを呼び出します。これらのメソッドについては後ほど定義します。.
コンポーネント コンストラクターに戻り、新しく追加された handleSubmit() メソッドをこれにリンクして、フォームでアクセスできるようにします。
...
class CustomerCreateUpdate extends Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
...次に、フォームデータから顧客を作成するためのhandleCreate()メソッドを定義します。handleSubmit(event)メソッドの上に次のコードを追加します。
...
handleCreate(){
customersService.createCustomer(
{
"first_name": this.refs.firstName.value,
"last_name": this.refs.lastName.value,
"email": this.refs.email.value,
"phone": this.refs.phone.value,
"address": this.refs.address.value,
"description": this.refs.description.value
}).then((result)=>{
alert("Customer created!");
}).catch(()=>{
alert('There was an error! Please re-check your form.');
});
}
...handleCreate() メソッドは、入力データから顧客を作成するために使用されます。このメソッドは対応する CustomersService.createCustomer() メソッドを呼び出し、このメソッドはバックエンドへの実際の API を呼び出して顧客を作成します。.
次に、handleCreate メソッドの下に、更新を実装するための handleUpdate(pk) メソッドを定義します。
...
handleUpdate(pk){
customersService.updateCustomer(
{
"pk": pk,
"first_name": this.refs.firstName.value,
"last_name": this.refs.lastName.value,
"email": this.refs.email.value,
"phone": this.refs.phone.value,
"address": this.refs.address.value,
"description": this.refs.description.value
}
).then((result)=>{
alert("Customer updated!");
}).catch(()=>{
alert('There was an error! Please re-check your form.');
});
}updateCustomer() メソッドは、顧客情報フォームから取得した新しい情報を使用して顧客を更新します。このメソッドは、customersService.updateCustomer() メソッドを呼び出します。.
次に、componentDidMount() メソッドを追加します。ユーザーが customer/:pk ルートにアクセスした場合、URL の主キーを使用してフォームに顧客情報を入力します。これを行うには、componentDidMount() ライフサイクルイベントでコンポーネントがマウントされた後、getCustomer(pk) メソッドを追加します。このメソッドを追加するには、コンポーネントのコンストラクターの下に次のコードを追加します。
...
componentDidMount(){
const { match: { params } } = this.props;
if(params && params.pk)
{
customersService.getCustomer(params.pk).then((c)=>{
this.refs.firstName.value = c.first_name;
this.refs.lastName.value = c.last_name;
this.refs.email.value = c.email;
this.refs.phone.value = c.phone;
this.refs.address.value = c.address;
this.refs.description.value = c.description;
})
}
}ファイルの全内容は次のとおりです。
import React, { Component } from 'react';
import CustomersService from './CustomersService';
const customersService = new CustomersService();
class CustomerCreateUpdate extends Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidMount(){
const { match: { params } } = this.props;
if(params && params.pk)
{
customersService.getCustomer(params.pk).then((c)=>{
this.refs.firstName.value = c.first_name;
this.refs.lastName.value = c.last_name;
this.refs.email.value = c.email;
this.refs.phone.value = c.phone;
this.refs.address.value = c.address;
this.refs.description.value = c.description;
})
}
}
handleCreate(){
customersService.createCustomer(
{
"first_name": this.refs.firstName.value,
"last_name": this.refs.lastName.value,
"email": this.refs.email.value,
"phone": this.refs.phone.value,
"address": this.refs.address.value,
"description": this.refs.description.value
}
).then((result)=>{
alert("Customer created!");
}).catch(()=>{
alert('There was an error! Please re-check your form.');
});
}
handleUpdate(pk){
customersService.updateCustomer(
{
"pk": pk,
"first_name": this.refs.firstName.value,
"last_name": this.refs.lastName.value,
"email": this.refs.email.value,
"phone": this.refs.phone.value,
"address": this.refs.address.value,
"description": this.refs.description.value
}
).then((result)=>{
console.log(result);
alert("Customer updated!");
}).catch(()=>{
alert('There was an error! Please re-check your form.');
});
}
handleSubmit(event) {
const { match: { params } } = this.props;
if(params && params.pk){
this.handleUpdate(params.pk);
}
else
{
this.handleCreate();
}
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label>
First Name:</label>
<input className="form-control" type="text" ref='firstName' />
<label>
Last Name:</label>
<input className="form-control" type="text" ref='lastName'/>
<label>
Phone:</label>
<input className="form-control" type="text" ref='phone' />
<label>
Email:</label>
<input className="form-control" type="text" ref='email' />
<label>
Address:</label>
<input className="form-control" type="text" ref='address' />
<label>
Description:</label>
<textarea className="form-control" ref='description' ></textarea>
<input className="btn btn-primary" type="submit" value="Submit" />
</div>
</form>
);
}
}
export default CustomerCreateUpdate;CustomerCreateUpdate コンポーネントを作成することで、メインの App コンポーネントを更新し、作成したさまざまなコンポーネントへのリンクを追加できます。.
ステップ9 – メインアプリケーションコンポーネントを更新する
このセクションでは、前の手順で作成したコンポーネントにリンクするように App コンポーネントを更新します。.
フロントエンド フォルダーから次のコマンドを実行して React ルーターをインストールします。これにより、さまざまな React コンポーネント間のルーティングとナビゲーションを追加できます。
cd ~/djangoreactproject/frontend
npm install --save react-router-dom次に、~/djangoreactproject/frontend/src/App.js を開きます。
nano ~/djangoreactproject/frontend/src/App.js既存の項目をすべて削除し、ルーティングを追加するために必要なクラスをインポートする以下のコードを追加します。Routerコンポーネントを作成するBrowserRouterと、Routeコンポーネントを作成するRouteです。
import React, { Component } from 'react';
import { BrowserRouter } from 'react-router-dom'
import { Route, Link } from 'react-router-dom'
import CustomersList from './CustomersList'
import CustomerCreateUpdate from './CustomerCreateUpdate'
import './App.css';BrowserRouter は、HTML5 履歴 API を使用して UI を URL と同期させます。.
次に、BrowserRouter コンポーネントによってラップされる基本コンポーネントを提供する基本レイアウトを作成します。
...
const BaseLayout = () => (
<div className="container-fluid">
<nav className="navbar navbar-expand-lg navbar-light bg-light">
<a className="navbar-brand" href="#">Django React Demo</a>
<button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNavAltMarkup">
<div className="navbar-nav">
<a className="nav-item nav-link" href="/">CUSTOMERS</a>
<a className="nav-item nav-link" href="/customer">CREATE CUSTOMER</a>
</div>
</div>
</nav>
<div className="content">
<Route path="/" exact component={CustomersList} />
<Route path="/customer/:pk" component={CustomerCreateUpdate} />
<Route path="/customer/" exact component={CustomerCreateUpdate} />
</div>
</div>
)アプリケーションのルートを定義するには、Route コンポーネントを使用します。これは、一致が見つかった時点でルーターがロードするコンポーネントです。各ルートには、一致させるルートを指定するための Route と、一致させるコンポーネントを指定するためのコンポーネントが必要です。exact 属性は、ルーターにルートを正確に一致させるように指示します。.
最後に、React アプリケーションのメインまたは最上位コンポーネントである App コンポーネントを作成します。
...
class App extends Component {
render() {
return (
<BrowserRouter>
<BaseLayout/>
</BrowserRouter>
);
}
}
export default App;アプリケーションはブラウザで実行されるため、BaseLayout コンポーネントを BrowserRouter コンポーネントでラップしました。.
完成したファイルは次のようになります。
import React, { Component } from 'react';
import { BrowserRouter } from 'react-router-dom'
import { Route, Link } from 'react-router-dom'
import CustomersList from './CustomersList'
import CustomerCreateUpdate from './CustomerCreateUpdate'
import './App.css';
const BaseLayout = () => (
<div className="container-fluid">
<nav className="navbar navbar-expand-lg navbar-light bg-light">
<a className="navbar-brand" href="#">Django React Demo</a>
<button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNavAltMarkup">
<div className="navbar-nav">
<a className="nav-item nav-link" href="/">CUSTOMERS</a>
<a className="nav-item nav-link" href="/customer">CREATE CUSTOMER</a>
</div>
</div>
</nav>
<div className="content">
<Route path="/" exact component={CustomersList} />
<Route path="/customer/:pk" component={CustomerCreateUpdate} />
<Route path="/customer/" exact component={CustomerCreateUpdate} />
</div>
</div>
)
class App extends Component {
render() {
return (
<BrowserRouter>
<BaseLayout/>
</BrowserRouter>
);
}
}
export default App;アプリケーションにルーティングを追加したら、テストの準備が整いました。http://localhost:3000 にアクセスしてください。アプリケーションのホームページが表示されます。
このプログラムにより、CRM プログラムの基盤が構築されます。.
結果
このチュートリアルでは、DjangoとReactを使ってデモアプリケーションを作成しました。REST APIの構築にはDjango RESTフレームワーク、APIの利用にはAxios、CSSスタイル設定にはBootstrap 4を使用しました。このプロジェクトのソースコードは、こちらのGitHubリポジトリでご覧いただけます。.












