著者は、Write for DOnationsプログラムの一部として寄付を受け取るためにOpen Sourcing Mental Illness Ltdを選択しました。
前書き
さまざまな種類のデバイスを使用して、インターネットに接続し、Webを閲覧します。 このため、アプリケーションはさまざまな場所からアクセスできる必要があります。 従来のWebサイトの場合、通常、レスポンシブUIで十分ですが、より複雑なアプリケーションでは他の手法やアーキテクチャを使用する必要があります。 これらには、クライアントサイドWebアプリケーション、プログレッシブWebアプリ(PWA)、またはネイティブモバイルアプリとして実装できる、個別のRESTバックエンドアプリケーションとフロントエンドアプリケーションが含まれます。
より複雑なアプリケーションを構築するときに使用できるツールには次のものがあります。
-
React、開発者がRESTAPIバックエンド用のWebおよびネイティブフロントエンドを構築できるようにするJavaScriptフレームワーク。
-
Djangoは、model view controller (MVC)ソフトウェアアーキテクチャパターンに従う無料のオープンソースPythonWebフレームワークです。
-
Django REST framework、DjangoでRESTAPIを構築するための強力で柔軟なツールキット。
このチュートリアルでは、React、Django、およびDjango REST Frameworkを使用して、個別のREST APIバックエンドとフロントエンドを備えた最新のWebアプリケーションを構築します。 DjangoでReactを使用することで、JavaScriptとフロントエンド開発の最新の進歩の恩恵を受けることができます。 組み込みのテンプレートエンジンを使用するDjangoアプリケーションを構築する代わりに、ReactをUIライブラリとして使用し、その仮想Document Object Model(DOM)、宣言型アプローチ、およびデータの変更をすばやくレンダリングするコンポーネントを利用します。
構築するWebアプリケーションは、顧客に関するレコードをデータベースに保存し、CRMアプリケーションの開始点として使用できます。 終了すると、Bootstrap 4でスタイル設定されたReactインターフェースを使用して、レコードを作成、読み取り、更新、および削除できるようになります。
前提条件
このチュートリアルを完了するには、次のものが必要です。
-
Ubuntu 18.04を搭載した開発マシン。
-
How To Install Python 3 and Set Up a Local Programming Environment on Ubuntu 18.04の手順1と2に従って、Python 3、
pip
、およびvenv
をマシンにインストールします。 -
Node.js 6+ and
npm
5.2 or higher installed on your machine. PPAからのインストールに関するHow To Install Node.js on Ubuntu 18.04の指示に従って、両方をインストールできます。
[[step-1 -—- creating-a-python-virtual-environment-and-installing-dependencies]] ==ステップ1—Python仮想環境の作成と依存関係のインストール
このステップでは、仮想環境を作成し、Django、Django RESTフレームワーク、django-cors-headers
など、アプリケーションに必要な依存関係をインストールします。
このアプリケーションでは、DjangoとReactの2つの異なる開発サーバーを使用します。 これらは異なるポートで実行され、2つの別個のドメインとして機能します。 このため、cross-origin resource sharing (CORS)がブラウザによってブロックされることなくReactからDjangoにHTTPリクエストを送信できるようにする必要があります。
ホームディレクトリに移動し、venv
Python3モジュールを使用して仮想環境を作成します。
cd ~
python3 -m venv ./env
source
を使用して、作成した仮想環境をアクティブ化します。
source env/bin/activate
次に、プロジェクトの依存関係をpip
でインストールします。 これらには以下が含まれます。
-
Django:プロジェクトのWebフレームワーク。
-
Django REST framework:DjangoでRESTAPIを構築するサードパーティアプリケーション。
-
django-cors-headers
:CORSを有効にするパッケージ。
Djangoフレームワークをインストールします。
pip install django djangorestframework django-cors-headers
プロジェクトの依存関係をインストールしたら、DjangoプロジェクトとReactフロントエンドを作成できます。
[[step-2 -—- creating-the-django-project]] ==ステップ2—Djangoプロジェクトの作成
この手順では、次のコマンドとユーティリティを使用してDjangoプロジェクトを生成します。
-
django-admin startproject project-name
:django-admin
は、Djangoでタスクを実行するために使用されるコマンドラインユーティリティです。startproject
コマンドは、新しいDjangoプロジェクトを作成します。 -
python manage.py startapp myapp
:manage.py
は、各Djangoプロジェクトに自動的に追加されるユーティリティスクリプトであり、新しいアプリケーションの作成、データベースの移行、Djangoプロジェクトのローカルでの提供などの多くの管理タスクを実行します。 そのstartapp
コマンドは、Djangoプロジェクト内にDjangoアプリケーションを作成します。 Djangoでは、applicationという用語は、プロジェクトにいくつかの機能セットを提供するPythonパッケージを表します。
まず、django-admin startproject
を使用してDjangoプロジェクトを作成します。 プロジェクトをdjangoreactproject
と呼びます。
django-admin startproject djangoreactproject
先に進む前に、tree
コマンドを使用してDjangoプロジェクトのディレクトリ構造を見てみましょう。
[。注意]##
Tip:tree
は、コマンドラインからファイルとディレクトリの構造を表示するための便利なコマンドです。 次のコマンドでインストールできます:
sudo apt-get install tree
これを使用するには、目的のディレクトリにcd
を入力し、tree
と入力するか、開始点へのパスをtree /home/sammy/sammys-project
。
で指定します。
プロジェクトルート内のdjangoreactproject
フォルダーに移動し、tree
コマンドを実行します。
cd ~/djangoreactproject
tree
次の出力が表示されます。
Output├── djangoreactproject
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py
~/djangoreactproject
フォルダーはプロジェクトのルートです。 このフォルダー内には、作業に重要なファイルがいくつかあります。
-
manage.py
:いくつかの管理タスクを実行するユーティリティスクリプト。 -
settings.py
:プロジェクトの設定を変更できるDjangoプロジェクトのメイン構成ファイル。 これらの設定には、プロジェクトで有効なアプリケーションを指定する文字列のINSTALLED_APPS
、listなどの変数が含まれます。 Djangoのドキュメントには、available settingsに関する詳細情報があります。 -
urls.py
:このファイルには、URLパターンと関連するビューのリストが含まれています。 各パターンは、URLと、そのURLに対して呼び出す必要がある関数との間の接続をマップします。 URLとビューの詳細については、How To Create Django Viewsのチュートリアルを参照してください。
プロジェクトでの作業の最初のステップは、前のステップでインストールしたパッケージ(DjangoRESTフレームワークやDjangoCORSパッケージなど)をsettings.py
に追加して構成することです。 nano
またはお気に入りのエディターでファイルを開きます。
nano ~/djangoreactproject/djangoreactproject/settings.py
INSTALLED_APPS
設定に移動し、rest_framework
およびcorsheaders
アプリケーションをリストの一番下に追加します。
~/djangoreactproject/djangoreactproject/settings.py
...
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クラスであるmiddlewaresのリストです。
~/djangoreactproject/djangoreactproject/settings.py
...
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
で実行されるため、新しいCORS_ORIGIN_ALLOW_ALL = False
とCORS_ORIGIN_WHITELIST('localhost:3000',)
の設定をsettings.py
ファイルに追加します。 これらの設定をファイルの任意の場所に追加します。
~/djangoreactproject/djangoreactproject/settings.py
...
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = (
'localhost:3000',
)
...
django-cors-headers
docsでより多くの構成オプションを見つけることができます。
ファイルを保存し、終了したらエディターを終了します。
まだ~/djangoreactproject
ディレクトリに、customers
という新しいDjangoアプリケーションを作成します。
python manage.py startapp customers
これには、顧客を管理するためのmodelsとviewsが含まれます。 モデルはアプリケーションデータのフィールドと動作を定義し、ビューはアプリケーションがWeb要求を適切に処理し、必要な応答を返すことを可能にします。
次に、このアプリケーションをプロジェクトのsettings.py
ファイルのインストール済みアプリケーションのリストに追加して、Djangoがプロジェクトの一部として認識できるようにします。 settings.py
を再度開きます。
nano ~/djangoreactproject/djangoreactproject/settings.py
customers
アプリケーションを追加します。
~/djangoreactproject/djangoreactproject/settings.py
...
INSTALLED_APPS = [
...
'rest_framework',
'corsheaders',
'customers'
]
...
次に、データベースをmigrateし、ローカル開発サーバーを起動します。 Migrationsは、モデルに加えた変更をデータベーススキーマに伝達するDjangoの方法です。 これらの変更には、たとえば、フィールドの追加やモデルの削除などが含まれます。 モデルと移行の詳細については、How To Create Django Modelsを参照してください。
データベースを移行します。
python manage.py migrate
ローカル開発サーバーを起動します。
python manage.py runserver
次のような出力が表示されます。
OutputPerforming 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.
Webアプリケーションはhttp://127.0.0.1:8000
から実行されます。 Webブラウザでこのアドレスに移動すると、次のページが表示されます。
この時点で、アプリケーションを実行したままにして、新しいターミナルを開いてプロジェクトの開発を続けます。
[[step-3 -—- creating-the-react-frontend]] ==ステップ3—Reactフロントエンドの作成
このセクションでは、Reactを使用してプロジェクトのフロントエンドアプリケーションを作成します。
Reactには、Webpackを直接構成しなくても、Reactプロジェクトをすばやく生成できる公式ユーティリティがあります。 Webpackは、JavaScriptコード、CSS、画像などのWebアセットをバンドルするために使用されるモジュールバンドラーです。 通常、Webpackを使用する前に、さまざまな構成オプションを設定する必要がありますが、create-react-app
ユーティリティのおかげで、さらに制御が必要であると判断するまで、Webpackを直接処理する必要はありません。 create-react-app
を実行するには、npm
パッケージバイナリを実行するツールであるnpxを使用できます。
2番目のターミナルで、プロジェクトディレクトリにいることを確認します。
cd ~/djangoreactproject
create-react-app
とnpx
を使用してfrontend
というReactプロジェクトを作成します。
npx create-react-app frontend
次に、Reactアプリケーション内を移動し、開発サーバーを起動します。
cd ~/djangoreactproject/frontend
npm start
アプリケーションはhttp://localhost:3000/
から実行されます。
React開発サーバーを実行したままにして、別のターミナルウィンドウを開いて続行します。
この時点でプロジェクト全体のディレクトリ構造を確認するには、ルートフォルダに移動して、tree
を再度実行します。
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
このアプリケーションは、Bootstrap 4を使用してReactインターフェースのスタイルを設定するため、CSS設定を管理するfrontend/src/App.css
ファイルにそれを含めます。 ファイルを開きます。
nano ~/djangoreactproject/frontend/src/App.css
次のimportをファイルの先頭に追加します。 ファイルの既存のコンテンツは削除できますが、必須ではありません。
~/djangoreactproject/frontend/src/App.css
@import 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css';
ここで、@import
は、他のスタイルシートからスタイルルールをインポートするために使用されるCSS命令です。
バックエンドアプリケーションとフロントエンドアプリケーションの両方を作成したので、顧客モデルといくつかのデモデータを作成しましょう。
[[step-4 -—- creating-the-customer-model-and-initial-data]] ==ステップ4—顧客モデルと初期データの作成
DjangoアプリケーションとReactフロントエンドを作成したら、次のステップは、顧客に関する情報を保持するデータベーステーブルを表すCustomerモデルを作成することです。 DjangoObject Relational Mapper (ORM)はPythonのクラスと変数をSQLのテーブルと列にマッピングすることでデータベース操作を処理するため、SQLは必要ありません。 このようにして、Django ORMは、Pythonインターフェイスを介したデータベースとのSQL対話を抽象化します。
仮想環境を再度アクティブ化します。
cd ~
source env/bin/activate
customers
ディレクトリに移動し、アプリケーションのモデルを保持するPythonファイルであるmodels.py
を開きます。
cd ~/djangoreactproject/customers/
nano models.py
ファイルには次のコンテンツが含まれます。
~/djangoreactproject/customers/models.py
from django.db import models
# Create your models here.
from django.db import models
importステートメントのおかげで、顧客モデルのAPIはすでにファイルにインポートされています。 ここで、models.Model
を拡張するCustomer
クラスを追加します。 Djangoの各モデルは、django.db.models.Model
を拡張するPythonクラスです。
Customer
モデルには、次のデータベースフィールドがあります。
-
first_name
—顧客の名。 -
last_name
—顧客の姓。 -
email
—顧客の電子メールアドレス。 -
phone
—顧客の電話番号。 -
address
—顧客の住所。 -
description
—顧客の説明。 -
createdAt
—顧客が追加された日付。
モデルの表示方法を定義する__str__()
関数も追加します。 私たちの場合、それは顧客の名になります。 クラスの構築とオブジェクトの定義の詳細については、How To Construct Classes and Define Objects in Python 3を参照してください。
ファイルに次のコードを追加します。
~/djangoreactproject/customers/models.py
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
次のような出力が得られます。
Outputcustomers/migrations/0001_initial.py
- Create model Customer
これらの変更をデータベースに適用します。
python manage.py migrate
移行が成功したことを示す出力が表示されます。
OutputOperations to perform:
Apply all migrations: admin, auth, contenttypes, customers, sessions
Running migrations:
Applying customers.0001_initial... OK
次に、data migration fileを使用して初期顧客データを作成します。 data migration fileは、データベース内のデータを追加または変更する移行です。 customers
アプリケーション用の空のデータ移行ファイルを作成します。
python manage.py makemigrations --empty --name customers customers
移行ファイルの名前とともに次の確認が表示されます。
OutputMigrations for 'customers':
customers/migrations/0002_customers.py
移行ファイルの名前は0002_customers.py
であることに注意してください。
次に、customers
アプリケーションの移行フォルダー内に移動します。
cd ~/djangoreactproject/customers/migrations
作成された移行ファイルを開きます。
nano 0002_customers.py
これは、ファイルの最初のコンテンツです。
~/djangoreactproject/customers/migrations/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つのリストがあります。
-
dependencies
:依存する移行が含まれます。 -
operations
:移行を適用するときに実行される操作が含まれます。
次に、methodを追加して、デモの顧客データを作成します。 Migration
クラスの定義の前に、次のメソッドを追加します。
~/djangoreactproject/customers/migrations/0002_customers.py
...
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()
...
このメソッドでは、customers
アプリのCustomer
クラスを取得し、データベースに挿入するデモ顧客を作成しています。
新しい顧客の作成を可能にするCustomer
クラスを取得するには、apps
オブジェクトのget_model()
メソッドを使用します。 apps
オブジェクトは、インストールされているアプリケーションとそのデータベースモデルのregistryを表します。
apps
オブジェクトは、create_data()
を実行するために使用するときに、RunPython()
メソッドから渡されます。 migrations.RunPython()
メソッドを空のoperations
リストに追加します。
~/djangoreactproject/customers/migrations/0002_customers.py
...
operations = [
migrations.RunPython(create_data),
]
RunPython()
は、移行でカスタムPythonコードを実行できるようにするMigrationsAPIの一部です。 operations
リストは、移行を適用するときにこのメソッドが実行されることを指定しています。
これは完全なファイルです。
~/djangoreactproject/customers/migrations/0002_customers.py
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),
]
データ移行の詳細については、data migrations in Djangoに関するドキュメントを参照してください。
データベースを移行するには、まずプロジェクトのルートフォルダーに戻ります。
cd ~/djangoreactproject
データベースを移行してデモデータを作成します。
python manage.py migrate
移行を確認する出力が表示されます。
OutputOperations to perform:
Apply all migrations: admin, auth, contenttypes, customers, sessions
Running migrations:
Applying customers.0002_customers... OK
このプロセスの詳細については、How To Create Django Modelsを参照してください。
Customerモデルとデモデータを作成したら、REST APIの構築に進むことができます。
[[step-5 -—- creating-the-rest-api]] ==ステップ5— RESTAPIの作成
このステップでは、Django REST Frameworkを使用してREST APIを作成します。 いくつかの異なるAPI viewsを作成します。 APIビューはAPIリクエストまたは呼び出しを処理する関数であり、API endpointはRESTシステムとのタッチポイントを表す一意のURLです。 たとえば、ユーザーがAPIエンドポイントにGETリクエストを送信すると、Djangoは対応する関数またはAPIビューを呼び出してリクエストを処理し、可能な結果を返します。
serializersも使用します。 Django RESTフレームワークのserializerを使用すると、複雑なモデルインスタンスとQuerySetをAPIで使用するためにJSON形式に変換できます。 シリアライザークラスは、データを解析してDjangoモデルとQuerySetsに逆シリアル化するメカニズムを提供する、別の方向でも機能します。
APIエンドポイントには次のものが含まれます。
-
api/customers
:このエンドポイントは、顧客を作成し、ページ付けされた顧客のセットを返すために使用されます。 -
api/customers/<pk>
:このエンドポイントは、主キーまたはIDによって単一の顧客を取得、更新、および削除するために使用されます。
また、プロジェクトのurls.py
ファイルに対応するエンドポイント(つまり、api/customers
とapi/customers/<pk>
)のURLを作成します。
Customer
モデルのserializer classを作成することから始めましょう。
Serializerクラスの追加
顧客インスタンスとQuerySetをJSONとの間で変換するには、Customer
モデルのシリアライザークラスを作成する必要があります。 シリアライザークラスを作成するには、最初にcustomers
アプリケーション内にserializers.py
ファイルを作成します。
cd ~/djangoreactproject/customers/
nano serializers.py
次のコードを追加して、シリアライザーAPIとCustomer
モデルをインポートします。
~/djangoreactproject/customers/serializers.py
from rest_framework import serializers
from .models import Customer
次に、serializers.ModelSerializer
を拡張し、シリアル化されるフィールドを指定するシリアライザークラスを作成します。
~/djangoreactproject/customers/serializers.py
...
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
。
これは、ファイルの完全なコンテンツです。
~/djangoreactproject/customers/serializers.py
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ビューを作成します。
~/djangoreactproject/customers/views.py
を開きます:
nano ~/djangoreactproject/customers/views.py
そこにあるものを削除し、次のインポートを追加します。
~/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 *
作成したシリアライザーを、Customer
モデルとDjangoおよびDjango RESTフレームワークAPIとともにインポートします。
次に、POSTおよびGET HTTP要求を処理するためのビューを追加します。
~/djangoreactproject/customers/views.py
...
@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ビューを作成します。 decoratorは、別の関数を受け取り、それを動的に拡張する関数です。
メソッド本体では、request.method
変数を使用して、現在のHTTPメソッドをチェックし、リクエストタイプに応じて対応するロジックを実行します。
-
GETリクエストの場合、メソッドはDjangoPaginatorを使用してデータをページ分割し、シリアル化後のデータの最初のページ、利用可能な顧客の数、利用可能なページの数、前のページと次のページへのリンクを返します。 Paginatorは、データのリストをページにページ分割し、各ページのアイテムにアクセスするメソッドを提供する組み込みのDjangoクラスです。
-
POSTリクエストの場合、このメソッドは受信した顧客データをシリアル化してから、シリアライザーオブジェクトの
save()
メソッドを呼び出します。 次に、201ステータスコードを持つHttpResponseのインスタンスであるResponseオブジェクトを返します。 作成する各ビューは、HttpResponse
オブジェクトを取得する責任があります。save()
メソッドは、シリアル化されたデータをデータベースに保存します。
HttpResponse
とビューの詳細については、このcreating view functionsの説明を参照してください。
次に、pk
(主キー)による顧客の取得、更新、および削除のためのGET、PUT、およびDELETE要求の処理を担当するAPIビューを追加します。
~/djangoreactproject/customers/views.py
...
@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_view(['GET', 'PUT', 'DELETE'])
で装飾されており、GET、PUT、およびDELETEリクエストを受け入れることができるAPIビューであることを示しています。
request.method
フィールドのチェックは、要求メソッドを検証し、その値に応じて適切なロジックを呼び出します。
-
GETリクエストの場合、顧客データはResponseオブジェクトを使用してシリアル化されて送信されます。
-
PUTリクエストの場合、メソッドは新しい顧客データのシリアライザーを作成します。 次に、作成されたシリアライザオブジェクトの
save()
メソッドを呼び出します。 最後に、更新された顧客とともにResponseオブジェクトを送信します。 -
DELETEリクエストの場合、メソッドは顧客オブジェクトの
delete()
メソッドを呼び出して削除し、データのないResponseオブジェクトを返します。
完成したファイルは次のようになります。
~/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 *
@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>
は単一の顧客をpk
で取得、更新、または削除するためのものです。
~/djangoreactproject/djangoreactproject/urls.py
を開きます:
nano ~/djangoreactproject/djangoreactproject/urls.py
そこにあるものは残しますが、ファイルの先頭にあるcustomers
ビューにインポートを追加します。
~/djangoreactproject/djangoreactproject/urls.py
from django.contrib import admin
from django.urls import path
from customers import views
from django.conf.urls import url
次に、api/customers/
とapi/customers/<pk>
のURLをアプリケーションのURLを含むurlpatterns
listに追加します。
~/djangoreactproject/djangoreactproject/urls.py
...
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^api/customers/$', views.customers_list),
url(r'^api/customers/(?P[0-9]+)$', views.customers_detail),
]
RESTエンドポイントを作成したら、それらを使用する方法を見てみましょう。
[[step-6 -—- sumption-the-rest-api-with-axios]] ==ステップ6—AxiosでRESTAPIを使用する
このステップでは、API呼び出しを行うために使用するHTTPクライアントであるAxiosをインストールします。 また、作成したAPIエンドポイントを使用するクラスを作成します。
まず、仮想環境を非アクティブ化します。
deactivate
次に、frontend
フォルダーに移動します。
cd ~/djangoreactproject/frontend
以下を使用して、npm
からaxios
をインストールします。
npm install axios --save
--save
オプションは、axios
依存関係をアプリケーションのpackage.json
ファイルに追加します。
次に、CustomersService.js
というJavaScriptファイルを作成します。このファイルには、RESTAPIを呼び出すためのコードが含まれています。 これは、プロジェクトのアプリケーションコードが存在するsrc
フォルダー内に作成します。
cd src
nano CustomersService.js
Django REST APIに接続するメソッドを含む次のコードを追加します。
~/djangoreactproject/frontend/src/CustomersService.js
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
コンポーネントを作成することで、APIからのデータをReactUIインターフェースに表示できるようになりました。
[[step-7 --- displaying-data-from-the-api-in-the-react-application]] ==ステップ7—ReactアプリケーションでAPIからのデータを表示する
このステップでは、CustomersList
Reactcomponentを作成します。 ReactコンポーネントはUIの一部を表します。また、UIを独立した再利用可能な部分に分割できます。
frontend/src
にCustomersList.js
を作成することから始めます。
nano ~/djangoreactproject/frontend/src/CustomersList.js
React
とComponent
をインポートして、Reactコンポーネントを作成することから始めます。
~/djangoreactproject/frontend/src/CustomersList.js
import React, { Component } from 'react';
次に、前の手順で作成したCustomersService
モジュールをインポートしてインスタンス化します。これにより、RESTAPIバックエンドとインターフェイスするメソッドが提供されます。
~/djangoreactproject/frontend/src/CustomersList.js
...
import CustomersService from './CustomersService';
const customersService = new CustomersService();
次に、Component
を拡張してREST APIを呼び出すCustomersList
コンポーネントを作成します。 Reactコンポーネントはextend or subclass the Component
classである必要があります。 E6クラスと継承の詳細については、Understanding Classes in JavaScriptに関するチュートリアルを参照してください。
次のコードを追加して、react.Component
を拡張するReactコンポーネントを作成します。
~/djangoreactproject/frontend/src/CustomersList.js
...
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;
constructor内で、state
オブジェクトを初期化しています。 これは、空のcustomers
arrayを使用してコンポーネントの状態変数を保持します。 この配列は、顧客と、バックエンドAPIから取得する次のページのURLを保持するnextPageURL
を保持します。 また、binding、nextPage()
、handleDelete()
methodsからthis
であるため、HTMLコードからアクセスできます。
次に、中括弧を閉じる前に、componentDidMount()
メソッドとCustomersList
クラス内のgetCustomers()
の呼び出しを追加します。
componentDidMount()
メソッドは、コンポーネントが作成されてDOMに挿入されるときに呼び出されるコンポーネントのライフサイクルメソッドです。 getCustomers()
は、Customers Serviceオブジェクトを呼び出して、データの最初のページと次のページのリンクをDjangoバックエンドから取得します。
~/djangoreactproject/frontend/src/CustomersList.js
...
componentDidMount() {
var self = this;
customersService.getCustomers().then(function (result) {
self.setState({ customers: result.data, nextPageURL: result.nextlink})
});
}
次に、顧客の削除を処理するhandleDelete()
メソッドをcomponentDidMount()
の下に追加します。
~/djangoreactproject/frontend/src/CustomersList.js
...
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
(主キー)を使用して顧客を削除します。 操作が成功すると、削除された顧客のcustomers
配列が除外されます。
次に、nextPage()
メソッドを追加して次のページのデータを取得し、次のページのリンクを更新します。
~/djangoreactproject/frontend/src/CustomersList.js
...
nextPage(){
var self = this;
customersService.getCustomersByURL(this.state.nextPageURL).then((result) => {
self.setState({ customers: result.data, nextPageURL: result.nextlink})
});
}
nextPage()
メソッドはgetCustomersByURL()
メソッドを呼び出します。このメソッドは、状態オブジェクトthis.state.nextPageURL
から次のページのURLを取得し、返されたデータでcustomers
配列を更新します。
最後に、コンポーネントrender()
methodを追加します。これにより、コンポーネントの状態から顧客のテーブルがレンダリングされます。
~/djangoreactproject/frontend/src/CustomersList.js
...
render() {
return (
#
First Name
Last Name
Phone
Email
Address
Description
Actions
{this.state.customers.map( c =>
{c.pk}
{c.first_name}
{c.last_name}
{c.phone}
{c.email}
{c.address}
{c.description}
Update
)}
);
}
これは、ファイルの完全なコンテンツです。
~/djangoreactproject/frontend/src/CustomersList.js
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 (
#
First Name
Last Name
Phone
Email
Address
Description
Actions
{this.state.customers.map( c =>
{c.pk}
{c.first_name}
{c.last_name}
{c.phone}
{c.email}
{c.address}
{c.description}
Update
)}
);
}
}
export default CustomersList;
顧客のリストを表示するためのCustomersList
コンポーネントを作成したので、顧客の作成と更新を処理するコンポーネントを追加できます。
[[step-8 -—- adding-the-customer-create-and-update-react-component]] ==ステップ8—顧客のCreate and UpdateReactコンポーネントの追加
このステップでは、顧客の作成と更新を処理するCustomerCreateUpdate
コンポーネントを作成します。 これは、ユーザーが新しい顧客に関するデータを入力するか、既存のエントリを更新するために使用できるフォームを提供することでこれを行います。
frontend/src
で、CustomerCreateUpdate.js
ファイルを作成します。
nano ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
次のコードを追加して、React
とComponent
をインポートしてReactコンポーネントを作成します。
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
import React, { Component } from 'react';
前の手順で作成したCustomersService
クラスをインポートしてインスタンス化することもできます。これにより、RESTAPIバックエンドとインターフェイスするメソッドが提供されます。
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
...
import CustomersService from './CustomersService';
const customersService = new CustomersService();
次に、Component
を拡張して顧客を作成および更新するCustomerCreateUpdate
コンポーネントを作成します。
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
...
class CustomerCreateUpdate extends Component {
constructor(props) {
super(props);
}
}
export default CustomerCreateUpdate;
クラス定義内に、コンポーネントのrender()
メソッドを追加します。これにより、顧客に関する情報を取得するHTMLフォームがレンダリングされます。
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
...
render() {
return (
);
}
このメソッドは、フォーム入力要素ごとに、ref
プロパティを追加して、フォーム要素の値にアクセスして設定します。
次に、render()
メソッドの上に、handleSubmit(event)
メソッドを定義して、ユーザーが送信ボタンをクリックしたときに適切な機能が得られるようにします。
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
...
handleSubmit(event) {
const { match: { params } } = this.props;
if(params && params.pk){
this.handleUpdate(params.pk);
}
else
{
this.handleCreate();
}
event.preventDefault();
}
...
handleSubmit(event)
メソッドはフォームの送信を処理し、ルートに応じて、handleUpdate(pk)
メソッドを呼び出して、渡されたpk
で顧客を更新するか、handleCreate()
メソッドを呼び出して作成します。新規顧客。 これらのメソッドをすぐに定義します。
コンポーネントコンストラクターに戻り、新しく追加されたhandleSubmit()
メソッドをthis
にバインドして、フォームでアクセスできるようにします。
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
...
class CustomerCreateUpdate extends Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
...
次に、handleCreate()
メソッドを定義して、フォームデータから顧客を作成します。 handleSubmit(event)
メソッドの上に、次のコードを追加します。
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
...
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)
メソッドを定義します。
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
...
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()
メソッドは、顧客情報フォームの新しい情報を使用して、pk
で顧客を更新します。 customersService.updateCustomer()
メソッドを呼び出します。
次に、componentDidMount()
メソッドを追加します。 ユーザーがcustomer/:pk
ルートにアクセスした場合、URLの主キーを使用して、顧客に関連する情報をフォームに入力します。 これを行うには、コンポーネントがcomponentDidMount()
のライフサイクルイベントにマウントされた後に、getCustomer(pk)
メソッドを追加できます。 このメソッドを追加するには、コンポーネントコンストラクターの下に次のコードを追加します。
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
...
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;
})
}
}
これは、ファイルの完全なコンテンツです。
~/djangoreactproject/frontend/src/CustomerCreateUpdate.js
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 (
);
}
}
export default CustomerCreateUpdate;
CustomerCreateUpdate
コンポーネントを作成したら、メインのApp
コンポーネントを更新して、作成したさまざまなコンポーネントへのリンクを追加できます。
[[step-9 -—- updating-the-main-app-component]] ==ステップ9—メインアプリコンポーネントの更新
このセクションでは、アプリケーションのApp
コンポーネントを更新して、前の手順で作成したコンポーネントへのリンクを作成します。
frontend
フォルダーから、次のコマンドを実行してReact Routerをインストールします。これにより、さまざまなReactコンポーネント間にルーティングとナビゲーションを追加できます。
cd ~/djangoreactproject/frontend
npm install --save react-router-dom
次に、~/djangoreactproject/frontend/src/App.js
を開きます。
nano ~/djangoreactproject/frontend/src/App.js
そこにあるものをすべて削除し、次のコードを追加して、ルーティングの追加に必要なクラスをインポートします。 これらには、ルーターコンポーネントを作成するBrowserRouter
、およびルートコンポーネントを作成するRoute
が含まれます。
~/djangoreactproject/frontend/src/App.js
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 history APIを使用してUIをURLと同期させます。
次に、BrowserRouter
コンポーネントによってラップされる基本コンポーネントを提供する基本レイアウトを作成します。
~/djangoreactproject/frontend/src/App.js
...
const BaseLayout = () => (
)
Route
コンポーネントを使用して、アプリケーションのルートを定義します。一致するものが見つかったら、ルーターがロードする必要のあるコンポーネント。 各ルートには、照合するパスを指定するためのpath
と、ロードするコンポーネントを指定するためのcomponent
が必要です。 exact
プロパティは、ルーターに正確なパスに一致するように指示します。
最後に、ReactアプリケーションのルートまたはトップレベルコンポーネントであるApp
コンポーネントを作成します。
~/djangoreactproject/frontend/src/App.js
...
class App extends Component {
render() {
return (
);
}
}
export default App;
アプリはブラウザで実行することを目的としているため、BaseLayout
コンポーネントをBrowserRouter
コンポーネントでラップしました。
完成したファイルは次のようになります。
~/djangoreactproject/frontend/src/App.js
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 = () => (
)
class App extends Component {
render() {
return (
);
}
}
export default App;
アプリケーションにルーティングを追加したら、アプリケーションをテストする準備ができました。 http://localhost:3000
に移動します。 アプリケーションの最初のページが表示されるはずです。
このアプリケーションを配置すると、CRMアプリケーションのベースができました。
結論
このチュートリアルでは、DjangoとReactを使用してデモアプリケーションを作成しました。 Django RESTフレームワークを使用してREST APIを作成し、Axiosを使用してAPIを使用し、Bootstrap 4を使用してCSSをスタイルしました。 このプロジェクトのソースコードは、このGitHub repositoryにあります。
このチュートリアルのセットアップでは、フロントエンドアプリとバックエンドアプリを別々に使用しました。 ReactをDjangoと統合する別のアプローチについては、このtutorialとこのtutorialを確認してください。
Djangoを使用してアプリケーションを構築する方法の詳細については、Django development seriesをたどることができます。 official Django docsも確認できます。