如何用React与Django交互:返回对象及通过ID获取对象数据
1. 如何从Django向React返回对象?
Django 端实现
用Django REST Framework(DRF)构建API是前后端分离场景下的标准方案,以下是具体步骤:
步骤1:安装并配置DRF
先安装依赖:
pip install djangorestframework
将rest_framework添加到项目settings.py的INSTALLED_APPS:
INSTALLED_APPS = [ # ... 其他应用 'rest_framework', ]
步骤2:定义示例模型
以书籍模型为例:
# your_app/models.py from django.db import models class Book(models.Model): title = models.CharField(max_length=100) author = models.CharField(max_length=50) publication_year = models.IntegerField() def __str__(self): return self.title
步骤3:编写序列化器
序列化器负责将Django模型转换为JSON格式:
# your_app/serializers.py from rest_framework import serializers from .models import Book class BookSerializer(serializers.ModelSerializer): class Meta: model = Book fields = '__all__'
步骤4:编写API视图
创建返回对象列表的视图:
# your_app/views.py from rest_framework.views import APIView from rest_framework.response import Response from .models import Book from .serializers import BookSerializer class BookListView(APIView): def get(self, request): books = Book.objects.all() serializer = BookSerializer(books, many=True) return Response(serializer.data)
步骤5:配置URL
应用级路由:
# your_app/urls.py from django.urls import path from .views import BookListView urlpatterns = [ path('api/books/', BookListView.as_view(), name='book-list'), ]
项目根路由:
# project/urls.py from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('', include('your_app.urls')), ]
跨域问题处理
由于React默认运行在localhost:3000,Django在localhost:8000,需解决跨域:
pip install django-cors-headers
配置settings.py:
INSTALLED_APPS = [ # ... 其他应用 'corsheaders', ] MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', # ... 其他中间件 ] CORS_ALLOWED_ORIGINS = [ "http://localhost:3000", ]
React 端实现
用fetch API请求数据并渲染:
// src/components/BookList.js import React, { useState, useEffect } from 'react'; function BookList() { const [books, setBooks] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { fetch('http://localhost:8000/api/books/') .then(res => res.json()) .then(data => { setBooks(data); setLoading(false); }) .catch(err => { console.error('请求失败:', err); setLoading(false); }); }, []); if (loading) return <div>加载中...</div>; return ( <div className="book-list"> <h2>书籍列表</h2> <ul> {books.map(book => ( <li key={book.id}> {book.title} - {book.author} ({book.publication_year}) </li> ))} </ul> </div> ); } export default BookList;
2. 如何通过React将对象ID发送至Django,并返回该对象的数据?
Django 端实现
创建接收ID参数的详情API视图:
步骤1:编写详情视图
方式一:自定义APIView
# your_app/views.py class BookDetailView(APIView): def get(self, request, book_id): try: book = Book.objects.get(id=book_id) serializer = BookSerializer(book) return Response(serializer.data) except Book.DoesNotExist: return Response({'error': '该书籍不存在'}, status=404)
方式二:DRF通用视图(更简洁)
from rest_framework.generics import RetrieveAPIView class BookDetailView(RetrieveAPIView): queryset = Book.objects.all() serializer_class = BookSerializer lookup_url_kwarg = 'book_id'
步骤2:配置详情路由
# your_app/urls.py urlpatterns = [ path('api/books/', BookListView.as_view(), name='book-list'), path('api/books/<int:book_id>/', BookDetailView.as_view(), name='book-detail'), ]
React 端实现
方式一:URL路径传参(结合React Router)
先安装React Router:
npm install react-router-dom
编写详情组件:
// src/components/BookDetail.js import React, { useState, useEffect } from 'react'; import { useParams } from 'react-router-dom'; function BookDetail() { const { bookId } = useParams(); const [book, setBook] = useState(null); const [error, setError] = useState(''); useEffect(() => { fetch(`http://localhost:8000/api/books/${bookId}/`) .then(res => { if (!res.ok) throw new Error('请求失败'); return res.json(); }) .then(data => setBook(data)) .catch(err => setError(err.message)); }, [bookId]); if (error) return <div className="error">{error}</div>; if (!book) return <div>加载中...</div>; return ( <div className="book-detail"> <h2>{book.title}</h2> <p>作者:{book.author}</p> <p>出版年份:{book.publication_year}</p> </div> ); } export default BookDetail;
配置路由:
// src/App.js import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import BookList from './components/BookList'; import BookDetail from './components/BookDetail'; function App() { return ( <Router> <div className="App"> <Routes> <Route path="/" element={<BookList />} /> <Route path="/book/:bookId" element={<BookDetail />} /> </Routes> </div> </Router> ); } export default App;
方式二:查询参数传递ID(点击按钮请求)
在列表组件中添加详情按钮:
// src/components/BookList.js import React, { useState, useEffect } from 'react'; function BookList() { const [books, setBooks] = useState([]); const [selectedBook, setSelectedBook] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { fetch('http://localhost:8000/api/books/') .then(res => res.json()) .then(data => { setBooks(data); setLoading(false); }) .catch(err => { console.error('请求失败:', err); setLoading(false); }); }, []); const fetchBookDetail = (bookId) => { fetch(`http://localhost:8000/api/books/detail/?id=${bookId}`) .then(res => res.json()) .then(data => setSelectedBook(data)) .catch(err => console.error('获取详情失败:', err)); }; if (loading) return <div>加载中...</div>; return ( <div className="book-list"> <h2>书籍列表</h2> <ul> {books.map(book => ( <li key={book.id}> {book.title} - {book.author} <button onClick={() => fetchBookDetail(book.id)}>查看详情</button> </li> ))} </ul> {selectedBook && ( <div className="book-detail"> <h3>书籍详情</h3> <p>{selectedBook.title} - {selectedBook.author} ({selectedBook.publication_year})</p> </div> )} </div> ); } export default BookList;
对应的Django视图:
# your_app/views.py class BookDetailByQueryView(APIView): def get(self, request): book_id = request.query_params.get('id') if not book_id: return Response({'error': '缺少ID参数'}, status=400) try: book = Book.objects.get(id=book_id) serializer = BookSerializer(book) return Response(serializer.data) except Book.DoesNotExist: return Response({'error': '该书籍不存在'}, status=404)
添加路由:
# your_app/urls.py urlpatterns = [ # ... 其他路由 path('api/books/detail/', BookDetailByQueryView.as_view(), name='book-detail-query'), ]
内容的提问来源于stack exchange,提问作者Mathew O'Sullivan
相关产品推荐
相关产品推荐

