使用 Django、Vue 和 GraphQL 构建博客(2)

Yuchuan 发表于 2021/12/04 08:41:53 2021/12/04
【摘要】 在这一点上,您已经完成了足够多的后端工作,您可以决定一头扎进 Django 的方向。您可以使用 Django 的 URL 路由和模板引擎来构建页面,将您在管理员中创建的所有帖子内容显示给读者。相反,您将在 GraphQL API 中包装您创建的后端,以便您最终可以从浏览器使用它并提供更丰富的客户端体验。 GraphQL 允许您仅检索您需要的数据,这与 RESTful API 中常见的非常大的响应

第 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 在你的项目中工作,你需要配置几个部分:

  1. 更新settings.py以便项目知道在哪里查找 GraphQL 信息。
  2. 添加一个 URL 模式来为 GraphQL API 和 GraphiQL(GraphQL 的可探索界面)提供服务。
  3. 创建 GraphQL 模式,以便 Graphene-Django 知道如何将您的模型转换为 GraphQL。

更新 Django 设置

GRAPHENE设置将 Graphene-Django 配置为在特定位置查找 GraphQL 架构。将其指向blog.schema.schemaPython 路径,您将很快创建该路径:

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.pyblog/目录中创建一个新模块。导入 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.Listgraphene.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变量来包装您的Querygraphene.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 的程度:

  1. CORS_ORIGIN_ALLOW_ALL 定义默认情况下 Django 应该全部打开还是全部关闭。
  2. 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.jssrc/目录中创建一个模块。该文件将保存有关哪些 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)

现在您将创建路线列表。每个路由都有两个属性:

  1. path 是一个 URL 模式,可以选择包含类似于 Django URL 模式的捕获变量。
  2. 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.jsrouter从您在上一节中创建的模块导入:

import router from '@/router'

然后将路由器传递给 Vue 实例:

new Vue({
  router,
  ...
})

这样就完成了 Vue Router 的配置。

步骤 6 总结

您已经为前端创建了路由,它将 URL 模式映射到将显示在该 URL 上的组件。路由还不能工作,因为它们指向尚不存在的组件。您将在下一步中创建这些组件。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:cloudbbs@huaweicloud.com进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。