使用 Django、Vue 和 GraphQL 构建博客(2)
第 2 步总结
您现在已经拥有所有数据模型,并且您已经配置了 Django 管理员,以便您可以添加和编辑这些模型。
启动或重新启动 Django 开发服务器,访问 admin 界面http://localhost:8000/admin
,并探索发生了什么变化。您应该会看到指向标签、个人资料和帖子列表的链接以及添加或编辑它们的链接。尝试添加和编辑其中的一些以查看管理界面如何响应。
第 3 步:设置 Graphene-Django
在这一点上,您已经完成了足够多的后端工作,您可以决定一头扎进 Django 的方向。您可以使用 Django 的 URL 路由和模板引擎来构建页面,将您在管理员中创建的所有帖子内容显示给读者。相反,您将在 GraphQL API 中包装您创建的后端,以便您最终可以从浏览器使用它并提供更丰富的客户端体验。
GraphQL 允许您仅检索您需要的数据,这与 RESTful API 中常见的非常大的响应相比非常有用。GraphQL 还提供了更多关于投影数据的灵活性,因此您通常可以以新的方式检索数据,而无需更改提供 GraphQL API 的服务的逻辑。
您将使用Graphene-Django将您迄今为止创建的内容集成到 GraphQL API 中。
安装 Graphene-Django
要开始使用 Graphene-Django,首先将其添加到项目的需求文件中:
graphene-django==2.14.0
然后使用更新的需求文件安装它:
(venv) $ python -m pip install -r requirements.txt
添加"graphene_django"
到INSTALLED_APPS
项目settings.py
模块中的变量,以便 Django 找到它:
INSTALLED_APPS = [
...
"blog",
"graphene_django",
]
Graphene-Django 现在已安装并准备好进行配置。
配置石墨烯-Django
为了让 Graphene-Django 在你的项目中工作,你需要配置几个部分:
- 更新
settings.py
以便项目知道在哪里查找 GraphQL 信息。 - 添加一个 URL 模式来为 GraphQL API 和 GraphiQL(GraphQL 的可探索界面)提供服务。
- 创建 GraphQL 模式,以便 Graphene-Django 知道如何将您的模型转换为 GraphQL。
更新 Django 设置
该GRAPHENE
设置将 Graphene-Django 配置为在特定位置查找 GraphQL 架构。将其指向blog.schema.schema
Python 路径,您将很快创建该路径:
GRAPHENE = {
"SCHEMA": "blog.schema.schema",
}
请注意,此添加可能会导致 Django 产生导入错误,您将在创建 GraphQL 架构时解决该错误。
为 GraphQL 和 GraphiQL 添加 URL 模式
为了让 Django 为 GraphQL 端点和 GraphiQL 接口提供服务,您需要将新的 URL 模式添加到backend/urls.py
. 您会将 URL 指向 Graphene-Django 的GraphQLView
. 因为您没有使用 Django 模板引擎的跨站点请求伪造 (CSRF)保护功能,您还需要导入 Django 的csrf_exempt
装饰器以将视图标记为免于 CSRF 保护:
from django.views.decorators.csrf import csrf_exempt
from graphene_django.views import GraphQLView
然后,将新的 URL 模式添加到urlpatterns
变量中:
urlpatterns = [
...
path("graphql", csrf_exempt(GraphQLView.as_view(graphiql=True))),
]
该graphiql=True
参数告诉 Graphene-Django 使 GraphiQL 接口可用。
创建 GraphQL 架构
现在您将创建 GraphQL 架构,它应该与您之前创建的管理配置类似。该模式由几个类组成,每个类都与特定的 Django 模型相关联,一个类用于指定如何解析前端需要的一些重要类型的查询。
schema.py
在blog/
目录中创建一个新模块。导入 Graphene-Django's DjangoObjectType
、你的blog
模型和 DjangoUser
模型:
from django.contrib.auth import get_user_model
from graphene_django import DjangoObjectType
from blog import models
为每个模型和User
模型创建一个相应的类。它们每个都应该有一个以 结尾的名称,Type
因为每个都代表一个GraphQL 类型。您的类应如下所示:
class UserType(DjangoObjectType):
class Meta:
model = get_user_model()
class AuthorType(DjangoObjectType):
class Meta:
model = models.Profile
class PostType(DjangoObjectType):
class Meta:
model = models.Post
class TagType(DjangoObjectType):
class Meta:
model = models.Tag
您需要创建一个Query
继承自graphene.ObjectType
. 该类将汇集您创建的所有类型类,您将向其中添加方法以指示可以查询您的模型的方式。您需要先导入graphene
:
import graphene
的Query
类是由一个数字,或者是属性的向上graphene.List
或graphene.Field
。您将使用graphene.Field
查询是否应返回单个项目以及graphene.List
是否将返回多个项目。
对于这些属性中的每一个,您还将创建一个方法来解析查询。您可以通过获取查询中提供的信息并返回适当的 Django 查询集作为响应来解析查询。
每个解析器的方法必须以 开头resolve_
,名称的其余部分应匹配相应的属性。例如,解析all_posts
属性查询集的方法必须命名为resolve_all_posts
。
您将创建查询以获取:
- 所有的帖子
- 具有给定用户名的作者
- 带有给定 slug 的帖子
- 给定作者的所有帖子
- 具有给定标签的所有帖子
Query
现在创建类。它应该类似于以下代码段:
class Query(graphene.ObjectType):
all_posts = graphene.List(PostType)
author_by_username = graphene.Field(AuthorType, username=graphene.String())
post_by_slug = graphene.Field(PostType, slug=graphene.String())
posts_by_author = graphene.List(PostType, username=graphene.String())
posts_by_tag = graphene.List(PostType, tag=graphene.String())
def resolve_all_posts(root, info):
return (
models.Post.objects.prefetch_related("tags")
.select_related("author")
.all()
)
def resolve_author_by_username(root, info, username):
return models.Profile.objects.select_related("user").get(
user__username=username
)
def resolve_post_by_slug(root, info, slug):
return (
models.Post.objects.prefetch_related("tags")
.select_related("author")
.get(slug=slug)
)
def resolve_posts_by_author(root, info, username):
return (
models.Post.objects.prefetch_related("tags")
.select_related("author")
.filter(author__user__username=username)
)
def resolve_posts_by_tag(root, info, tag):
return (
models.Post.objects.prefetch_related("tags")
.select_related("author")
.filter(tags__name__iexact=tag)
)
您现在拥有架构的所有类型和解析器,但请记住,GRAPHENE
您创建的变量指向blog.schema.schema
. 创建一个schema
变量来包装您的Query
类graphene.Schema
以将它们联系在一起:
schema = graphene.Schema(query=Query)
此变量与"blog.schema.schema"
您在本教程前面为 Graphene-Django 配置的值相匹配。
第 3 步总结
您已经充实了博客的数据模型,现在您还使用 Graphene-Django 包装了您的数据模型,以将该数据作为 GraphQL API 提供服务。
运行 Django 开发服务器并访问http://localhost:8000/graphql
. 您应该会看到带有一些注释文本的 GraphiQL 界面,这些文本解释了如何使用该工具。
展开屏幕右上角的Docs部分,然后单击query: Query。您应该会看到您在架构中配置的每个查询和类型。
如果您尚未创建任何测试博客内容,请立即创建。尝试以下查询,它应该返回您创建的所有帖子的列表:
{
allPosts {
title
subtitle
author {
user {
username
}
}
tags {
name
}
}
}
响应应该返回一个帖子列表。每个帖子的结构应与查询的形状相匹配,如下例所示:
{
"data": {
"allPosts": [
{
"title": "The Great Coney Island Debate",
"subtitle": "American or Lafayette?",
"author": {
"user": {
"username": "coney15land"
}
},
"tags": [
{
"name": "food"
},
{
"name": "coney island"
}
]
}
]
}
}
如果您保存了一些帖子并在回复中看到它们,那么您就可以继续了。
第 4 步:设置 django-cors-headers
在调用后端工作完成之前,您需要再执行一个步骤。因为后端和前端将在本地运行在不同的端口上,并且因为它们可能在生产环境中运行在完全不同的域上,所以跨域资源共享 (CORS)发挥了作用。如果不处理 CORS,从前端到后端的请求通常会被您的浏览器阻止。
该django-cors-headers
项目使处理 CORS 变得相当轻松。您将使用它来告诉 Django 响应请求,即使它们来自另一个来源,这将允许前端与 GraphQL API 正确通信。
安装 django-cors-headers
首先,添加django-cors-headers
到您的需求文件:
django-cors-headers==3.6.0
然后使用更新的需求文件安装它:
(venv) $ python -m pip install -r requirements.txt
添加"corsheaders"
到INSTALLED_APPS
项目settings.py
模块的列表中:
INSTALLED_APPS = [
...
"corsheaders",
]
然后添加"corsheaders.middleware.CorsMiddleware"
到MIDDLEWARE
变量的末尾:
MIDDLEWARE = [
"corsheaders.middleware.CorsMiddleware",
...
]
该django-cors-headers
文档建议将中间件尽可能早地放在MIDDLEWARE
列表中。您可以将它放在此项目中列表的最顶部。
配置 django-cors-headers
CORS 的存在是有充分理由的。您不想公开您的应用程序以供从 Internet 上的任何地方使用。您可以使用两个设置来非常精确地定义要打开 GraphQL API 的程度:
CORS_ORIGIN_ALLOW_ALL
定义默认情况下 Django 应该全部打开还是全部关闭。CORS_ORIGIN_WHITELIST
定义您的 Django 应用程序将允许来自哪些域的请求。
将以下设置添加到settings.py
:
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = ("http://localhost:8080",)
这些设置将只允许来自您的前端的请求,您最终将在8080
本地端口上运行。
第 4 步总结
后端完成!您有一个工作数据模型、一个工作管理界面、一个可以使用 GraphiQL 探索的工作 GraphQL API,以及从接下来将构建的前端查询 API 的能力。如果您有一段时间没有休息,这是一个停下来的好地方。
第 5 步:设置 Vue.js
您将使用 Vue 作为博客的前端。要设置 Vue,您将创建 Vue 项目,安装几个重要的插件,并运行 Vue 开发服务器以确保您的应用程序及其依赖项正常工作。
创建 Vue 项目
与 Django 非常相似,Vue 提供了一个命令行界面,无需完全从头开始即可创建项目。您可以将其与 Node 的npx
命令配对,以引导其他人发布的基于 JavaScript 的命令。使用这种方法,您无需手动安装启动和运行 Vue 项目所需的各种单独的依赖项。用npx
现在来创建Vue公司的项目:
$ cd /path/to/dvg/
$ npx @vue/cli create frontend --default
...
🎉 Successfully created project frontend.
...
$ cd frontend/
这将frontend/
在现有目录旁边创建一个目录backend/
,安装一些 JavaScript 依赖项,并为应用程序创建一些框架文件。
安装 Vue 插件
你需要一些 Vue 插件来执行正确的浏览器路由并与你的 GraphQL API 交互。这些插件有时会影响您的文件,因此最好在刚开始时安装它们,这样它们就不会覆盖任何内容,然后再配置它们。安装 Vue Router 和 Vue Apollo 插件,在出现提示时选择默认选项:
$ npx @vue/cli add router
$ npx @vue/cli add apollo
这些命令需要一些时间来安装依赖项,它们会添加或更改项目中的一些文件以配置和安装 Vue 项目中的每个插件。
第 5 步总结
您现在应该能够运行 Vue 开发服务器:
$ npm run serve
现在,您的 Django 应用程序运行于http://localhost:8000
,Vue 应用程序运行于http://localhost:8080
。
http://localhost:8080
在浏览器中访问。您应该会看到 Vue 启动页面,这表明您已成功安装所有内容。如果您看到启动页面,您就可以开始创建您自己的一些组件了。
第 6 步:设置 Vue 路由器
客户端应用程序的一个重要部分是处理路由,而不必向服务器发出新请求。在 Vue 中,一个常见的解决方案是您之前安装的Vue Router插件。您将使用 Vue Router 而不是普通的 HTML 锚标签来链接到您博客的不同页面。
创建路线
现在您已经安装了 Vue Router,您需要配置 Vue 以使用 Vue Router。您还需要使用它应该路由的 URL 路径来配置 Vue Router。
router.js
在src/
目录中创建一个模块。该文件将保存有关哪些 URL 映射到哪些 Vue 组件的所有配置。首先导入 Vue 和 Vue Router:
import Vue from 'vue'
import VueRouter from 'vue-router'
添加以下导入,每个导入对应于您将很快创建的组件:
import Post from '@/components/Post'
import Author from '@/components/Author'
import PostsByTag from '@/components/PostsByTag'
import AllPosts from '@/components/AllPosts'
注册 Vue Router 插件:
Vue.use(VueRouter)
现在您将创建路线列表。每个路由都有两个属性:
path
是一个 URL 模式,可以选择包含类似于 Django URL 模式的捕获变量。component
是当浏览器导航到匹配路径模式的路由时显示的 Vue 组件。
将这些路由添加为routes
变量。它们应该如下所示:
const routes = [
{ path: '/author/:username', component: Author },
{ path: '/post/:slug', component: Post },
{ path: '/tag/:tag', component: PostsByTag },
{ path: '/', component: AllPosts },
]
创建一个新实例VueRouter
并将其从router.js
模块中导出,以便其他模块可以使用它:
const router = new VueRouter({
routes: routes,
mode: 'history',
})
export default router
您将router
在下一部分的另一个模块中导入该变量。
安装路由器
在 顶部src/main.js
,router
从您在上一节中创建的模块导入:
import router from '@/router'
然后将路由器传递给 Vue 实例:
new Vue({
router,
...
})
这样就完成了 Vue Router 的配置。
步骤 6 总结
您已经为前端创建了路由,它将 URL 模式映射到将显示在该 URL 上的组件。路由还不能工作,因为它们指向尚不存在的组件。您将在下一步中创建这些组件。
- 点赞
- 收藏
- 关注作者
评论(0)