在上篇[1]中,我们分别用 Django 和 Nuxt 实现了后端和前端的雏形。在这一部分,我们将实现前后端之间的通信,使得前端可以从后端获取数据,并且将进一步丰富网站的功能。
本文所涉及的源代码都放在了 Github[2] 上,如果您觉得我们写得还不错,希望您能给❤️这篇文章点个在看+Github仓库加星❤️哦~ 本文代码改编自 Scotch[3]。
从服务器获取数据
在这一部分,我们将真正实现一个全栈应用——让前端能够向后端发起请求,从而获取想要的数据。
配置 Django 的静态文件服务
首先我们要配置一下 Django 服务器,使前端能够访问其静态文件。调整 api/api/urls.py 文件如下:
# ...
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('core.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
注意
这样配置静态文件路由的方式仅应当在开发环境下使用。在生产环境下(settings.py 中的
DEBUG
设为False
时),静态文件路由将自动失效(因为 Django 并不适合作为静态文件服务器,应该选用类似 Nginx 之类的服务器,在后续教程中我们将更深入地讨论)。
实现前端的数据请求功能
在客户端,我们先要对 Nuxt 进行全局配置。Nuxt 包括 axios[4] 包,这是一个非常出色的基于 Promise 的 HTTP 请求库。在 nuxt.config.js 中的 axios
一项中添加 Django 服务器的 URL:
export default {
// ...
/*
** Axios module configuration
** See https://axios.nuxtjs.org/options
*/
axios: {
baseURL: 'http://localhost:8000/api',
},
// ...
}
将食谱列表页面中暂时填充的假数据删去,通过 asyncData
方法获取数据。由于我们之前配置好了 axios,所以 asyncData
函数可以获取到 $axios
对象用于发起 HTTP 请求。我们实现页面加载的数据获取以及 deleteRecipe
事件,代码如下:
<template>
<main class="container mt-5">
<div class="row">
<div class="col-12 text-right mb-4">
<div class="d-flex justify-content-between">
<h3>吃货天堂</h3>
<nuxt-link to="/recipes/add" class="btn btn-info">添加食谱</nuxt-link>
</div>
</div>
<template v-for="recipe in recipes">
<div :key="recipe.id" class="col-lg-3 col-md-4 col-sm-6 mb-4">
<recipe-card :onDelete="deleteRecipe" :recipe="recipe"></recipe-card>
</div>
</template>
</div>
</main>
</template>
<script>
import RecipeCard from "~/components/RecipeCard.vue";
export default {
head() {
return {
title: "食谱列表"
};
},
components: {
RecipeCard
},
async asyncData({ $axios, params }) {
try {
let recipes = await $axios.$get(`/recipes/`);
return { recipes };
} catch (e) {
return { recipes: [] };
}
},
data() {
return {
recipes: []
};
},
methods: {
async deleteRecipe(recipe_id) {
try {
if (confirm('确认要删除吗?')) {
await this.$axios.$delete(`/recipes/${recipe_id}/`);