如何在 Ubuntu 18.04 上使用 Django 和 React 构建现代网络应用程序来管理客户信息

作者选择Open Sourcing Mental Illness Ltd作为Write for DOnations计划的一部分接受捐赠。

简介

人们使用不同类型的设备连接互联网和浏览网页。因此,应用程序需要能够从不同位置访问。对于传统网站来说,有一个响应式用户界面通常就足够了,但更复杂的应用程序往往需要使用其他技术和架构。这包括拥有独立的 REST 后端和前端应用程序,这些应用程序可以作为客户端网络应用程序、渐进式网络应用程序(PWA)或本地移动应用程序来实现。

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

在本教程中,您将使用 React、Django 和 Django REST 框架构建一个具有独立 REST API 后端和前端的现代 Web 应用程序。通过将 React 与 Django 结合使用,您将能够从 JavaScript 和前端开发的最新进展中获益。与使用内置模板引擎构建 Django 应用程序不同,您将使用 React 作为 UI 库,充分利用其虚拟文档对象模型 (DOM)、声明式方法和可快速呈现数据变化的组件。

您要创建的网络应用程序会在数据库中存储客户记录,您可以将其作为客户关系管理应用程序的起点。完成后,您就可以使用采用 Bootstrap 4 设计的 React 界面来创建、读取、更新和删除记录。

先决条件

要完成本教程,您需要

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

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

我们的应用程序将为 Django 和 React 使用两个不同的开发服务器。它们将运行在不同的端口上,并作为两个独立的域运行。因此,我们需要启用cross-origin resource sharing (CORS) 从 React 向 Django 发送 HTTP 请求,而不会被浏览器阻止。

导航至主目录,使用 venv Python 3 模块创建虚拟环境:

1cd ~
2python3 -m venv ./env

使用 source 激活创建的虚拟环境:

1source env/bin/activate

接下来,使用 pip 安装项目的依赖项。其中包括

Django :项目的网络框架。 Django REST 框架 :使用 Django 构建 REST API 的第三方应用程序。 django-cors-headers :启用 CORS 的软件包。

安装 Django 框架:

1pip install django djangorestframework django-cors-headers

安装好项目依赖项后,就可以创建 Django 项目和 React 前端了。

第 2 步 - 创建 Django 项目

在这一步中,我们将使用以下命令和实用程序生成 Django 项目:

django-admin startproject project-namedjango-admin是用于完成 Django 任务的命令行工具。startproject "命令创建一个新的 Django 项目。 python manage.py startapp myapp :manage.py "是一个自动添加到每个 Django 项目中的实用脚本,用于执行一系列管理任务:创建新应用程序、迁移数据库以及为本地 Django 项目提供服务。它的 startapp 命令会在 Django 项目中创建一个 Django 应用程序。在 Django 中,术语 application 描述了一个 Python 包,它在项目中提供了一些功能。

首先,使用 django-admin startproject 创建 Django 项目。我们将把项目命名为 djangoreactproject

1django-admin startproject djangoreactproject

在继续之前,让我们使用 tree 命令查看一下 Django 项目的目录结构。

<$>[注] 提示: tree 是一个非常有用的命令,可以从命令行查看文件和目录结构。你可以用以下命令安装它:

1sudo apt-get install tree

要使用它,请 cd 进入所需目录并键入 tree 或使用 tree /home/sammy/sammys-project 提供起点路径。 <$>

导航至项目根目录下的 djangoreactproject 文件夹,然后运行 tree 命令:

1cd ~/djangoreactproject
2tree

您将看到以下输出:

1[secondary_label Output]
2├── djangoreactproject
3│   ├── __init__.py
4│   ├── settings.py
5│   ├── urls.py
6│   └── wsgi.py
7└── manage.py

djangoreactproject` 文件夹是项目的根目录。在这个文件夹中,有几个文件对你的工作很重要:

manage.py :执行一系列管理任务的实用脚本。 settings.py :Django 项目的主要配置文件,您可以在此修改项目设置。这些设置包括诸如 INSTALLED_APPPS之类的变量,这是一个指定项目启用应用程序的字符串list。Django 文档中有更多关于可用设置的信息。 urls.py :该文件包含 URL 模式和相关视图的列表。每个模式都映射了 URL 与该 URL 应调用的函数之间的连接。有关 URL 和视图的更多信息,请参阅我们的教程如何创建 Django 视图

使用项目的第一步是配置上一步安装的软件包,包括 Django REST 框架和 Django CORS 软件包,将它们添加到 settings.py 中。用 nano 或你喜欢的编辑器打开该文件:

1nano ~/djangoreactproject/djangoreactproject/settings.py

导航至 INSTALLED_APPS 设置,将 rest_frameworkcorsheaders 应用程序添加到列表底部:

 1[label ~/djangoreactproject/djangoreactproject/settings.py]
 2...
 3INSTALLED_APPS = [
 4    'django.contrib.admin',
 5    'django.contrib.auth',
 6    'django.contrib.contenttypes',
 7    'django.contrib.sessions',
 8    'django.contrib.messages',
 9    'django.contrib.staticfiles',
10    'rest_framework',
11    'corsheaders'
12]

接下来,将先前安装的 CORS 软件包中的 corsheaders.middleware.CorsMiddleware 中间件添加到 MIDDLEWARE 设置中。该设置是 middlewares 的列表,这是一个 Python 类,包含每次网络应用程序处理请求或响应时处理的代码:

1[label ~/djangoreactproject/djangoreactproject/settings.py]
2...
3
4MIDDLEWARE = [
5...
6'django.contrib.messages.middleware.MessageMiddleware',
7'django.middleware.clickjacking.XFrameOptionsMiddleware',
8'corsheaders.middleware.CorsMiddleware'
9]

接下来,您可以启用 CORS。CORS_ORIGIN_ALLOW_ALL "设置指定是否允许所有域的 CORS,而 "CORS_ORIGIN_WHITELIST "是一个 Python 元组,包含允许的 URL。在我们的例子中,由于 React 开发服务器将在 http://localhost:3000 上运行,我们将在 settings.py 文件中添加新的 CORS_ORIGIN_ALLOW_ALL = FalseCORS_ORIGIN_WHITELIST('localhost:3000',) 设置。将这些设置添加到文件中的任意位置:

1[label ~/djangoreactproject/djangoreactproject/settings.py]
2
3...
4CORS_ORIGIN_ALLOW_ALL = False
5
6CORS_ORIGIN_WHITELIST = (
7       'localhost:3000',
8)
9...

您可以在 django-cors-headers文档 中找到更多配置选项。

完成后保存文件并退出编辑器。

还是在 ~/djangoreactproject 目录中,新建一个名为 customers 的 Django 应用程序:

1python manage.py startapp customers

这将包含管理客户的 模型视图。模型定义了应用程序数据的字段和行为,而视图则使我们的应用程序能够正确处理网络请求并返回所需的响应。

接下来,将此应用程序添加到项目的 settings.py 文件的已安装应用程序列表中,以便 Django 将其识别为项目的一部分。再次打开 settings.py

1nano ~/djangoreactproject/djangoreactproject/settings.py

添加 "客户 "应用程序:

1[label ~/djangoreactproject/djangoreactproject/settings.py]
2...
3INSTALLED_APPS = [
4    ...
5    'rest_framework',
6    'corsheaders',
7    'customers'
8]
9...

接下来,迁移数据库并启动本地开发服务器。迁移 是 Django 将对模型所做的更改传播到数据库模式的方式。这些更改包括添加字段或删除模型等。有关模型和迁移的更多信息,请参阅 如何创建 Django 模型

迁移数据库:

1python manage.py migrate

启动本地开发服务器:

1python manage.py runserver

您将看到类似下面的输出:

1[secondary_label Output]
2Performing system checks...
3
4System check identified no issues (0 silenced).
5October 22, 2018 - 15:14:50
6Django version 2.1.2, using settings 'djangoreactproject.settings'
7Starting development server at http://127.0.0.1:8000/
8Quit the server with CONTROL-C.

您的网络应用程序将从 http://127.0.0.1:8000运行。如果您在浏览器中导航到该地址,应该会看到以下页面:

Django演示页面](assets/django_react_1604/django_home.png)

此时,请不要运行应用程序,打开一个新的终端继续开发项目。

第 3 步 - 创建 React 前端

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

React 有一个官方工具,可以让您快速生成 React 项目,而无需直接配置 Webpack。Webpack 是一个模块捆绑工具,用于捆绑 JavaScript 代码、CSS 和图片等网络资产。通常情况下,在使用 Webpack 之前,您需要设置各种配置选项,但由于有了 create-react-app 实用程序,在您决定需要更多控制之前,您不必直接与 Webpack 打交道。要运行 create-react-app,可以使用 npx,这是一个执行 npm 软件包二进制文件的工具。

在第二个终端中,确保已进入项目目录:

1[environment second]
2cd ~/djangoreactproject

使用 create-react-appnpx 创建名为 frontend 的 React 项目:

1[environment second]
2npx create-react-app frontend

接下来,在 React 应用程序中导航并启动开发服务器:

1[environment second]
2cd ~/djangoreactproject/frontend
3npm start

您的应用程序将从 http://localhost:3000/ 运行:

React 演示页面

让 React 开发服务器继续运行,然后打开另一个终端窗口继续。

要查看此时整个项目的目录结构,请导航至根目录并再次运行 tree

1[environment third]
2cd ~/djangoreactproject
3tree

你会看到这样一个结构:

 1[secondary_label Output]
 2[environment third]
 3├── customers
 4│   ├── admin.py
 5│   ├── apps.py
 6│   ├── __init__.py
 7│   ├── migrations
 8│   │   └── __init__.py
 9│   ├── models.py
10│   ├── tests.py
11│   └── views.py
12├── djangoreactproject
13│   ├── __init__.py
14│   ├── __pycache__
15│   ├── settings.py
16│   ├── urls.py
17│   └── wsgi.py
18├── frontend
19│   ├── package.json
20│   ├── public
21│   │   ├── favicon.ico
22│   │   ├── index.html
23│   │   └── manifest.json
24│   ├── README.md
25│   ├── src
26│   │   ├── App.css
27│   │   ├── App.js
28│   │   ├── App.test.js
29│   │   ├── index.css
30│   │   ├── index.js
31│   │   ├── logo.svg
32│   │   └── registerServiceWorker.js
33│   └── yarn.lock
34└── manage.py

我们的应用程序将使用 Bootstrap 4 来设计 React 界面,因此我们将把它包含在管理 CSS 设置的 frontend/src/App.css 文件中。打开该文件:

1[environment third]
2nano ~/djangoreactproject/frontend/src/App.css

在文件开头添加以下 import。您可以删除文件的现有内容,但这不是必需的:

1[label ~/djangoreactproject/frontend/src/App.css]
2@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 与数据库的交互。

再次激活虚拟环境:

1[environment third]
2cd ~
3source env/bin/activate

移动到customers目录,打开models.py,这是一个保存应用程序模型的 Python 文件:

1[environment third]
2cd ~/djangoreactproject/customers/
3nano models.py

文件将包含以下内容

1[label ~/djangoreactproject/customers/models.py]
2from django.db import models
3# Create your models here.

由于使用了 from django.db import models 导入语句,文件中已经导入了客户模型的 API。现在,您将添加扩展了 models.ModelCustomer 类。Django 中的每个模型都是一个扩展了 django.db.models.Model 的 Python 类。

客户 "模型将包含这些数据库字段:

first_name - 客户的名。 last_name - 客户的姓。 email - 客户的电子邮件地址。 phone - 客户的电话号码。 address - 客户的地址。 description - 客户的描述。 createdAt - 添加客户的日期。

我们还将添加 __str__() 函数,它定义了模型的显示方式。在我们的例子中,将显示客户的名字。有关构建类和定义对象的更多信息,请参阅 How To Construct Classes and Define Objects in Python 3

在文件中添加以下代码

 1[label ~/djangoreactproject/customers/models.py]
 2from django.db import models
 3
 4class Customer(models.Model):
 5    first_name = models.CharField("First name", max_length=255)
 6    last_name = models.CharField("Last name", max_length=255)
 7    email = models.EmailField()
 8    phone = models.CharField(max_length=20)
 9    address =  models.TextField(blank=True, null=True)
10    description = models.TextField(blank=True, null=True)
11    createdAt = models.DateTimeField("Created At", auto_now_add=True)
12    
13    def __str__(self):
14    	return self.first_name

接下来,迁移数据库以创建数据库表。使用 makemigrations命令创建迁移文件,并在其中添加模型更改,然后 "migrate`"将迁移文件中的更改应用到数据库中。

返回项目根文件夹:

1[environment third]
2cd ~/djangoreactproject

运行以下程序创建迁移文件:

1[environment third]
2python manage.py makemigrations

输出结果如下

1[secondary_label Output]
2[environment third]
3customers/migrations/0001_initial.py
4    - Create model Customer

将这些更改应用到数据库:

1[environment third]
2python manage.py migrate

您将看到显示迁移成功的输出结果:

1[secondary_label Output]
2[environment third]
3Operations to perform:
4  Apply all migrations: admin, auth, contenttypes, customers, sessions
5Running migrations:
6  Applying customers.0001_initial... OK

接下来,你将使用_数据迁移文件_创建初始客户数据。数据迁移文件](https://docs.djangoproject.com/en/2.0/topics/migrations/# data-migrations) 是在数据库中添加或修改数据的迁移文件。为 "客户 "应用程序创建一个空的数据迁移文件:

1[environment third]
2python manage.py makemigrations --empty --name customers customers

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

1[secondary_label Output]
2[environment third]
3Migrations for 'customers':
4  customers/migrations/0002_customers.py

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

接下来,导航进入 "客户 "应用程序的迁移文件夹:

1[environment third]
2cd ~/djangoreactproject/customers/migrations

打开创建的迁移文件:

1[environment third]
2nano 0002_customers.py

这是文件的初始内容:

1[label ~/djangoreactproject/customers/migrations/0002_customers.py]
2from django.db import migrations
3
4class Migration(migrations.Migration):
5    dependencies = [
6        ('customers', '0001_initial'),
7    ]
8    operations = [
9    ]

import 语句从 django.db 中导入了 migrations API(用于创建迁移的 Django API),django.db是一个内置包,包含用于处理数据库的类。

Migration类是一个Python类,用于描述迁移数据库时执行的操作。该类扩展了 migrations.Migration`,有两个列表:

dependencies :包含依赖迁移。 operations :包含应用迁移时要执行的操作。

接下来,添加一个方法来创建演示客户数据。在Migration类的定义前添加以下方法:

1[label ~/djangoreactproject/customers/migrations/0002_customers.py]
2...
3def create_data(apps, schema_editor):
4    Customer = apps.get_model('customers', 'Customer')
5    Customer(first_name="Customer 001", last_name="Customer 001", email="[email protected]", phone="00000000", address="Customer 000 Address", description= "Customer 001 description").save()
6
7...

在此方法中,我们将从 "客户 "应用程序中抓取 "客户 "类,并创建一个演示客户以插入数据库。

要获取用于创建新客户的 "客户 "类,我们需要使用 "应用程序 "对象的 "get_model() "方法。应用程序 "对象代表已安装应用程序的注册表及其数据库模型。

当我们使用RunPython()方法运行create_data()时,apps对象将从RunPython()方法中传递过来。将 migrations.RunPython() 方法添加到空的 operations 列表中:

1[label ~/djangoreactproject/customers/migrations/0002_customers.py]
2
3...
4    operations = [
5        migrations.RunPython(create_data),
6    ]

RunPython()是迁移 API 的一部分,允许你在迁移中运行自定义 Python 代码。我们的 operations` 列表指定在应用迁移时执行该方法。

这是完整的文件:

 1[label ~/djangoreactproject/customers/migrations/0002_customers.py]
 2from django.db import migrations
 3
 4def create_data(apps, schema_editor):
 5    Customer = apps.get_model('customers', 'Customer')
 6    Customer(first_name="Customer 001", last_name="Customer 001", email="[email protected]", phone="00000000", address="Customer 000 Address", description= "Customer 001 description").save()
 7
 8class Migration(migrations.Migration):
 9    dependencies = [
10        ('customers', '0001_initial'),
11    ]
12    operations = [
13        migrations.RunPython(create_data),
14    ]

有关数据迁移的更多信息,请参阅 [Django 中的数据迁移] 文档(https://docs.djangoproject.com/en/2.0/topics/migrations/# data-migrations)

要迁移数据库,首先要返回项目的根文件夹:

1[environment third]
2cd ~/djangoreactproject

迁移数据库以创建演示数据:

1[environment third]
2python manage.py migrate

您将看到确认迁移的输出结果:

1[secondary_label Output]
2[environment third]
3Operations to perform:
4  Apply all migrations: admin, auth, contenttypes, customers, sessions
5Running migrations:
6  Applying customers.0002_customers... OK

有关此过程的详细信息,请参阅 如何创建 Django 模型

创建了客户模型和演示数据后,我们就可以继续构建 REST API 了。

第 5 步 - 创建 REST API

在这一步中,我们将使用 Django REST 框架创建 REST API。我们将创建几个不同的_API 视图。API 视图是一个处理 API 请求或调用的函数,而_API 端点_是一个唯一的 URL,代表与 REST 系统的接触点。例如,当用户向 API 端点发送 GET 请求时,Django 会调用相应的函数或 API 视图来处理请求并返回任何可能的结果。

我们还将使用 序列化器。Django REST 框架中的serializer允许将复杂的模型实例和 QuerySets 转换为 JSON 格式,以供 API 使用。序列化器类也可以反向工作,提供将数据解析和反序列化为 Django 模型和 QuerySets 的机制。

我们的应用程序接口端点将包括

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

我们还将在项目的 urls.py 文件中为相应的端点(即 api/customersapi/customers/<pk>)创建 URL。

首先,让我们为我们的 Customer 模型创建 _serializer 类。

添加序列化器类

为我们的 "客户 "模型创建一个序列化器类对于将客户实例和查询集转换为 JSON 和从 JSON 转换为 JSON 是必要的。要创建序列化器类,首先要在 customers 应用程序中创建一个 serializers.py 文件:

1[environment third]
2cd ~/djangoreactproject/customers/
3nano serializers.py

添加以下代码,以导入序列化器 API 和 Customer 模型:

1[label ~/djangoreactproject/customers/serializers.py]
2from rest_framework import serializers
3from .models import Customer

接下来,创建一个扩展了 serializers.ModelSerializer 的序列化器类,并指定要序列化的字段:

1[label ~/djangoreactproject/customers/serializers.py]
2
3...
4class CustomerSerializer(serializers.ModelSerializer):
5
6    class Meta:
7        model = Customer 
8        fields = ('pk','first_name', 'last_name', 'email', 'phone','address','description')

Meta "类指定了要序列化的模型和字段:"pk"、"first_name"、"last_name"、"email"、"phone"、"address"、"description"。

这是文件的全部内容:

1[label ~/djangoreactproject/customers/serializers.py]
2from rest_framework import serializers
3from .models import Customer
4
5class CustomerSerializer(serializers.ModelSerializer):
6
7    class Meta:
8        model = Customer 
9        fields = ('pk','first_name', 'last_name', 'email', 'phone','address','description')

现在我们已经创建了序列化器类,可以添加 API 视图了。

添加应用程序接口视图

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

打开 ~/djangoreactproject/customers/views.py

1[environment third]
2nano ~/djangoreactproject/customers/views.py

删除现有内容,添加以下导入内容:

1[label ~/djangoreactproject/customers/views.py]
2from rest_framework.response import Response
3from rest_framework.decorators import api_view
4from rest_framework import status
5
6from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
7from .models import Customer 
8from .serializers import *

我们将导入创建的序列化器、"客户 "模型以及 Django 和 Django REST 框架 API。

接下来,添加用于处理 POST 和 GET HTTP 请求的视图:

 1[label ~/djangoreactproject/customers/views.py]
 2...
 3
 4@api_view(['GET', 'POST'])
 5def customers_list(request):
 6    """
 7 List customers, or create a new customer.
 8 """
 9    if request.method == 'GET':
10        data = []
11        nextPage = 1
12        previousPage = 1
13        customers = Customer.objects.all()
14        page = request.GET.get('page', 1)
15        paginator = Paginator(customers, 10)
16        try:
17            data = paginator.page(page)
18        except PageNotAnInteger:
19            data = paginator.page(1)
20        except EmptyPage:
21            data = paginator.page(paginator.num_pages)
22
23        serializer = CustomerSerializer(data,context={'request': request} ,many=True)
24        if data.has_next():
25            nextPage = data.next_page_number()
26        if data.has_previous():
27            previousPage = data.previous_page_number()
28
29        return Response({'data': serializer.data , 'count': paginator.count, 'numpages' : paginator.num_pages, 'nextlink': '/api/customers/?page=' + str(nextPage), 'prevlink': '/api/customers/?page=' + str(previousPage)})
30
31    elif request.method == 'POST':
32        serializer = CustomerSerializer(data=request.data)
33        if serializer.is_valid():
34            serializer.save()
35            return Response(serializer.data, status=status.HTTP_201_CREATED)
36        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

首先,我们使用@api_view(['GET', 'POST']) 装饰器创建一个可以接受 GET 和 POST 请求的 API 视图。装饰器](https://wiki.python.org/moin/PythonDecorators) 是一个函数,它接收另一个函数并对其进行动态扩展。

在方法体中,我们使用 request.method 变量来检查当前的 HTTP 方法,并根据请求类型执行相应的逻辑:

  • 如果是 GET 请求,该方法将使用 Django Paginator对数据进行分页,并返回序列化后的第一页数据、可用客户数、可用页面数以及上一页和下一页的链接。Paginator 是 Django 的一个内置类,可将数据列表分页,并提供访问各页项目的方法。
  • 如果是 POST 请求,该方法会将收到的客户数据序列化,然后调用序列化对象的 save() 方法。然后,该方法会返回一个 Response 对象(HttpResponse 的实例),状态代码为 201。您创建的每个视图都负责返回一个 HttpResponse 对象。save() "方法将序列化数据保存到数据库中。

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

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

 1[label ~/djangoreactproject/customers/views.py]
 2
 3...
 4@api_view(['GET', 'PUT', 'DELETE'])
 5def customers_detail(request, pk):
 6 """
 7 Retrieve, update or delete a customer by id/pk.
 8 """
 9    try:
10        customer = Customer.objects.get(pk=pk)
11    except Customer.DoesNotExist:
12        return Response(status=status.HTTP_404_NOT_FOUND)
13
14    if request.method == 'GET':
15        serializer = CustomerSerializer(customer,context={'request': request})
16        return Response(serializer.data)
17
18    elif request.method == 'PUT':
19        serializer = CustomerSerializer(customer, data=request.data,context={'request': request})
20        if serializer.is_valid():
21            serializer.save()
22            return Response(serializer.data)
23        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
24
25    elif request.method == 'DELETE':
26        customer.delete()
27        return Response(status=status.HTTP_204_NO_CONTENT)

该方法用 `@api_view(['GET','PUT','DELETE'])'装饰,表示它是一个可以接受 GET、PUT 和 DELETE 请求的 API 视图。

request.method "字段中的检查将验证请求方法,并根据其值调用正确的逻辑:

  • 如果是 GET 请求,客户数据将被序列化,并使用响应对象发送。
  • 如果是 PUT 请求,该方法会为新的客户数据创建一个序列化器。然后,调用已创建序列化器对象的 save() 方法。最后,发送包含更新客户信息的响应对象。
  • 如果是 DELETE 请求,该方法会调用客户对象的 delete() 方法将其删除,然后返回一个不含数据的 Response 对象。

完成后的文件看起来是这样的

 1[label ~/djangoreactproject/customers/views.py]
 2from rest_framework.response import Response
 3from rest_framework.decorators import api_view
 4from rest_framework import status
 5
 6from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
 7from .models import Customer 
 8from .serializers import *
 9
10@api_view(['GET', 'POST'])
11def customers_list(request):
12    """
13 List customers, or create a new customer.
14 """
15    if request.method == 'GET':
16        data = []
17        nextPage = 1
18        previousPage = 1
19        customers = Customer.objects.all()
20        page = request.GET.get('page', 1)
21        paginator = Paginator(customers, 5)
22        try:
23            data = paginator.page(page)
24        except PageNotAnInteger:
25            data = paginator.page(1)
26        except EmptyPage:
27            data = paginator.page(paginator.num_pages)
28
29        serializer = CustomerSerializer(data,context={'request': request} ,many=True)
30        if data.has_next():
31            nextPage = data.next_page_number()
32        if data.has_previous():
33            previousPage = data.previous_page_number()
34
35        return Response({'data': serializer.data , 'count': paginator.count, 'numpages' : paginator.num_pages, 'nextlink': '/api/customers/?page=' + str(nextPage), 'prevlink': '/api/customers/?page=' + str(previousPage)})
36
37    elif request.method == 'POST':
38        serializer = CustomerSerializer(data=request.data)
39        if serializer.is_valid():
40            serializer.save()
41            return Response(serializer.data, status=status.HTTP_201_CREATED)
42        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
43
44@api_view(['GET', 'PUT', 'DELETE'])
45def customers_detail(request, pk):
46    """
47 Retrieve, update or delete a customer by id/pk.
48 """
49    try:
50        customer = Customer.objects.get(pk=pk)
51    except Customer.DoesNotExist:
52        return Response(status=status.HTTP_404_NOT_FOUND)
53
54    if request.method == 'GET':
55        serializer = CustomerSerializer(customer,context={'request': request})
56        return Response(serializer.data)
57
58    elif request.method == 'PUT':
59        serializer = CustomerSerializer(customer, data=request.data,context={'request': request})
60        if serializer.is_valid():
61            serializer.save()
62            return Response(serializer.data)
63        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
64
65    elif request.method == 'DELETE':
66        customer.delete()
67        return Response(status=status.HTTP_204_NO_CONTENT)

现在我们可以继续创建端点。

添加应用程序接口端点

现在我们将创建 API 端点:api/customers/",用于查询和创建客户;"api/customers/",用于通过客户的 "pk "获取、更新或删除单个客户。

打开~/djangoreactproject/djangoreactproject/urls.py

1[environment third]
2nano ~/djangoreactproject/djangoreactproject/urls.py

保留现有内容,但将导入内容添加到文件顶部的 "客户 "视图中:

1[label ~/djangoreactproject/djangoreactproject/urls.py]
2from django.contrib import admin
3from django.urls import path
4from customers import views
5from django.conf.urls import url

接下来,将 api/customers/api/customers/<pk> URL 添加到包含应用程序 URL 的 urlpatterns列表

1[label ~/djangoreactproject/djangoreactproject/urls.py]
2...
3
4urlpatterns = [
5    path('admin/', admin.site.urls),
6    url(r'^api/customers/$', views.customers_list),
7    url(r'^api/customers/(?P<pk>[0-9]+)$', views.customers_detail),
8]

创建了 REST 端点后,让我们看看如何使用它们。

第 6 步 - 使用 Axios 的 REST API

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

首先,停用虚拟环境:

1[environment third]
2deactivate

接下来,导航到 "frontend "文件夹:

1[environment third]
2cd ~/djangoreactproject/frontend

使用 npmnpm 安装 axios

1[environment third]
2npm install axios --save

保存 "选项会在应用程序的 "package.json "文件中添加 "axios "依赖关系。

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

1[environment third]
2cd src
3nano CustomersService.js

添加以下代码,其中包含连接 Django REST API 的方法:

 1[label ~/djangoreactproject/frontend/src/CustomersService.js]
 2import axios from 'axios';
 3const API_URL = 'http://localhost:8000';
 4
 5export default class CustomersService{
 6    
 7    constructor(){}
 8    
 9    
10    getCustomers() {
11    	const url = `${API_URL}/api/customers/`;
12    	return axios.get(url).then(response => response.data);
13    }  
14    getCustomersByURL(link){
15    	const url = `${API_URL}${link}`;
16    	return axios.get(url).then(response => response.data);
17    }
18    getCustomer(pk) {
19    	const url = `${API_URL}/api/customers/${pk}`;
20    	return axios.get(url).then(response => response.data);
21    }
22    deleteCustomer(customer){
23    	const url = `${API_URL}/api/customers/${customer.pk}`;
24    	return axios.delete(url);
25    }
26    createCustomer(customer){
27    	const url = `${API_URL}/api/customers/`;
28    	return axios.post(url,customer);
29    }
30    updateCustomer(customer){
31    	const url = `${API_URL}/api/customers/${customer.pk}`;
32    	return axios.put(url,customer);
33    }
34}

客户服务 "类将调用以下 Axios 方法:

  • getCustomers():获取客户的第一页。
  • getCustomersByURL():通过 URL 获取客户。这样就可以通过传递链接(如 /api/customers/?page=2)来获取客户的下一页。
  • getCustomer():通过主键获取客户。
  • createCustomer():创建客户。
  • updateCustomer():更新客户信息。
  • deleteCustomer():删除客户。

现在,我们可以通过创建一个 CustomersList 组件,在 React UI 界面中显示来自 API 的数据。

第 7 步 - 在 React 应用程序中显示来自应用程序接口的数据

在这一步中,我们将创建 CustomersList React 组件。React 组件代表用户界面的一部分;它还可以将用户界面分割成独立、可重用的部分。

首先在 frontend/src 中创建 CustomersList.js

1[environment third]
2nano ~/djangoreactproject/frontend/src/CustomersList.js

首先导入 ReactComponent 以创建 React 组件:

1[label ~/djangoreactproject/frontend/src/CustomersList.js]
2import React, { Component } from  'react';

接下来,导入并实例化在上一步中创建的 CustomersService 模块,该模块提供与 REST API 后端接口的方法:

1[label ~/djangoreactproject/frontend/src/CustomersList.js]
2
3...
4import CustomersService from  './CustomersService';
5
6const customersService  =  new CustomersService();

接下来,创建一个扩展了 ComponentCustomersList 组件,以调用 REST API。React 组件应扩展或子类化Component。有关 E6 类和继承的更多信息,请参阅我们的教程 Understanding Classes in JavaScript

添加以下代码以创建一个扩展了 react.Component 的 React 组件:

 1[label ~/djangoreactproject/frontend/src/CustomersList.js]
 2
 3...
 4class CustomersList extends Component {
 5
 6    constructor(props) {
 7    	super(props);
 8    	this.state  = {
 9    		customers: [],
10    		nextPageURL:  ''
11    	};
12    	this.nextPage  =  this.nextPage.bind(this);
13    	this.handleDelete  =  this.handleDelete.bind(this);
14    }
15}
16export default CustomersList;

构造函数中,我们将初始化[state](https://reactjs.org/docs/react-component.html state)对象。它使用一个空的 customers array 来保存组件的状态变量。这个数组将保存客户和一个 nextPageURL ,它将保存从后端 API 获取的下一个页面的 URL。我们还将绑定 nextPage()handleDelete() 方法this,以便从 HTML 代码中访问它们。

接下来,在结尾大括号之前,在 "CustomersList "类中添加 "componentDidMount() "方法和对 "getCustomers() "的调用。

componentDidMount()方法是组件的生命周期方法,在组件创建并插入 DOM 时被调用。getCustomers()` 调用客户服务对象,以从 Django 后台获取第一页数据和下一页的链接:

1[label ~/djangoreactproject/frontend/src/CustomersList.js]
2
3...
4componentDidMount() {
5    var self  =  this;
6    customersService.getCustomers().then(function (result) {
7    	self.setState({ customers:  result.data, nextPageURL:  result.nextlink})
8    });
9}

现在,在 "componentDidMount() "下面添加 "handleDelete() "方法,用于删除客户:

 1[label ~/djangoreactproject/frontend/src/CustomersList.js]
 2
 3...
 4handleDelete(e,pk){
 5    var self  =  this;
 6    customersService.deleteCustomer({pk :  pk}).then(()=>{
 7    	var newArr  =  self.state.customers.filter(function(obj) {
 8    		return obj.pk  !==  pk;
 9    	});
10    	self.setState({customers:  newArr})
11    });
12}

处理删除() "方法调用 "删除客户() "方法,使用客户的 "pk"(主键)删除客户。如果操作成功,就会在 customers 数组中筛选出删除的客户。

接下来,添加一个 nextPage() 方法,以获取下一页的数据并更新下一页链接:

1[label ~/djangoreactproject/frontend/src/CustomersList.js]
2
3...
4nextPage(){
5    var self  =  this;
6    customersService.getCustomersByURL(this.state.nextPageURL).then((result) => {
7    	self.setState({ customers:  result.data, nextPageURL:  result.nextlink})
8    });
9}

nextPage()方法调用getCustomersByURL()方法,该方法从状态对象中获取下一页的 URL,即this.state.nextPageURL,并用返回的数据更新customers`数组。

最后,添加组件 render()方法,根据组件状态渲染客户表:

 1[label ~/djangoreactproject/frontend/src/CustomersList.js]
 2
 3...
 4render() {
 5
 6    return (
 7    <div className="customers--list">
 8    	<table className="table">
 9    		<thead key="thead">
10    		<tr>
11    			<th>#</th>
12    			<th>First Name</th>
13    			<th>Last Name</th>
14    			<th>Phone</th>
15    			<th>Email</th>
16    			<th>Address</th>
17    			<th>Description</th>
18    			<th>Actions</th>
19    		</tr>
20    		</thead>
21    		<tbody>
22    			{this.state.customers.map( c  =>
23    			<tr key={c.pk}>
24    				<td>{c.pk}  </td>
25    				<td>{c.first_name}</td>
26    				<td>{c.last_name}</td>
27    				<td>{c.phone}</td>
28    				<td>{c.email}</td>
29    				<td>{c.address}</td>
30    				<td>{c.description}</td>
31    				<td>
32    				<button onClick={(e)=>  this.handleDelete(e,c.pk) }> Delete</button>
33    				<a href={"/customer/" + c.pk}> Update</a>
34    				</td>
35    			</tr>)}
36    		</tbody>
37    	</table>
38    	<button className="btn btn-primary"  onClick=  {  this.nextPage  }>Next</button>
39    </div>
40    );
41}

这是文件的全部内容:

 1[label ~/djangoreactproject/frontend/src/CustomersList.js]
 2import React, { Component } from  'react';
 3import CustomersService from  './CustomersService';
 4
 5const customersService  =  new CustomersService();
 6
 7class CustomersList extends Component {
 8
 9constructor(props) {
10    super(props);
11    this.state  = {
12    	customers: [],
13    	nextPageURL:  ''
14    };
15    this.nextPage  =  this.nextPage.bind(this);
16    this.handleDelete  =  this.handleDelete.bind(this);
17}
18
19componentDidMount() {
20    var self  =  this;
21    customersService.getCustomers().then(function (result) {
22    	console.log(result);
23    	self.setState({ customers:  result.data, nextPageURL:  result.nextlink})
24    });
25}
26handleDelete(e,pk){
27    var self  =  this;
28    customersService.deleteCustomer({pk :  pk}).then(()=>{
29    	var newArr  =  self.state.customers.filter(function(obj) {
30    		return obj.pk  !==  pk;
31    	});
32    	
33    	self.setState({customers:  newArr})
34    });
35}
36
37nextPage(){
38    var self  =  this;
39    console.log(this.state.nextPageURL);		
40    customersService.getCustomersByURL(this.state.nextPageURL).then((result) => {
41    	self.setState({ customers:  result.data, nextPageURL:  result.nextlink})
42    });
43}
44render() {
45
46    return (
47    	<div className="customers--list">
48    		<table className="table">
49    		<thead key="thead">
50    		<tr>
51    			<th>#</th>
52    			<th>First Name</th>
53    			<th>Last Name</th>
54    			<th>Phone</th>
55    			<th>Email</th>
56    			<th>Address</th>
57    			<th>Description</th>
58    			<th>Actions</th>
59    		</tr>
60    		</thead>
61    		<tbody>
62    		{this.state.customers.map( c  =>
63    			<tr key={c.pk}>
64    			<td>{c.pk}  </td>
65    			<td>{c.first_name}</td>
66    			<td>{c.last_name}</td>
67    			<td>{c.phone}</td>
68    			<td>{c.email}</td>
69    			<td>{c.address}</td>
70    			<td>{c.description}</td>
71    			<td>
72    			<button onClick={(e)=>  this.handleDelete(e,c.pk) }> Delete</button>
73    			<a href={"/customer/" + c.pk}> Update</a>
74    			</td>
75    		</tr>)}
76    		</tbody>
77    		</table>
78    		<button className="btn btn-primary"  onClick=  {  this.nextPage  }>Next</button>
79    	</div>
80    	);
81  }
82}
83export default CustomersList;

现在我们已经创建了用于显示客户列表的 CustomersList 组件,我们可以添加用于处理客户创建和更新的组件。

第 8 步 - 添加客户创建和更新 React 组件

在这一步中,我们将创建 "CustomerCreateUpdate "组件,该组件将处理客户的创建和更新。它将提供一个表单,用户可以使用该表单输入新客户的数据或更新现有条目。

frontend/src 中创建一个 CustomerCreateUpdate.js 文件:

1[environment third]
2nano ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

添加以下代码创建 React 组件,导入 ReactComponent

1[label ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js]
2import React, { Component } from  'react';

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

1[label ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js]
2...
3import CustomersService from  './CustomersService';
4
5const customersService  =  new CustomersService();

接下来,创建一个扩展了 ComponentCustomerCreateUpdate 组件,用于创建和更新客户:

 1[label ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js]
 2
 3...
 4class CustomerCreateUpdate extends Component {
 5    
 6    constructor(props) {
 7    	super(props);
 8    }
 9
10}
11export default CustomerCreateUpdate;

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

 1[label ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js]
 2
 3...
 4render() {
 5        return (
 6          <form onSubmit={this.handleSubmit}>
 7          <div className="form-group">
 8            <label>
 9              First Name:</label>
10              <input className="form-control" type="text" ref='firstName' />
11
12            <label>
13              Last Name:</label>
14              <input className="form-control" type="text" ref='lastName'/>
15
16            <label>
17              Phone:</label>
18              <input className="form-control" type="text" ref='phone' />
19
20            <label>
21              Email:</label>
22              <input className="form-control" type="text" ref='email' />
23
24            <label>
25              Address:</label>
26              <input className="form-control" type="text" ref='address' />
27
28            <label>
29              Description:</label>
30              <textarea className="form-control" ref='description' ></textarea>
31
32            <input className="btn btn-primary" type="submit" value="Submit" />
33            </div>
34          </form>
35        );
36  }

对于每个表单输入元素,该方法都会添加一个 ref 属性,用于访问和设置表单元素的值。

接下来,在render() 方法的上方,定义一个handleSubmit(event) 方法,这样当用户点击提交按钮时,就能实现适当的功能:

 1[label ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js]
 2
 3...
 4handleSubmit(event) {
 5    const { match: { params } } =  this.props;
 6    if(params  &&  params.pk){
 7    	this.handleUpdate(params.pk);
 8    }
 9    else
10    {
11    	this.handleCreate();
12    }
13    event.preventDefault();
14}
15
16...

handleSubmit(event) "方法处理表单提交,并根据路由调用 "handleUpdate(pk) "方法用传递的 "pk "更新客户,或调用 "handleCreate() "方法创建新客户。我们将很快定义这些方法。

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

1[label ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js]
2...
3class CustomerCreateUpdate extends Component {
4
5constructor(props) {
6    super(props);
7    this.handleSubmit = this.handleSubmit.bind(this);
8}
9...

接下来,定义 handleCreate() 方法,以便根据表单数据创建客户。在 handleSubmit(event) 方法的上方,添加以下代码:

 1[label ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js]
 2
 3...
 4handleCreate(){
 5    customersService.createCustomer(
 6    	{
 7    	"first_name":  this.refs.firstName.value,
 8    	"last_name":  this.refs.lastName.value,
 9    	"email":  this.refs.email.value,
10    	"phone":  this.refs.phone.value,
11    	"address":  this.refs.address.value,
12    	"description":  this.refs.description.value
13    	}).then((result)=>{
14    			alert("Customer created!");
15    	}).catch(()=>{
16    			alert('There was an error! Please re-check your form.');
17    	});
18}
19
20...

处理创建() "方法将用于根据输入的数据创建客户。它会调用相应的 CustomersService.createCustomer() 方法,该方法会向后台发出实际 API 调用,以创建客户。

接下来,在 "handleCreate() "方法下面定义 "handleUpdate(pk) "方法来实现更新:

 1[label ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js]
 2
 3...
 4handleUpdate(pk){
 5customersService.updateCustomer(
 6    {
 7    "pk":  pk,
 8    "first_name":  this.refs.firstName.value,
 9    "last_name":  this.refs.lastName.value,
10    "email":  this.refs.email.value,
11    "phone":  this.refs.phone.value,
12    "address":  this.refs.address.value,
13    "description":  this.refs.description.value
14    }
15    ).then((result)=>{
16    	
17    	alert("Customer updated!");
18    }).catch(()=>{
19    	alert('There was an error! Please re-check your form.');
20    });
21}

updateCustomer()方法将使用客户信息表中的新信息通过pk更新客户。它调用customersService.updateCustomer()` 方法。

接下来,添加一个 componentDidMount() 方法。如果用户访问了customer/:pk路由,我们希望使用 URL 中的主键在表单中填写与客户相关的信息。为此,我们可以在componentDidMount()的生命周期事件中安装组件后添加getCustomer(pk)方法。在组件构造函数下面添加以下代码以添加此方法:

 1[label ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js]
 2
 3...
 4componentDidMount(){
 5    const { match: { params } } =  this.props;
 6    if(params  &&  params.pk)
 7    {
 8    	customersService.getCustomer(params.pk).then((c)=>{
 9    		this.refs.firstName.value  =  c.first_name;
10    		this.refs.lastName.value  =  c.last_name;
11    		this.refs.email.value  =  c.email;
12    		this.refs.phone.value  =  c.phone;
13    		this.refs.address.value  =  c.address;
14    		this.refs.description.value  =  c.description;
15    	})
16    }
17}

这是文件的全部内容:

  1[label ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js]
  2import React, { Component } from 'react';
  3import CustomersService from './CustomersService';
  4
  5const customersService = new CustomersService();
  6
  7class CustomerCreateUpdate extends Component {
  8    constructor(props) {
  9        super(props);
 10
 11        this.handleSubmit = this.handleSubmit.bind(this);
 12      }
 13
 14      componentDidMount(){
 15        const { match: { params } } = this.props;
 16        if(params && params.pk)
 17        {
 18          customersService.getCustomer(params.pk).then((c)=>{
 19            this.refs.firstName.value = c.first_name;
 20            this.refs.lastName.value = c.last_name;
 21            this.refs.email.value = c.email;
 22            this.refs.phone.value = c.phone;
 23            this.refs.address.value = c.address;
 24            this.refs.description.value = c.description;
 25          })
 26        }
 27      }
 28
 29      handleCreate(){
 30        customersService.createCustomer(
 31          {
 32            "first_name": this.refs.firstName.value,
 33            "last_name": this.refs.lastName.value,
 34            "email": this.refs.email.value,
 35            "phone": this.refs.phone.value,
 36            "address": this.refs.address.value,
 37            "description": this.refs.description.value
 38        }          
 39        ).then((result)=>{
 40          alert("Customer created!");
 41        }).catch(()=>{
 42          alert('There was an error! Please re-check your form.');
 43        });
 44      }
 45      handleUpdate(pk){
 46        customersService.updateCustomer(
 47          {
 48            "pk": pk,
 49            "first_name": this.refs.firstName.value,
 50            "last_name": this.refs.lastName.value,
 51            "email": this.refs.email.value,
 52            "phone": this.refs.phone.value,
 53            "address": this.refs.address.value,
 54            "description": this.refs.description.value
 55        }          
 56        ).then((result)=>{
 57          console.log(result);
 58          alert("Customer updated!");
 59        }).catch(()=>{
 60          alert('There was an error! Please re-check your form.');
 61        });
 62      }
 63      handleSubmit(event) {
 64        const { match: { params } } = this.props;
 65
 66        if(params && params.pk){
 67          this.handleUpdate(params.pk);
 68        }
 69        else
 70        {
 71          this.handleCreate();
 72        }
 73
 74        event.preventDefault();
 75      }
 76
 77      render() {
 78        return (
 79          <form onSubmit={this.handleSubmit}>
 80          <div className="form-group">
 81            <label>
 82              First Name:</label>
 83              <input className="form-control" type="text" ref='firstName' />
 84
 85            <label>
 86              Last Name:</label>
 87              <input className="form-control" type="text" ref='lastName'/>
 88
 89            <label>
 90              Phone:</label>
 91              <input className="form-control" type="text" ref='phone' />
 92
 93            <label>
 94              Email:</label>
 95              <input className="form-control" type="text" ref='email' />
 96
 97            <label>
 98              Address:</label>
 99              <input className="form-control" type="text" ref='address' />
100
101            <label>
102              Description:</label>
103              <textarea className="form-control" ref='description' ></textarea>
104
105            <input className="btn btn-primary" type="submit" value="Submit" />
106            </div>
107          </form>
108        );
109      }  
110}
111
112export default CustomerCreateUpdate;

创建了 "CustomerCreateUpdate "组件后,我们就可以更新主 "App "组件,为我们创建的不同组件添加链接。

第 9 步 - 更新主应用程序组件

在本节中,我们将更新应用程序的 App 组件,以创建指向在前面步骤中创建的组件的链接。

frontend 文件夹中运行以下命令安装 React Router,它允许你在各种 React 组件之间添加路由和导航:

1[environment third]
2cd ~/djangoreactproject/frontend
3npm install --save react-router-dom

接下来,打开 ~/djangoreactproject/frontend/src/App.js

1[environment third]
2nano ~/djangoreactproject/frontend/src/App.js

删除所有内容,然后添加以下代码,导入添加路由所需的类。这些类包括创建路由器组件的 BrowserRouter 和创建路由组件的 Route

1[label ~/djangoreactproject/frontend/src/App.js]
2import React, { Component } from  'react';
3import { BrowserRouter } from  'react-router-dom'
4import { Route, Link } from  'react-router-dom'
5import CustomersList from  './CustomersList'
6import CustomerCreateUpdate from  './CustomerCreateUpdate'
7import  './App.css';

BrowserRouter使用HTML5 history API使用户界面与 URL 保持同步。

接下来,创建一个基础布局,提供由 BrowserRouter 组件封装的基础组件:

 1[label ~/djangoreactproject/frontend/src/App.js]
 2...
 3
 4const BaseLayout  = () => (
 5<div className="container-fluid">
 6    <nav className="navbar navbar-expand-lg navbar-light bg-light">
 7    	<a className="navbar-brand"  href="#">Django React Demo</a>
 8    	<button className="navbar-toggler"  type="button"  data-toggle="collapse"  data-target="#navbarNavAltMarkup"  aria-controls="navbarNavAltMarkup"  aria-expanded="false"  aria-label="Toggle navigation">
 9    	<span className="navbar-toggler-icon"></span>
10    </button>
11    <div className="collapse navbar-collapse"  id="navbarNavAltMarkup">
12    	<div className="navbar-nav">
13    		<a className="nav-item nav-link"  href="/">CUSTOMERS</a>
14    		<a className="nav-item nav-link"  href="/customer">CREATE CUSTOMER</a>
15    	</div>
16    </div>
17    </nav>
18    <div className="content">
19    	<Route path="/"  exact component={CustomersList}  />
20    	<Route path="/customer/:pk"  component={CustomerCreateUpdate}  />
21    	<Route path="/customer/"  exact component={CustomerCreateUpdate}  />
22    </div>
23</div>
24)

我们使用 Route 组件来定义应用程序的路由;一旦发现匹配,路由器应加载的组件。每个路由都需要一个 path 来指定要匹配的路径,一个 component 来指定要加载的组件。exact "属性告诉路由器要匹配精确的路径。

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

 1[label ~/djangoreactproject/frontend/src/App.js]
 2...
 3
 4class App extends Component {
 5
 6render() {
 7    return (
 8    <BrowserRouter>
 9    	<BaseLayout/>
10    </BrowserRouter>
11    );
12}
13}
14export default App;

我们用 "BrowserRouter "组件封装了 "BaseLayout "组件,因为我们的应用程序将在浏览器中运行。

完成后的文件看起来是这样的

 1[label ~/djangoreactproject/frontend/src/App.js]
 2import React, { Component } from 'react';
 3import { BrowserRouter } from 'react-router-dom'
 4import { Route, Link } from 'react-router-dom'
 5
 6import CustomersList from './CustomersList'
 7import CustomerCreateUpdate from './CustomerCreateUpdate'
 8import './App.css';
 9
10const BaseLayout = () => (
11  <div className="container-fluid">
12<nav className="navbar navbar-expand-lg navbar-light bg-light">
13  <a className="navbar-brand" href="#">Django React Demo</a>
14  <button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
15    <span className="navbar-toggler-icon"></span>
16  </button>
17  <div className="collapse navbar-collapse" id="navbarNavAltMarkup">
18    <div className="navbar-nav">
19      <a className="nav-item nav-link" href="/">CUSTOMERS</a>
20      <a className="nav-item nav-link" href="/customer">CREATE CUSTOMER</a>
21
22    </div>
23  </div>
24</nav>  
25
26    <div className="content">
27      <Route path="/" exact component={CustomersList} />
28      <Route path="/customer/:pk"  component={CustomerCreateUpdate} />
29      <Route path="/customer/" exact component={CustomerCreateUpdate} />
30
31    </div>
32
33  </div>
34)
35
36class App extends Component {
37  render() {
38    return (
39      <BrowserRouter>
40        <BaseLayout/>
41      </BrowserRouter>
42    );
43  }
44}
45
46export default App;

在应用程序中添加路由后,我们就可以测试应用程序了。导航至 http://localhost:3000。您将看到应用程序的第一页:

应用程序主页](assets/django_react_1604/django_react_app.png)

有了这个应用程序,您就有了客户关系管理应用程序的基础。

结论

在本教程中,您使用 Django 和 React 创建了一个演示应用程序。您使用了 Django REST 框架来构建 REST API,使用 Axios 来消费 API,并使用 Bootstrap 4 来设计 CSS。 您可以在 GitHub 代码库 中找到此项目的源代码。

本教程的设置使用了独立的前端和后端应用程序。有关将 React 与 Django 集成的不同方法,请查看此 教程 和此 教程

有关使用 Django 构建应用程序的更多信息,请参阅Django 开发系列。您还可以查看 Django 官方文档

Published At
Categories with 技术
comments powered by Disqus