如何在 Ubuntu 18.04 上使用 Django 和 React 构建用于客户信息管理的现代化 Web 应用程序

0 股票
0
0
0
0

介绍

人们使用各种设备连接互联网并浏览网页。因此,应用程序需要能够从各种位置访问。对于传统网站而言,响应式用户界面通常就足够了,但更复杂的应用程序往往需要使用其他技术和架构。这些技术和架构包括使用独立的后端和前端 REST 应用程序,这些应用程序可以作为客户端 Web 应用程序、渐进式 Web 应用程序 (PWA) 或原生移动应用程序运行。.

构建更复杂的应用程序时,您可以使用的一些工具包括:

  • React 是一个 JavaScript 框架,它允许开发人员为其 REST API 后端构建 Web 和原生页面。.
  • Django 是一个免费开源的 Python Web 框架,它遵循模型-视图-控制器 (MVC) 软件架构模式。.
  • Django REST Framework 是一个功能强大且灵活的工具包,用于在 Django 中构建 REST API。.

在本教程中,您将使用 React、Django 和 Django REST Framework 构建一个具有独立 REST API 后端和前端的现代 Web 应用程序。通过将 React 与 Django 结合使用,您可以充分利用 JavaScript 和前端开发的最新进展。您将不再构建使用内置模板引擎的 Django 应用程序,而是将 React 用作 UI 库,它采用虚拟文档对象模型 (DOM)、声明式方法以及能够快速渲染数据更改的组件。.

你即将构建的 Web 应用程序会将客户记录存储在数据库中,你可以将其作为 CRM 应用程序的起点。完成后,你可以使用基于 Bootstrap 4 样式的 React 界面来读取、更新和删除数据。.

先决条件

要完成本教程,您需要:

  • 一台运行Ubuntu 18.04的开发机。.
  • 按照“如何在 Ubuntu 18.04 上安装 Python 3 并设置本地开发环境”中的步骤 1 和 2,即可在您的机器上安装 Python 3、pip 和 venv。.
  • 您的计算机上已安装 Node.js 6+ 和 npm 5.2 或更高版本。您可以按照“如何在 Ubuntu 18.04 上安装 Node.js(从 PPA 安装)”中的说明安装它们。.

步骤 1 – 创建 Python 虚拟环境并安装依赖项

在此步骤中,我们将创建一个虚拟环境,并安装应用程序所需的依赖项,包括 Django、Django REST framework 和 django-cors-headers。.

我们的应用程序将使用两个不同的开发服务器分别用于 Django 和 React。它们将运行在不同的端口上,并作为两个独立的域名运行。因此,我们需要启用跨资源共享 (CORS),以便 React 可以向 Django 发送 HTTP 请求而不会被浏览器阻止。.

进入你的用户主目录,使用 Python 3 的 venv 模块创建一个虚拟环境:

cd ~
python3 -m venv ./env

使用以下源激活已创建的虚拟环境:

source env/bin/activate

接下来,使用 pip 安装项目依赖项。这些依赖项包括以下内容:

  • Django:该项目的 Web 框架。.
  • Django REST Framework:一个使用 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 framework 和 Django CORS 包,方法是将它们添加到 settings.py 文件中。使用 nano 或您喜欢的编辑器打开该文件:

nano ~/djangoreactproject/djangoreactproject/settings.py

转到 INSTALLED_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 配置中。此配置是一个中间件列表,中间件是一个 Python 类,其中包含每次 Web 应用程序发出请求或响应时都会处理的代码:

...
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` 文件中。您可以将这些设置添加到文件中的任意位置:

...
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.

您的 Web 应用程序将在 http://127.0.0.1:8000 运行。如果您在 Web 浏览器中访问此地址,您应该会看到以下页面:

此时,保持程序运行,打开一个新的终端继续开发项目。.

步骤 3 – 创建 React 前端

在本节中,我们将使用 React 创建项目的前端应用程序。.

React 官方提供了一个工具,可以让你快速生成 React 项目,而无需直接配置 Webpack。Webpack 是一个模块打包器,用于打包 Web 资源,例如 JavaScript 代码、CSS 和图像。通常,你需要在使用 Webpack 之前设置各种配置选项,但借助 Create-react-app 工具,除非你需要更多控制权,否则无需直接处理 Webpack。要运行 Create-react-app,你可以使用 npx,这是一个运行 npm 打包的二进制文件的工具。.

在第二个终端中,请确保您位于项目目录中:

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 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css';

这里,@import 是一个 CSS 指令,用于从其他样式表导入样式规则。.

现在我们已经创建了后端和前端应用程序,接下来让我们创建客户模型和一些演示数据。.

步骤 4 – 创建客户模型和初始数据

创建完 Django 应用和 React 实例后,下一步是创建客户模型,它代表存储客户信息的数据库表。您无需编写任何 SQL 代码,因为 Django 对象关系映射器 (ORM) 通过将 Python 类和变量映射到 SQL 表和列来执行数据库操作。这样,Django ORM 通过 Python 接口抽象了与数据库的 SQL 交互。.

重新启用您的虚拟环境:

cd ~
source env/bin/activate

进入 clients 目录并打开 models.py 文件,这是一个包含应用程序模型的 Python 文件:

cd ~/djangoreactproject/customers/
nano models.py

文件将包含以下内容:

from django.db import models
# Create your models here.

由于使用了 `import models from django.db` 语句,Customer 模型 API 已经包含在文件中。现在,您需要添加继承自 `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

接下来,您将使用数据传输文件创建初始客户数据。数据传输文件是一种迁移文件,用于向数据库添加或更改数据。请为“客户”应用程序创建一个空的数据传输文件:

python manage.py makemigrations --empty --name customers customers

您将看到以下确认信息,其中包含您的迁移文件的名称:

Output
Migrations for 'customers':
customers/migrations/0002_customers.py

请注意,您的迁移文件的名称是 0002_customers.py。.

接下来,导航到客户端应用程序的 migrations 文件夹:

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 导入 Migrations API,这是一个用于创建迁移的 Django API。django.db 是一个内置包,其中包含用于操作数据库的类。.

Migration 类是一个 Python 类,用于描述数据库迁移时执行的操作。它继承自 migrations.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() 是迁移 API 的一部分,允许您在迁移中运行自定义 Python 代码。我们的操作列表指定此方法将在应用迁移时执行。.

以下是完整文件:

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 端点则是一个唯一的 URL,代表与 REST 系统的交互点。例如,当用户向 API 端点发送 GET 请求时,Django 将调用相应的函数或 API 视图来处理该请求并返回可能的结果。.

我们还会用到序列化器。Django REST 框架中的序列化器可以将复杂的模型实例和查询集转换为 JSON 格式,以便 API 调用。序列化器类还可以反向工作,提供解析和分离 Django 模型和查询集中数据的机制。.

我们的 API 接口将包括:

  • api/customers:此端点用于创建客户并返回分页的客户集合。.
  • api/customers/此端点用于通过主键或 ID 获取、更新和删除单个客户。.

我们还在项目的 urls.py 文件中为相关的端点创建 URL(例如 api/customers 和 api/customers/)。 )。.

我们先来为客户端模型创建序列化器类。.

添加一个序列化器类

为 Customer 模型创建序列化器类对于在 JSON 和 Customer 实例与 QuerySet 之间进行转换至关重要。要创建序列化器类,首先需要在 Customers 应用程序中创建一个 serializers.py 文件:

cd ~/djangoreactproject/customers/
nano serializers.py

添加以下代码以导入 API 序列号和客户端模型:

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 视图

在本节中,我们将为我们的应用程序创建 API 视图,当用户访问与视图函数对应的端点时,Django 将调用这些视图。.

~/djangoreactproject/customers/views.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()` 方法。之后,它会返回一个 Response 对象(HttpResponse 的实例),状态码为 201。您创建的每个配置文件都负责返回一个 HttpResponse 对象。`save()` 方法会将序列化的数据保存到数据库中。.

有关 HttpResponse 和视图的更多信息,请参阅有关创建视图函数的讨论。.

现在添加 API 视图,该视图负责处理 GET、PUT 和 DELETE 请求,以便通过主键 (pk) 获取、更新和删除客户:

...
@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() 方法会调用客户端对象的 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/通过主键获取、更新或删除单个客户。.

打开 ~/djangoreactproject/djangoreactproject/urls.py:

nano ~/djangoreactproject/djangoreactproject/urls.py

保留现有内容,但在文件顶部的“客户”视图中添加导入语句:

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

在这一步中,我们将安装 Axios,这是我们用来发起 API 调用的 HTTP 客户端。我们还将创建一个类来使用我们创建的 API 端点。.

首先,停用您的虚拟环境:

deactivate

然后进入你的前端文件夹:

cd ~/djangoreactproject/frontend

使用以下命令从 npm 安装 axios:

npm install axios --save

--save 选项会将 axios 依赖项添加到应用程序的 package.json 文件中。.

接下来,创建一个名为 CustomersService.js 的 JavaScript 文件,其中包含调用 REST API 的代码。我们将在 src 文件夹中创建此文件,该文件夹是我们项目应用程序代码所在的位置:

cd src
nano CustomersService.js

添加以下代码,其中包含连接到 Django 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();

接下来,创建一个名为 CustomersList 的组件,该组件继承自 Component 类以调用 REST API。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;

在构造函数中,我们初始化状态对象。该对象使用一个空的客户数组来保存组件的状态变量。该数组包含客户列表和 `nextPageURL`,后者保存着要从后端 API 获取的下一页的 URL。我们还将 `nextPage()` 和 `handleDelete()` 方法附加到该对象,以便可以从 HTML 代码中访问它们。.

接下来,在 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})
});
}

现在在 componentDidMount() 下方添加 handleDelete() 方法,该方法用于处理客户端删除操作:

...
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() 方法来获取下一页的数据并更新下一页链接:

...
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() 方法,该方法会根据组件的状态渲染一个客户表格:

...
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 创建组件并更新客户端

在此步骤中,我们将创建 CustomerCreateUpdate 组件,该组件负责创建和更新客户信息。它通过提供一个表单来实现这一点,用户可以使用该表单输入新的客户数据或更新现有条目。.

在 frontend/src 目录下,创建 CustomerCreateUpdate.js 文件:

nano ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

添加以下代码,通过导入 React 和 Component 来创建 React 组件:

import React, { Component } from 'react';

我们还可以导入并实例化上一步创建的 CustomersService 类,该类提供了与后端 REST API 通信的方法:

...
import CustomersService from './CustomersService';

const customersService = new CustomersService();

接下来,创建一个继承自 Component 的 CustomerCreateUpdate 组件,用于创建和更新客户信息:

...
class CustomerCreateUpdate extends Component {

constructor(props) {
super(props);
}
}
export default CustomerCreateUpdate;

在类定义中,添加组件的 render() 方法,该方法会渲染一个 HTML 表单来收集客户信息:

...
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)` 方法处理表单提交,并根据路由的不同,调用 `handleUpdate(pk)` 方法以使用传入的 pk 值更新客户端,或调用 `handleCreate()` 方法创建新客户端。我们稍后将定义这些方法。.

回到组件构造函数中,将新添加的 handleSubmit() 方法链接到 this,以便您可以在表单中访问它:

...
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

删除所有现有项,并添加以下代码以导入必要的类来添加路由功能。这些类包括 BrowserRouter(用于创建 Router 组件)和 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 history 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 组件来定义应用程序路由。路由器会在找到匹配项时立即加载该组件。每个路由都需要一个路由参数来指定要匹配的路由,以及一个组件参数来指定要匹配的组件。exact 属性指示路由器精确匹配路由。.

最后,创建 App 组件,它是我们 React 应用程序的主要组件或顶级组件:

...
class App extends Component {
render() {
return (
<BrowserRouter>
<BaseLayout/>
</BrowserRouter>
);
}
}
export default App;

我们使用 BrowserRouter 组件包裹了 BaseLayout 组件,因为我们的应用程序将在浏览器中运行。.

最终文件如下所示:

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 创建了一个演示应用程序。您使用 Django REST framework 构建了 REST API,使用 Axios 调用 API,并使用 Bootstrap 4 实现 CSS 样式。您可以在此 GitHub 仓库中找到该项目的源代码。.

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

您可能也喜欢

VPN自动断开连接软件

什么是 VPN 自动断开连接软件?VPN 自动断开连接软件是一种高级安全措施,它可以……