使用Django REST框架将Django与Reactjs整合起来
在这篇文章中,我们将学习使用Django REST框架在Django后端和React js前端之间进行通信的过程。为了更好地理解这个概念,我们将建立一个简单的任务管理器,并通过React js和Django之间这种类型的集成的主要概念。
Reactjs简而言之是一个用于开发单页应用程序(SPA)的Javascript库,具有非常详细和结构良好的文档。在这个项目中,React将作为前端,通过对Django后台的请求来处理用户界面(UI)。
项目概述
让我们先看看我们将建立什么。下面的图片显示了任务管理器的用户界面。
这个任务管理器应用程序是一种待办事项清单。这里我们有三个按钮,分别是 “已完成”、”未完成 “和一个名为 “添加任务 “的按钮来添加任务,如上图所示。
为了添加一个任务,你点击添加任务按钮,这将在应用程序中打开一个窗口来添加任务,如下图所示。在这里,我们可以为任务添加 “标题”,并在 “描述 “部分给它一个描述。最后,你可以根据任务的状态(即,已完成或未完成)进行检查或取消检查,如下图所示。
在你 “保存 “任务后,你可以在 “已完成 “和 “未完成 “选项卡之间浏览,以跟踪任务,如下所示。
在这里,你也可以选择 “删除 “或 “编辑 “现有任务,如下图所示。
以上执行的所有操作都由Django REST框架管理。
创建项目:
先决条件:
因此,以下是项目的先决条件。
为了验证你是否安装了Python 3,在你的命令提示符中使用以下命令(由于这个项目是在Windows机器上开发的,我们将使用命令提示符,但根据你的操作系统,你可以使用终端)。
python -V
这将显示出你系统上当前的Python版本,如下图所示。
要检查Node模块是否已经安装,请使用下面的命令。
node --version
这将显示你的系统上的节点版本,如下图所示。
在这一点上,我们就可以开始了,因为我们的系统中已经安装了Python和Node js。
实现:
让我们从后端开始。
后端(Django):
现在让我们打开我们的命令提示符。现在按照下面的步骤,以同样的顺序来跟读本文。
第1步:使用以下命令创建一个名为_“Django-react-app “的目录(该命令可能会根据你的操作系统而略有变化)。
mkdir django-react-app
第2步:移动到我们刚刚创建的目录中,使用下面的命令。
cd django-react-project
第3步:现在使用下面的命令创建一个虚拟环境。
python -m venv dar
我们将我们的虚拟环境命名为_”dar” _,是Django和react的缩写。这是必要的,因为我们不需要在全局范围内安装软件包和依赖关系。这也是一种良好的编程实践。
第4步:用下面的命令激活我们刚刚创建的虚拟环境。
dar\Scripts\activate.bat
这将激活我们的虚拟机,如下图所示。
步骤5:现在使用以下命令在虚拟机内安装Django。
pip install django
当你的安装完成后,你会得到一个类似的消息。
第6步:现在让我们为我们的Django后端创建名为”_backend “的项目。要做到这一点,请使用下面的命令。
django-admin startproject backend
Django-react应用程序将是我们的主文件夹,在它里面,我们将有两个文件夹,一个用于后台,一个用于我们稍后创建的前台。
第7步:现在使用以下命令导航到后台文件夹。
cd backend
第8步:现在我们将启动我们的应用程序,并使用下面的命令调用它 “todo”。
python manage.py startapp todo
使用上述命令可以创建应用程序,如下图所示。
现在让我们继续启动VS代码并打开里面的项目文件夹。在这个阶段,我们的项目结构将看起来像下面这样。
第9步:现在使用下面的命令来迁移该项目。
python manage.py migrate
迁移将被应用,如下图所示。
第10步:现在让我们使用下面的命令运行服务器。
python manage.py runserver
现在你可以访问本地主机,检查项目是否已经正常启动。正如你在下面的图片中看到的,项目已经启动并运行。
第11步:现在我们需要在_settings.py _文件中采取一些配置步骤。在INSTALLED_APPS部分添加我们创建的应用程序的名称(即,todo),如下图所示。
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'todo',
]
在这一点上,settings.py文件将看起来像下面这样。
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-_c3!4)8+yce2l-ju@gz@b6(e0$00y@xhx7+lxk1p==k+pyqko3'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'todo',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'backend.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'backend.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/'
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
第12步:接下来,我们将需要创建一个模型。模型将决定如何将待办事项__项目存储在数据库中。我们在模型中会有三个属性。
- 标题。这将是任务的标题,最大长度为150个字符。
- 描述。这将是任务的描述,最大长度为500个字符。
- 已完成。这将是一个布尔值,它将被用来确定任务的当前状态。默认情况下,它将被设置为false。
因此,继续打开models.py文件和以下代码。
class Todo(models.Model):
title=models.CharField(max_length=150)
description=models.CharField(max_length=500)
completed=models.BooleanField(default=False)
我们还将在Todo类里面创建一个字符串表示的标题,如下所示。
def __str__(self):
#it will return the title
return self.title G")
在这一点上,我们的models.py文件将看起来像这样。
from django.db import models
class Todo(models.Model):
title=models.CharField(max_length=150)
description=models.CharField(max_length=500)
completed=models.BooleanField(default=False)
# string representation of the class
def __str__(self):
#it will return the title
return self.title
第13步:现在让我们继续做迁移。注意,每次你对models.py文件进行修改,我们都需要进行迁移。使用下面的命令来做。
python manage.py makemigrations
当你的迁移准备就绪时,将产生以下信息。
第14步:现在让我们使用下面的命令应用所有的迁移。
python manage.py migrate
这将应用我们的迁移,如下图所示。
现在我们可以测试一下CRUD操作是否在使用Admin站点(或者,界面)的todo模型文件上工作。为此,我们将需要在admin.py文件中注册这些模型。
第15步:打开_admin.py _文件,在其中添加以下代码。
from django.contrib import admin
# import the model Todo
from .models import Todo
# create a class for the admin-model integration
class TodoAdmin(admin.ModelAdmin):
# add the fields of the model here
list_display = ("title","description","completed")
# we will need to register the
# model class and the Admin model class
# using the register() method
# of admin.site class
admin.site.register(Todo,TodoAdmin)
第16步:现在让我们使用以下命令创建一个超级用户。
python manage.py createsuperuser
在这里,我们将使用以下凭证。
- Username: Geeks
- 电子邮件地址:geeks@geeksforgeeks.org
- Password:12345
注意:你可以根据你的需要设置你的凭证。上述凭证不需要相同。
当超级用户被创建时,我们会得到以下信息。
第17步:现在让我们运行服务器,用下面的命令检查到目前为止一切都在按计划进行。
python manage.py runserver
导航到以下链接。
http://127.0.0.1:8000/admin/login/?next=/admin/
这将显示我们的管理页面,如下图所示。
在这里填写你的凭证并登录。我们将使用创建超级用户时使用的凭证。
这将引导我们进入以下页面。在这里,我们可以看到我们的用户、应用程序和组,如下图所示。
Users:
Todo:
让我们给它添加一些任务并保存,如下所示。
我们可以看到这项任务列在todo部分,如下图所示。
创建API
为了创建API,我们将需要安装Django REST Framework for Serializers。我们还需要Django-cors-headers来白名单3000端口,这是React的默认端口。
现在按照以下步骤来创建Django REST框架。
第1步:安装Django REST框架,在后台目录中使用以下命令。
pip install djangorestframework
安装完成后,将显示以下信息。
步骤2:现在使用以下命令安装D _jango-cors-headers _。
pip install django-cors-headers
安装完成后,将显示以下信息。
第3步:现在打开_setting.py _文件,将我们刚刚安装的两个依赖项添加到INSTALLED_APPS中,如下图所示。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'todo',
'corsheaders',
'rest_framework',
]
第4步:在settings.py文件中,我们还需要把localhost的3000端口列入白名单。如果我们不这样做,在localhost:8000和localhost:3000之间会有一个块。添加下面的代码来实现同样的目的。
# White listing the localhost:3000 port
# for React
CORS_ORIGIN_WHITELIST = (
'http://localhost:3000',
)
第5步:在MIDDLEWARE部分,我们需要添加cors-headers设置,如下图所示。
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'corsheaders.middleware.CorsMiddleware'
]
在这一点上,我们的_settings.py _将看起来像下面这样。
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-_c3!4)8+yce2l-ju@gz@b6(e0$00y@xhx7+lxk1p==k+pyqko3'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'todo',
'corsheaders',
'rest_framework',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'corsheaders.middleware.CorsMiddleware'
]
ROOT_URLCONF = 'backend.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'backend.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# White listing the localhost:3000 port
CORS_ORIGIN_WHITELIST = (
'http://localhost:3000'
)
# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/'
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
现在我们需要为Todo数据模型创建序列化器。序列器负责将模型实例转换为JSON。这将有助于前端轻松处理收到的数据。JSON是网络上数据交换的标准。
第6步:现在在todo文件夹内创建一个文件,命名为_serializers.py. _在该文件夹内添加以下代码。
# import serializers from the REST framework
from rest_framework import serializers
# import the todo data model
from .models import Todo
# create a serializer class
class TodoSerializer(serializers.ModelSerializer):
# create a meta class
class Meta:
model = Todo
fields = ('id', 'title','description','completed')
第7步:现在是创建视图的时候了。所以打开_views.py _文件。现在在该文件中添加以下代码。
from django.shortcuts import render
# import view sets from the REST framework
from rest_framework import viewsets
# import the TodoSerializer from the serializer file
from .serializers import TodoSerializer
# import the Todo model from the models file
from .models import Todo
# create a class for the Todo model viewsets
class TodoView(viewsets.ModelViewSet):
# create a serializer class and
# assign it to the TodoSerializer class
serializer_class = TodoSerializer
# define a variable and populate it
# with the Todo list objects
queryset = Todo.objects.all()
第8步:现在打开urls.py文件,在其中添加以下代码。
from django.contrib import admin
# add include to the path
from django.urls import path, include
# import views from todo
from todo import views
# import routers from the REST framework
# it is necessary for routing
from rest_framework import routers
# create a router object
router = routers.DefaultRouter()
# register the router
router.register(r'tasks',views.TodoView, 'task')
urlpatterns = [
path('admin/', admin.site.urls),
# add another path to the url patterns
# when you visit the localhost:8000/api
# you should be routed to the django Rest framework
path('api/', include(router.urls))
]
这是创建REST API的最后一步,我们现在可以执行所有的CRUD操作。路由器允许我们进行查询。例如,如果我们去 “tasks”,这将返回所有任务的列表。此外,你可以有一个单一的 “task”,其中有一个_id _来返回一个单一的任务,其中id是主键。
现在让我们检查一下我们是否在正确的方向上前进。因此,运行服务器并导航到以下网址。
localhost:8000/api
如果一切顺利,我们将得到以下结果。
正如你所看到的,我们的API已经启动并运行。
现在,如果我们导航到以下链接,就可以查看并与我们的任务互动。
locaLHOST:8000/api/tasks
前端(React js):
现在让我们为我们的Todo应用程序建立前端。为此,请按照以下步骤进行。
第1步:导航到主项目目录(即Django-react-app),使用以下命令激活虚拟环境。
dar\Scripts\activate.bat
第2步:现在使用下面的命令来创建React js应用程序的模板。
npx create-react-app frontend
这里,npx代表Node Package Executable。在模板设置完成后,你会得到以下信息。
我们还需要一些UI设计方面的天赋,特别是reactstrap和bootstrap。
第3步:所以,使用下面的命令在项目中安装reactstrap和bootstrap。
npm install reactstrap bootstrap
第四步:首先进入Frontend文件夹,使用下面的命令运行React服务器,以确保到此为止一切正常。
npm start
如果一切正常,你会在localhost:3000上得到以下页面
第5步:现在打开前端文件夹中的App.js文件。并清除模板代码,将其改为以下代码。
import "./App.css";
function App() {
return <div className="App"><h2>Welcome to Geeksforgeeks!</h2></div>;
}
export default App;
在这一点上,前台看起来会像下面这样。
正如你在上面的图片中所看到的。对App.js文件所做的任何修改都会直接反映到用户界面上。
第6步:现在将代码放到App.js文件。为了更好地理解,在代码中加入了注释。
// import Component from the react module
import React, { Component } from "react";
import Modal from "./components/Modal";
import axios from 'axios';
// create a class that extends the component
class App extends Component {
// add a constructor to take props
constructor(props) {
super(props);
// add the props here
this.state = {
// the viewCompleted prop represents the status
// of the task. Set it to false by default
viewCompleted: false,
activeItem: {
title: "",
description: "",
completed: false
},
// this list stores all the completed tasks
taskList: []
};
}
// Add componentDidMount()
componentDidMount() {
this.refreshList();
}
refreshList = () => {
axios //Axios to send and receive HTTP requests
.get("http://localhost:8000/api/tasks/")
.then(res => this.setState({ taskList: res.data }))
.catch(err => console.log(err));
};
// this arrow function takes status as a parameter
// and changes the status of viewCompleted to true
// if the status is true, else changes it to false
displayCompleted = status => {
if (status) {
return this.setState({ viewCompleted: true });
}
return this.setState({ viewCompleted: false });
};
// this array function renders two spans that help control
// the set of items to be displayed(ie, completed or incomplete)
renderTabList = () => {
return (
<div className="my-5 tab-list">
<span
onClick={() => this.displayCompleted(true)}
className={this.state.viewCompleted ? "active" : ""}
>
completed
</span>
<span
onClick={() => this.displayCompleted(false)}
className={this.state.viewCompleted ? "" : "active"}
>
Incompleted
</span>
</div>
);
};
// Main variable to render items on the screen
renderItems = () => {
const { viewCompleted } = this.state;
const newItems = this.state.taskList.filter(
(item) => item.completed === viewCompleted
);
return newItems.map((item) => (
<li
key={item.id}
className="list-group-item d-flex justify-content-between align-items-center"
>
<span
className={`todo-title mr-2 {
this.state.viewCompleted ? "completed-todo" : ""
}`}
title={item.description}
>
{item.title}
</span>
<span>
<button
onClick={() => this.editItem(item)}
className="btn btn-secondary mr-2"
>
Edit
</button>
<button
onClick={() => this.handleDelete(item)}
className="btn btn-danger"
>
Delete
</button>
</span>
</li>
));
};
toggle = () => {
//add this after modal creation
this.setState({ modal: !this.state.modal });
};
handleSubmit = (item) => {
this.toggle();
alert("save" + JSON.stringify(item));
};
// Submit an item
handleSubmit = (item) => {
this.toggle();
if (item.id) {
// if old post to edit and submit
axios
.put(`http://localhost:8000/api/tasks/{item.id}/`, item)
.then((res) => this.refreshList());
return;
}
// if new post to submit
axios
.post("http://localhost:8000/api/tasks/", item)
.then((res) => this.refreshList());
};
// Delete item
handleDelete = (item) => {
axios
.delete(`http://localhost:8000/api/tasks/${item.id}/`)
.then((res) => this.refreshList());
};
handleDelete = (item) => {
alert("delete" + JSON.stringify(item));
};
// Create item
createItem = () => {
const item = { title: "", description: "", completed: false };
this.setState({ activeItem: item, modal: !this.state.modal });
};
//Edit item
editItem = (item) => {
this.setState({ activeItem: item, modal: !this.state.modal });
};
// Start by visual effects to viewer
render() {
return (
<main className="content">
<h1 className="text-success text-uppercase text-center my-4">
GFG Task Manager
</h1>
<div className="row ">
<div className="col-md-6 col-sm-10 mx-auto p-0">
<div className="card p-3">
<div className="">
<button onClick={this.createItem} className="btn btn-info">
Add task
</button>
</div>
{this.renderTabList()}
<ul className="list-group list-group-flush">
{this.renderItems()}
</ul>
</div>
</div>
</div>
{this.state.modal ? (
<Modal
activeItem={this.state.activeItem}
toggle={this.toggle}
onSave={this.handleSubmit}
/>
) : null}
</main>
);
}
}
export default App;
第7步:现在打开Index.css文件,清除里面的CSS,在文件中添加以下CSS。
.todo-title {
cursor: pointer;
}
.completed-todo {
text-decoration: line-through;
}
.tab-list > span {
padding: 5px 8px;
border: 1px solid rgb(7, 167, 68);
border-radius: 10px;
margin-right: 5px;
cursor: pointer;
}
.tab-list > span.active {
background-color: rgb(6, 139, 12);
color: #fff;
}
第8步:现在在_src _目录下创建一个名为“Components “的新文件夹,并在其中添加一个文件Modal.js。然后在其中添加以下代码。
import React, { Component } from "react";
// importing all of these classes from reactstrap module
import {
Button,
Modal,
ModalHeader,
ModalBody,
ModalFooter,
Form,
FormGroup,
Input,
Label
} from "reactstrap";
// build a class base component
class CustomModal extends Component {
constructor(props) {
super(props);
this.state = {
activeItem: this.props.activeItem
};
}
// changes handler to check if a checkbox is checed or not
handleChange = e => {
let { name, value } = e.target;
if (e.target.type === "checkbox") {
value = e.target.checked;
}
const activeItem = { ...this.state.activeItem, [name]: value };
this.setState({ activeItem });
};
// rendering modal in the custommodal class received toggle and on save as props,
render() {
const { toggle, onSave } = this.props;
return (
<Modal isOpen={true} toggle={toggle}>
<ModalHeader toggle={toggle}> Task Item </ModalHeader>
<ModalBody>
<Form>
{/* 3 formgroups
1 title label */}
<FormGroup>
<Label for="title">Title</Label>
<Input
type="text"
name="title"
value={this.state.activeItem.title}
onChange={this.handleChange}
placeholder="Enter Task Title"
/>
</FormGroup>
{/* 2 description label */}
<FormGroup>
<Label for="description">Description</Label>
<Input
type="text"
name="description"
value={this.state.activeItem.description}
onChange={this.handleChange}
placeholder="Enter Task Description"
/>
</FormGroup>
{/* 3 completed label */}
<FormGroup check>
<Label for="completed">
<Input
type="checkbox"
name="completed"
checked={this.state.activeItem.completed}
onChange={this.handleChange}
/>
Completed
</Label>
</FormGroup>
</Form>
</ModalBody>
{/* create a modal footer */}
<ModalFooter>
<Button color="success" onClick={() => onSave(this.state.activeItem)}>
Save
</Button>
</ModalFooter>
</Modal>
);
}
}
export default CustomModal
第10步:对_index.js _文件做如下修改。
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
// importing css stylesheet to use the bootstrap class
// add this line only in this file
import "bootstrap/dist/css/bootstrap.min.css";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);
API 连接:
为了让我们能够向Django后台服务器上的API端点发出请求,我们需要安装Axios。在frontend文件夹中使用以下命令来安装Axios。
npm install axios
输出:
祝贺你!!。在这一点上,你已经成功地建立了一个Fullstack Django-React应用程序,并使用Django REST框架来建立前端和后端的通信。