如何使用Django和GraphQL创建URL缩短器

The author selected Girls Who Code to receive a donation as part of the Write for DOnations program.

作者选择了《编码的女孩》作为Write for DOnations计划的一部分来接受捐赠。

介绍 (Introduction)

GraphQL is an API standard created and open-sourced by Facebook as an alternative to REST APIs. As opposed to REST APIs, GraphQL uses a typed system to define its data structure, where all the information sent and received must be compliant to a pre-defined schema. It also exposes a single endpoint for all communication instead of multiple URLs for different resources and solves the overfetching issue by returning only the data asked for by the client, thereby generating smaller and more concise responses.

GraphQL是由Facebook创建并开源的API标准,是REST API的替代方案。 与REST API相对,GraphQL使用类型化的系统来定义其数据结构,其中所有发送和接收的信息都必须符合预定义的架构。 它还为所有通信公开了一个端点,而不是为不同资源公开了多个URL,并仅返回客户端要求的数据,从而解决了提取过多的问题,从而生成了更小,更简洁的响应。

In this tutorial you will create a backend for a URL shortener—a service that takes any URL and generates a shorter, more readable version—while diving into GraphQL concepts, like queries and mutations, and tools, like the GraphiQL interface. You may already have used such services before, like bit.ly.

在本教程中,您将创建URL缩短器的后端(该服务可接收任何URL并生成更短,更易读的版本),同时深入探讨GraphQL概念(如查询和变异 )以及工具(如GraphiQL接口) 。 您可能以前已经使用过此类服务,例如bit.ly

Since GraphQL is a language agnostic technology, it is implemented on top of various languages and frameworks. Here, you will use the general purpose Python programming language, the Django web framework, and the Graphene-Django library as the GraphQL Python implementation with specific integrations for Django.

由于GraphQL是与语言无关的技术,因此它是在各种语言和框架之上实现的。 在这里,您将使用通用Python编程语言Django Web框架Graphene-Django库作为具有特定Django集成的GraphQL Python实现。

先决条件 (Prerequisites)

  • To continue with this tutorial, you’ll need Python version 3.5 or higher installed on your development machine. To install Python, follow our tutorial on How To Install and Set Up a Local Programming Environment for Python 3 for your OS. Make sure to also create and start a virtual environment; to follow the lead of this tutorial, you can name your project directory shorty.

    要继续本教程,您需要在开发计算机上安装Python 3.5或更高版本。 要安装Python,请遵循有关如何为您的操作系统安装和设置Python 3本地编程环境的教程。 确保还创建并启动虚拟环境 ; 要遵循本教程的指导,您可以将项目目录命名为shorty

  • An entry-level knowledge of Django is desired, but not mandatory. If you are curious, you can follow this Django Development series created by the DigitalOcean community.

    需要Django的入门级知识,但不是必需的。 如果您好奇,可以按照DigitalOcean社区创建的Django开发系列进行。

第1步-设置Django项目 (Step 1 — Setting Up the Django Project)

In this step, you will be installing all the necessary tools for the application and setting up your Django project.

在此步骤中,您将为应用程序安装所有必需的工具,并设置Django项目。

Once you have created your project directory and started your virtual environment, as covered in the prerequisites, install the necessary packages using pip, the Python package manager. This tutorial will install Django version 2.1.7 and Graphene-Django version 2.2.0 or higher:

如前提条件所述,一旦创建了项目目录并启动了虚拟环境,请使用Python软件包管理器pip安装必要的软件包。 本教程将安装Django 2.1.7版和Graphene-Django 2.2.0或更高版本:

  • pip install "django==2.1.7" "graphene-django>==2.2.0"

    pip install“ django == 2.1.7 ”“ graphene-django> == 2.2.0 ”

You now have all the tools needed in your tool belt. Next, you will create a Django project using the django-admin command. A project is the default Django boilerplate—a set of folders and files with everything necessary to start the development of a web application. In this case, you will call your project shorty and create it inside your current folder by specifying the . at the end:

现在,您已经拥有了工具带中所需的所有工具。 接下来,您将使用django-admin命令创建一个Django项目。 项目是默认的Django样板文件-一组文件夹和文件,其中包含开始开发Web应用程序所需的一切。 在这种情况下,您将调用项目shorty并通过指定来在当前文件夹中创建它. 在末尾:

  • django-admin startproject shorty .

    Django的管理startproject命令的矮子 。

After creating your project, you will run the Django migrations. These files contain Python code generated by Django and are responsible for changing the application’s structure according to the Django models. Changes might include the creation of a table, for example. By default, Django comes with its own set of migrations responsible for subsystems like Django Authentication, so it is necessary to execute them with the following command:

创建项目后,您将运行Django迁移 。 这些文件包含Django生成的Python代码,并负责根据Django模型更改应用程序的结构。 例如,更改可能包括创建表。 默认情况下,Django带有其自己的一组迁移,这些迁移负责诸如Django Authentication之类的子系统,因此有必要使用以下命令执行它们:

  • python manage.py migrate

    python manage.py迁移

This command uses the Python interpreter to invoke a Django script called manage.py, responsible for managing different aspects of your project, like creating apps or running migrations.

该命令使用Python解释器调用一个名为manage.py的Django脚本,该脚本负责管理项目的不同方面,例如创建应用程序或运行迁移。

This will give output similar to the following:

这将产生类似于以下内容的输出:


   
   
Output
Operations to perform: Apply all migrations: admin, auth, contenttypes, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying admin.0003_logentry_add_action_flag_choices... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying sessions.0001_initial... OK

Once Django’s database is ready to go, start its local development server:

Django的数据库准备就绪后,请启动其本地开发服务器:

  • python manage.py runserver

    python manage.py运行服务器

This will give:

这将给出:


   
   
Output
Performing system checks... System check identified no issues (0 silenced). March 18, 2020 - 15:46:15 Django version 2.1.7, using settings 'shorty.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C.

This command will take away the prompt in your terminal and start the server.

此命令将删除您终端中的提示并启动服务器。

Visit the http://127.0.0.1:8000 page in your local browser. You will see this page:

在您的本地浏览器中访问http://127.0.0.1:8000页面。 您将看到此页面:

To stop the server and return to your terminal, press CTRL+C. Whenever you need to access the browser, make sure the preceding command is running.

要停止服务器并返回到终端,请按CTRL+C 每当您需要访问浏览器时,请确保前面的命令正在运行。

Next, you will finish this step by enabling the Django-Graphene library in the project. Django has the concept of app, a web application with a specific responsibility. A project is composed of one or multiple apps. For now, open the shorty/settings.py file in your text editor of choice. This tutorial will be using vim:

接下来,您将通过在项目中启用Django-Graphene库来完成此步骤。 Django具有app的概念,这是一个专门负责的Web应用程序。 一个项目由一个或多个应用程序组成。 现在,在您选择的文本编辑器中打开shorty /settings.py文件。 本教程将使用vim

  • vim shorty/settings.py

    vim 矮子 /settings.py

The settings.py file manages all the settings in your project. Inside it, search for the INSTALLED_APPS entry and add the 'graphene_django' line:

settings.py文件管理项目中的所有设置。 在其中,搜索INSTALLED_APPS条目并添加'graphene_django'行:

shorty/shorty/settings.py
shorty / shorty / settings.py
...
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'graphene_django',
]
...

This addition tells Django that you will be using an app called graphene_django, which you installed in Step 1.

此附加功能告诉Django,您将使用在步骤1中安装的名为graphene_django的应用程序。

At the bottom of the file, add the following variable:

在文件底部,添加以下变量:

shorty/shorty/settings.py
shorty / shorty / settings.py
...
GRAPHENE = {
    'SCHEMA': 'shorty.schema.schema',
}

This last variable points to your main Schema, which you will create later. In GraphQL, a Schema contains all the object types, such as Resources, Queries, and Mutations. Think of it as documentation representing all the data and functionality available in your system.

最后一个变量指向您的主Schema ,您将在以后创建它。 在GraphQL中,模式包含所有对象类型,例如资源,查询和突变。 将其视为代表系统中所有可用数据和功能的文档。

After the modifications, save and close the file.

修改后,保存并关闭文件。

Now you have configured the Django project. In the next step, you will create a Django app and its Models.

现在,您已经配置了Django项目。 在下一步中,您将创建一个Django应用及其模型。

第2步-设置Django应用和模型 (Step 2 — Setting Up a Django App and Models)

A Django platform is usually composed of one project and many applications or apps. An app describes a set of features inside a project, and, if well-designed, can be reused across Django projects.

Django平台通常由一个项目和许多应用程序组成 。 一个应用程序描述了项目内部的一组功能,如果设计合理,则可以在Django项目中重复使用。

In this step, you will create an app called shortener, responsible for the actual URL shortening feature. To create its basic skeleton, type the next command in your terminal:

在此步骤中,您将创建一个名为shortener的应用程序,该应用程序负责实际的URL缩短功能。 要创建其基本骨架,请在终端中键入下一个命令:

  • python manage.py startapp shortener

    python manage.py startapp 缩短器

Here you used the parameters startapp app_name, instructing manage.py to create an app named shortener.

在这里,你所使用的参数startapp app_name ,指示manage.py来创建一个应用程序命名为shortener

To finish the app creation, open the shorty/settings.py file

要完成应用的创建,请打开shorty /settings.py文件

  • vim shorty/settings.py

    vim 矮子 /settings.py

Add the app’s name to the same INSTALLED_APPS entry you modified before:

将应用程序的名称添加到您之前修改过的同一INSTALLED_APPS条目中:

shorty/shorty/settings.py
shorty / shorty / settings.py
...
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'graphene_django'
    'shortener',
]
...

Save and close the file.

保存并关闭文件。

With your shortener added to shorty/settings.py, you can move on to creating the models for your project. Models are one of the key features in Django. They are used to represent a database in a “Pythonic” way, allowing you to manage, query, and store data using Python code.

有了您的shortener添加到shorty /settings.py ,您可以继续为您的项目创建的模型。 模型是Django中的关键功能之一。 它们用于以“ Pythonic”方式表示数据库,使您可以使用Python代码管理,查询和存储数据。

Before opening the models.py file for changes, this tutorial will give an overview of the changes you will make.

在打开models.py文件进行更改之前,本教程将概述您将进行的更改。

Your model file—shortener/models.py—will contain the following content once you have replaced the existing code:

替换现有代码后,模型文件shorter shortener/models.py将包含以下内容:

shorty/shortener/models.py
矮子/shortener/models.py
from hashlib import md5

from django.db import models

Here you will import the required packages needed by your code. You will add the line from hashlib import md5 at the top to import the Python standard library that will be used to create a hash of the URL. The from django.db import models line is a Django helper for creating models.

在这里,您将导入代码所需的必需软件包。 您将在顶部的from hashlib import md5中添加该行from hashlib import md5以导入Python标准库,该库将用于创建URL的哈希from django.db import models行是用于创建模型的Django帮助程序。

Warning: This tutorial refers to hash as the result of a function that takes an input and always returns the same output. This tutorial will be using the MD5 hash function for demonstration purposes.

警告:本教程将散列称为函数的结果,该函数接受输入并始终返回相同的输出。 本教程将使用MD5哈希函数进行演示。

Note that MD5 has collision issues and should be avoided in production.

请注意,MD5存在碰撞问题 ,应在生产中避免使用。

Next, you will add a Model named URL with the following fields:

接下来,您将添加一个带有以下字段的名为URL的模型:

  • full_url: the URL to be shortened.

    full_url :要缩短的URL。

  • url_hash: a short hash representing the full URL.

    url_hash :代表完整URL的短哈希。

  • clicks: how many times the short URL was accessed.

    clicks :访问短网址的次数。

  • created_at: the date and time at which the URL was created.

    created_at :创建URL的日期和时间。

shorty/shortener/models.py
矮子/shortener/models.py
...

class URL(models.Model):
    full_url = models.URLField(unique=True)
    url_hash = models.URLField(unique=True)
    clicks = models.IntegerField(default=0)
    created_at = models.DateTimeField(auto_now_add=True)

You will generate the url_hash by applying the MD5 hash algorithm to the full_url field and using just the first 10 characters returned during the Model’s save() method, executed every time Django saves an entry to the database. Additionally, URL shorteners usually track how many times a link was clicked. You will achieve this by calling the method clicked() when the URL is visited by a user.

通过将MD5哈希算法应用于full_url字段,并仅使用在Model的save()方法期间返回的前10个字符来生成url_hash ,每次Django将条目保存到数据库时都将执行该字符。 此外,URL缩短程序通常跟踪链接被单击的次数。 您将通过在用户访问URL时调用clicked()方法来实现此目的。

The operations mentioned will be added inside your URL model with this code:

所提到的操作将通过以下代码添加到您的URL模型中:

shorty/shortener/models.py
矮子/shortener/models.py
...

    def clicked(self):
        self.clicks += 1
        self.save()

    def save(self, *args, **kwargs):
        if not self.id:
            self.url_hash = md5(self.full_url.encode()).hexdigest()[:10]

        return super().save(*args, **kwargs)

Now that you’ve reviewed the code, open the shortener/models.py file:

既然您已经检查了代码,请打开shortener/models.py文件:

  • vim shortener/models.py

    vim Shorter / models.py

Replace the code with the following content:

将代码替换为以下内容:

shorty/shortener/models.py
矮子/shortener/models.py
from hashlib import md5

from django.db import models


class URL(models.Model):
    full_url = models.URLField(unique=True)
    url_hash = models.URLField(unique=True)
    clicks = models.IntegerField(default=0)
    created_at = models.DateTimeField(auto_now_add=True)

    def clicked(self):
        self.clicks += 1
        self.save()

    def save(self, *args, **kwargs):
        if not self.id:
            self.url_hash = md5(self.full_url.encode()).hexdigest()[:10]

        return super().save(*args, **kwargs)

Be sure to save and close the file.

确保保存并关闭文件。

To apply these changes in the database, you will need to create the migrations by running the following command:

要在数据库中应用这些更改,您将需要通过运行以下命令来创建迁移:

  • python manage.py makemigrations

    python manage.py makemigrations

This will give you the following output:

这将为您提供以下输出:


   
   
Output
Migrations for 'shortener': shortener/migrations/0001_initial.py - Create model URL

Then execute the migrations:

然后执行迁移:

  • python manage.py migrate

    python manage.py迁移

You will see the following output in your terminal:

您将在终端中看到以下输出:


   
   
Output
Operations to perform: Apply all migrations: admin, auth, contenttypes, sessions, shortener Running migrations: Applying shortener.0001_initial... OK

Now that you’ve set up the models, in the next step you will create the GraphQL endpoint and a Query.

现在,您已经建立了模型,在下一步中,您将创建GraphQL端点和一个查询。

第3步-创建查询 (Step 3 — Creating Queries)

The REST architecture exposes different resources in different endpoints, each one containing a well-defined data structure. For example, you may fetch a users’ list at /api/users, always expecting the same fields. GraphQL, on the other hand, has a single endpoint for all interactions, and uses Queries to access data. The main—and most valuable—difference is that you can use a Query to retrieve all your users within a single request.

REST体系结构在不同的端点中公开不同的资源,每个端点都包含一个定义明确的数据结构。 例如,您可以在/api/users处获取用户列表,总是期望使用相同的字段。 另一方面,GraphQL具有用于所有交互的单个端点,并使用查询来访问数据。 主要(也是最有价值的)区别是,您可以使用查询来检索单个请求中的所有用户。

Start by creating a Query to fetch all URLs. You will need a couple of things:

首先创建一个查询以获取所有URL。 您将需要注意以下几点:

  • A URL type, linked to your previously defined model.

    URL类型,链接到您先前定义的模型。
  • A Query statement named urls.

    名为urls的查询语句。

  • A method to resolve your Query, meaning to fetch all URLs from the database and return them to the client.

    一种解决您的查询的方法,意味着从数据库中获取所有URL并将其返回给客户端。

Create a new file called shortener/schema.py:

创建一个名为shortener/schema.py的新文件:

  • vim shortener/schema.py

    vim缩短器/schema.py

Start by adding the Python import statements:

首先添加Python import语句:

shorty/shortener/schema.py
矮子/起酥​​油/schema.py
import graphene
from graphene_django import DjangoObjectType

from .models import URL

The first line imports the main graphene library, which contains the base GraphQL types, like List. The DjangoObjectType is a helper to create a Schema definition from any Django model, and the third line imports your previously create URL model.

第一行导入主要的graphene库,其中包含基本的GraphQL类型,如ListDjangoObjectType是从任何Django模型创建Schema定义的助手,第三行导入您先前创建的URL模型。

After that, create a new GraphQL type for the URL model by adding the following lines:

之后,通过添加以下行,为URL模型创建新的GraphQL类型:

shorty/shortener/schema.py
矮子/起酥​​油/schema.py
...
class URLType(DjangoObjectType):
    class Meta:
        model = URL

Finally, add these lines to create a Query type for the URL model:

最后,添加以下行以创建URL模型的查询类型:

shorty/shortener/schema.py
矮个子/shortener/schema.py
...
class Query(graphene.ObjectType):
    urls = graphene.List(URLType)

    def resolve_urls(self, info, **kwargs):
        return URL.objects.all()

This code creates a Query class with one field named urls, which is a list of the previously defined URLType. When resolving the Query through the resolve_urls method, you return all the URLs stored in the database.

这段代码使用一个名为urls字段创建一个Query类,该字段是先前定义的URLType的列表。 通过resolve_urls方法解析查询时,您将返回存储在数据库中的所有URL。

The full shortener/schema.py file is shown here:

完整的shortener/schema.py文件显示在此处:

shorty/shortener/schema.py
矮个子/shortener/schema.py
import graphene
from graphene_django import DjangoObjectType

from .models import URL


class URLType(DjangoObjectType):
    class Meta:
        model = URL


class Query(graphene.ObjectType):
    urls = graphene.List(URLType)

    def resolve_urls(self, info, **kwargs):
        return URL.objects.all()

Save and close the file.

保存并关闭文件。

All the Queries must now be added to the main Schema. Think of it as a holder for all your resources.

现在必须将所有查询添加到主模式。 将其视为您所有资源的持有者。

Create a new file in the shorty/schema.py path and open it with your editor:

shorty /schema.py路径中创建一个新文件,并使用编辑器将其打开:

  • vim shorty/schema

    vim 矮子 /模式

Import the following Python packages by adding the following lines. The first one, as already mentioned, contains the base GraphQL types. The second line imports the previously created Schema file.

通过添加以下行来导入以下Python软件包。 如前所述,第一个包含基本的GraphQL类型。 第二行导入先前创建的模式文件。

shorty/shorty/schema.py
shorty / shorty / schema.py
import graphene

import shortener.schema

Next, add the main Query class. It will hold, via inheritance, all the Queries and future operations created:

接下来,添加主Query类。 通过继承,它将保留所有查询和创建的未来操作:

shorty/shorty/schema.py
shorty / shorty / schema.py
...
class Query(shortener.schema.Query, graphene.ObjectType):
    pass

Lastly, create the schema variable:

最后,创建schema变量:

shorty/shorty/schema.py
shorty / shorty / schema.py
...
schema = graphene.Schema(query=Query)

The SCHEMA setting you defined in Step 2 points to the schema variable you’ve just created.

您在步骤2中定义的SCHEMA设置指向您刚创建的schema变量。

The full shorty/schema.py file is shown here:

完整的shorty /schema.py文件显示在此处:

shorty/shorty/schema.py
shorty / shorty / schema.py
import graphene

import shortener.schema


class Query(shortener.schema.Query, graphene.ObjectType):
    pass

schema = graphene.Schema(query=Query)

Save and close the file.

保存并关闭文件。

Next, enable the GraphQL endpoint and the GraphiQL interface, which is a graphical web interface used to interact with the GraphQL system.

接下来,启用GraphQL端点和GraphiQL界面,这是用于与GraphQL系统进行交互的图形Web界面。

Open the shorty/urls.py file:

打开shorty /urls.py文件:

  • vim shorty/urls.py

    vim 矮子 /urls.py

For learning purposes, delete the file contents and save it, so that you can start from scratch.

出于学习目的,请删除文件内容并保存,以便从头开始。

The first lines you will add are Python import statements:

您将添加的第一行是Python import语句:

shorty/shorty/urls.py
shorty / shorty / urls.py
from django.urls import path
from django.views.decorators.csrf import csrf_exempt

from graphene_django.views import GraphQLView

The path function is used by Django to create an accessible URL for the GraphiQL interface. Following it, you import the csrf_exempt, which allows clients to send data to the server. A complete explanation can be found in the Graphene Documentation. In the last line, you imported the actual code responsible for the interface via GraphQLView.

Django使用path函数为GraphiQL接口创建可访问的URL。 之后,导入csrf_exempt ,它允许客户端将数据发送到服务器。 可以在石墨烯文档中找到完整的说明。 在最后一行,您通过GraphQLView导入了负责接口的实际代码。

Next, create a variable named urlpatterns.

接下来,创建一个名为urlpatterns的变量。

shorty/shorty/urls.py
shorty / shorty / urls.py
...
urlpatterns = [
    path('graphql/', csrf_exempt(GraphQLView.as_view(graphiql=True))),
]

This will stitch together all the code necessary to make the GraphiQL interface available in the graphql/ path:

这将使所有的graphiQL接口在graphql/路径中可用所需的代码组合在一起:

The full shortener/urls.py file is shown here:

完整的shortener/urls.py文件显示在此处:

shorty/shorty/urls.py
shorty / shorty / urls.py
from django.urls import path
from django.views.decorators.csrf import csrf_exempt

from graphene_django.views import GraphQLView

urlpatterns = [
    path('graphql/', csrf_exempt(GraphQLView.as_view(graphiql=True))),
]

Save the file and close it.

保存文件并关闭它。

Back in the terminal, run the python manage.py runserver command (if not running already):

返回终端,运行python manage.py runserver命令(如果尚未运行):

  • python manage.py runserver

    python manage.py运行服务器

Open your web browser at the http://localhost:8000/graphql address. You will be presented with this screen:

http://localhost:8000/graphql地址打开Web浏览器。 您将看到以下屏幕:

The GraphiQL is an interface where you can run GraphQL statements and see the results. One feature is the Docs section on the top right. Since everything in GraphQL is typed, you get free documentation about all your Types, Queries, Mutations, etc.

GraphiQL是一个界面,您可以在其中运行GraphQL语句并查看结果。 其中一项功能是右上角的“ Docs部分。 由于GraphQL中的所有内容都是类型化的,因​​此您可以获得有关所有类型,查询,变异等的免费文档。

After exploring the page, insert your first Query on the main text area:

浏览页面后,在主文本区域中插入第一个查询:

query {
  urls {
    id
    fullUrl
    urlHash
    clicks
    createdAt
  }
}

This content shows how a GraphQL Query is structured: First, you use the keyword query to tell the server that you only want some data back. Next, you use the urls field defined in the shortener/schema.py file inside the Query class. From that, you explicitly request all the fields defined in the URL model using camel case-style, which is the default for GraphQL.

此内容显示了GraphQL查询的结构:首先,您使用关键字query告诉服务器您只希望返回一些数据。 接下来,您使用Query类中的shortener/schema.py文件中定义的urls字段。 由此,您可以使用驼峰式样式显式请求URL模型中定义的所有字段,这是GraphQL的默认设置。

Now, click on the play arrow button in the top left.

现在,单击左上方的播放箭头按钮

You will receive the following response, stating that you still have no URLs:

您将收到以下答复,指出您仍然没有URL:


   
   
Output
{ "data": { "urls": [] } }

This shows that GraphQL is working. In your terminal, press CTRL+C to stop your server.

这表明GraphQL正在运行。 在终端中,按CTRL+C停止服务器。

You have accomplished a lot in this step, creating the GraphQL endpoint, making a Query to fetch all URLs, and enabling the GraphiQL interface. Now, you will create Mutations to change the database.

在这一步中,您已经完成了很多工作,创建GraphQL端点,进行查询以获取所有URL,并启用GraphiQL接口。 现在,您将创建Mutations来更改数据库。

第4步-创建变异 (Step 4 — Creating Mutations)

The majority of applications have a way to change the database state by adding, updating, or deleting data. In GraphQL, these operations are called Mutations. They look like Queries but use arguments to send data to the server.

大多数应用程序都有一种通过添加,更新或删除数据来更改数据库状态的方法。 在GraphQL中,这些操作称为Mutations 。 它们看起来像查询,但是使用参数将数据发送到服务器。

To create your first Mutation, open shortener/schema.py:

要创建您的第一个Mutation,请打开shortener/schema.py

  • vim shortener/schema.py

    vim缩短器/schema.py

At the end of the file, start by adding a new class named CreateURL:

在文件末尾,首先添加一个名为CreateURL的新类:

shorty/shortener/schema.py
矮子/起酥​​油/schema.py
...
class CreateURL(graphene.Mutation):
    url = graphene.Field(URLType)

This class inherits the graphene.Mutation helper to have the capabilities of a GraphQL Mutation. It also has a property name url, defining the content returned by the server after the Mutation is completed. In this case, it will be the URLType data structure.

此类继承了graphene.Mutation助手,具有GraphQL Mutation的功能。 它还具有一个属性名称url ,定义了Mutation完成后服务器返回的内容。 在这种情况下,它将是URLType数据结构。

Next, add a subclass named Arguments to the already defined class:

接下来,将一个名为Arguments的子类添加到已定义的类中:

shorty/shortener/schema.py
矮子/起酥​​油/schema.py
...
    class Arguments:
        full_url = graphene.String()

This defines what data will be accepted by the server. Here, you are expecting a parameter named full_url with a String content:

这定义了服务器将接受哪些数据。 在这里,您需要一个带有String内容的名为full_url的参数:

Now add the following lines to create the mutate method:

现在添加以下行以创建mutate方法:

shorty/shortener/schema.py
矮子/起酥​​油/schema.py
...

    def mutate(self, info, full_url):
        url = URL(full_url=full_url)
        url.save()

This mutate method does a lot of the work by receiving the data from the client and saving it to the database. In the end, it returns the class itself containing the newly created item.

这种mutate方法通过从客户端接收数据并将其保存到数据库来完成许多工作。 最后,它返回包含新创建项目的类本身。

Lastly, create a Mutation class to hold all the Mutations for your app by adding these lines:

最后,通过添加以下行,创建一个Mutation类来保存您应用的所有Mutations:

shorty/shortener/schema.py
矮个子/shortener/schema.py
...

class Mutation(graphene.ObjectType):
    create_url = CreateURL.Field()

So far, you will only have one mutation named create_url.

到目前为止,您只有一个名为create_url突变。

The full shortener/schema.py file is shown here:

完整的shortener/schema.py文件显示在此处:

shorty/shortener/schema.py
矮子/起酥​​油/schema.py
import graphene
from graphene_django import DjangoObjectType

from .models import URL


class URLType(DjangoObjectType):
    class Meta:
        model = URL


class Query(graphene.ObjectType):
    urls = graphene.List(URLType)

    def resolve_urls(self, info, **kwargs):
        return URL.objects.all() 


class CreateURL(graphene.Mutation):
    url = graphene.Field(URLType)

    class Arguments:
        full_url = graphene.String()

    def mutate(self, info, full_url):
        url = URL(full_url=full_url)
        url.save()

        return CreateURL(url=url)


class Mutation(graphene.ObjectType):
    create_url = CreateURL.Field()

Close and save the file.

关闭并保存文件。

To finish adding the Mutation, change the shorty/schema.py file:

要完成添加变异,请更改shorty /schema.py文件:

  • vim shorty/schema.py

    vim 矮子 /schema.py

Alter the file to include the following highlighted code:

更改文件以包括以下突出显示的代码:

shorty/shorty/schema.py
shorty / shorty / schema.py
import graphene

import shortener.schema


class Query(shortener.schema.Query, graphene.ObjectType):
    pass


class Mutation(shortener.schema.Mutation, graphene.ObjectType):
    pass


schema = graphene.Schema(query=Query, mutation=Mutation)

Save and close the file. If you are not running the local server, start it:

保存并关闭文件。 如果您没有运行本地服务器,请启动它:

  • python manage.py runserver

    python manage.py运行服务器

Navigate to http://localhost:8000/graphql in your web browser. Execute your first Mutation in the GraphiQL web interface by running the following statement:

在您的Web浏览器中导航到http://localhost:8000/graphql 。 通过运行以下语句在GraphiQL Web界面中执行您的第一个Mutation:

mutation {
  createUrl(fullUrl:"https://www.digitalocean.com/community") {
    url {
      id
      fullUrl
      urlHash
      clicks
      createdAt
    }
  }
}

You composed the Mutation with the createURL name, the fullUrl argument, and the data you want in the response defined inside the url field.

您使用在url字段内定义的响应中的createURL名称, fullUrl参数和所需的数据组成了Mutation。

The output will contain the URL information you just created inside the GraphQL data field, as shown here:

输出将包含您刚刚在GraphQL data字段中创建的URL信息,如下所示:


   
   
Output
{ "data": { "createUrl": { "url": { "id": "1", "fullUrl": "https://www.digitalocean.com/community", "urlHash": "077880af78", "clicks": 0, "createdAt": "2020-01-30T19:15:10.820062+00:00" } } } }

With that, a URL was added to the database with its hashed version, as you can see in the urlHash field. Try running the Query you created in the last Step to see its result:

这样,就可以将URL及其哈希版本添加到数据库,如您在urlHash字段中urlHash 。 尝试运行在上一步中创建的查询,以查看其结果:

query {
  urls {
    id
    fullUrl
    urlHash
    clicks
    createdAt
  }
}

The output will show the stored URL:

输出将显示存储的URL:


   
   
Output
{ "data": { "urls": [ { "id": "1", "fullUrl": "https://www.digitalocean.com/community", "urlHash": "077880af78", "clicks": 0, "createdAt": "2020-03-18T21:03:24.664934+00:00" } ] } }

You can also try executing the same Query, but only asking for the fields you want.

您也可以尝试执行相同的查询,但仅询问所需的字段。

Next, try it one more time with a different URL:

接下来,使用其他网址再试一次:

mutation {
  createUrl(fullUrl:"https://www.digitalocean.com/write-for-donations/") {
    url {
      id
      fullUrl
      urlHash
      clicks
      createdAt
    }
  }
}

The output will be:

输出将是:


   
   
Output
{ "data": { "createUrl": { "url": { "id": "2", "fullUrl": "https://www.digitalocean.com/write-for-donations/", "urlHash": "703562669b", "clicks": 0, "createdAt": "2020-01-30T19:31:10.820062+00:00" } } } }

The system is now able to create short URLs and list them. In the next step, you will enable users to access a URL by its short version, redirecting them to the correct page.

系统现在可以创建短URL并列出它们。 在下一步中,您将使用户能够通过其简短版本访问URL,并将其重定向到正确的页面。

第5步-创建访问端点 (Step 5 — Creating the Access Endpoint)

In this step, you will use Django Views—a method that takes a request and returns a response—to redirect anyone accessing the http://localhost:8000/url_hash endpoint to its full URL.

在此步骤中,您将使用Django Views(一种接受请求并返回响应的方法)将访问http://localhost:8000/ url_hash端点的任何人重定向到其完整URL。

Open the shortener/views.py file with your editor:

使用编辑器打开shortener/views.py文件:

  • vim shortener/views.py

    vim shorter / views.py

To start, import two packages by replacing the contents with the following lines:

首先,通过将内容替换为以下行来导入两个软件包:

shorty/shortener/views.py
shorty / shortener / views.py
from django.shortcuts import get_object_or_404, redirect

from .models import URL

These will be explained more thoroughly later on.

这些将在以后更全面地说明。

Next, you will create a Django View named root. Add this code snippet responsible for the View at the end of your file:

接下来,您将创建一个名为root的Django视图。 在文件末尾添加负责View的以下代码段:

shorty/shortener/views.py
shorty / shortener / views.py
...

def root(request, url_hash):
    url = get_object_or_404(URL, url_hash=url_hash)
    url.clicked()

    return redirect(url.full_url)

This receives an argument called url_hash from the URL requested by a user. Inside the function, the first line tries to get the URL from the database using the url_hash argument. If not found, it returns the HTTP 404 error to the client, which means that the resource is missing. Afterwards, it increments the clicked property of the URL entry, making sure to track how many times the URL is accessed. At the end, it redirects the client to the requested URL.

这将从用户请求的URL接收一个名为url_hash的参数。 在函数内部,第一行尝试使用url_hash参数从数据库获取URL。 如果未找到,它将向客户端返回HTTP 404错误,这意味着资源丢失。 之后,它将增加URL条目的clicked属性,并确保跟踪URL的访问次数。 最后,它将客户端重定向到请求的URL。

The full shortener/views.py file is shown here:

完整的shortener/views.py文件如下所示:

shorty/shortener/views.py
shorty / shortener / views.py
from django.shortcuts import get_object_or_404, redirect

from .models import URL


def root(request, url_hash):
    url = get_object_or_404(URL, url_hash=url_hash)
    url.clicked()

    return redirect(url.full_url)

Save and close the file.

保存并关闭文件。

Next, open shorty/urls.py:

接下来,打开shorty /urls.py

  • vim shorty/urls.py

    vim 矮子 /urls.py

Add the following highlighted code to enable the root View.

添加以下突出显示的代码以启用root视图。

shorty/shorty/urls.py
shorty / shorty / urls.py
from django.urls import path
from django.views.decorators.csrf import csrf_exempt

from graphene_django.views import GraphQLView

from shortener.views import root


urlpatterns = [
    path('graphql/', csrf_exempt(GraphQLView.as_view(graphiql=True))),
    path('<str:url_hash>/', root, name='root'),
]

The root View will be accessible in the / path of your server, accepting a url_hash as a string parameter.

root视图可以在服务器的/路径中访问,并接受url_hash作为字符串参数。

Save and close the file. If you are not running the local server, start it by executing the python manage.py runserver command.

保存并关闭文件。 如果您没有运行本地服务器,请通过执行python manage.py runserver命令将其启动。

To test your new addition, open your web browser and access the http://localhost:8000/077880af78 URL. Note that the last part of the URL is the hash created by the Mutation from Step 5. You will be redirected to the hash’s URL page, in this case, the DigitalOcean Community website.

要测试新添加的内容,请打开Web浏览器并访问http://localhost:8000/077880af78 URL。 请注意,URL的最后一部分是由步骤5中的Mutation创建的哈希。您将被重定向到哈希的URL页面,在本例中为DigitalOcean Community网站。

Now that you have the URL redirection working, you will make the application safer by implementing error handling when the Mutation is executed.

现在您可以使用URL重定向了,通过执行Mutation时执行错误处理,可以使应用程序更安全。

第6步-实施错误处理 (Step 6 — Implementing Error Handling)

Handling errors is a best practice in all applications, since developers don’t usually control what will be sent to the server. In this case, you can try to foresee failures and minimize their impacts. In a complex system such as GraphQL, a lot of things might go wrong, from the client asking for the wrong data to the server losing access to the database.

处理错误是所有应用程序中的最佳做法,因为开发人员通常不控制将发送给服务器的内容。 在这种情况下,您可以尝试预见失败并最大程度地减少其影响。 在诸如GraphQL之类的复杂系统中,很多事情可能会出错,从客户端请求错误的数据到服务器失去对数据库的访问权限。

As a typed system, GraphQL can verify everything the client asks for and receives in an operation called Schema Validation. You can see this in action by making a Query with a non-existing field.

作为类型化的系统,GraphQL可以在称为Schema Validation的操作中验证客户端要求和接收的所有内容。 您可以通过使用不存在的字段进行查询来查看此操作。

Navigate to http://localhost:8000/graphql in your browser once more, and execute the next Query within the GraphiQL interface, with the iDontExist field:

http://localhost:8000/graphql在浏览器中导航到http://localhost:8000/graphql ,并在GraphiQL界面中使用iDontExist字段执行下一个查询:

query {
  urls {
    id
    fullUrl
    urlHash
    clicks
    createdAt
    iDontExist
  }
}

Since there is no iDontExist field defined in your Query, GraphQL returns an error message:

由于查询中未定义iDontExist字段,因此GraphQL返回错误消息:


   
   
Output
{ "errors": [ { "message": "Cannot query field \"iDontExist\" on type \"URLType\".", "locations": [ { "line": 8, "column": 5 } ] } ] }

This is important because, in the GraphQL typed system, the aim is to send and receive just the information already defined in the schema.

这很重要,因为在GraphQL类型的系统中,目标是仅发送和接收已在模式中定义的信息。

The current application accepts any arbitrary string in the full_url field. The problem is that if someone sends a poorly constructed URL, you would be redirecting the user to nowhere when trying the stored information. In this case, you need to verify if the full_url is well formatted before saving it to the database, and, if there’s any error, raise the GraphQLError exception with a custom message.

当前应用程序在full_url字段中接受任意字符串。 问题是,如果有人发送了构造错误的URL,则在尝试存储的信息时您会将用户重定向到任何地方。 在这种情况下,您需要先检查full_url的格式是否正确,然后再将其保存到数据库中;如果有任何错误,请使用自定义消息引发GraphQLError异常。

Let’s implement this functionality in two steps. First, open the shortener/models.py file:

让我们分两步实现此功能。 首先,打开shortener/models.py文件:

  • vim shortener/models.py

    vim Shorter / models.py

Add the highlighted lines in the import section:

在导入部分中添加突出显示的行:

shorty/shortener/models.py
矮子/shortener/models.py
from hashlib import md5

from django.db import models
from django.core.validators import URLValidator
from django.core.exceptions import ValidationError

from graphql import GraphQLError
...

The URLValidator is a Django helper to validate a URL String and the GraphQLError is used by Graphene to raise exceptions with a custom message.

URLValidator是Django的帮助程序,用于验证URL字符串, GraphQLError使用GraphQLError引发自定义消息的异常。

Next, make sure to validate the URL received by the user before saving it to the database. Enable this operation by adding the highlighted code in the shortener/models.py file:

接下来,请确保在将用户收到的URL保存到数据库之前对其进行验证。 通过在shortener/models.py文件中添加突出显示的代码来启用此操作:

shorty/shortener/models.py
矮子/shortener/models.py
class URL(models.Model):
    full_url = models.URLField(unique=True)
    url_hash = models.URLField(unique=True)
    clicks = models.IntegerField(default=0)
    created_at = models.DateTimeField(auto_now_add=True)

    def clicked(self):
        self.clicks += 1
        self.save()

    def save(self, *args, **kwargs):
        if not self.id:
            self.url_hash = md5(self.full_url.encode()).hexdigest()[:10]

        validate = URLValidator()
        try:
            validate(self.full_url)
        except ValidationError as e:
            raise GraphQLError('invalid url')

        return super().save(*args, **kwargs)

First, this code instantiates the URLValidator in the validate variable. Inside the try/except block, you validate() the URL received and raise a GraphQLError with the invalid url custom message if something went wrong.

首先,此代码在validate变量中实例化URLValidator 。 在try/except块中,您validate()接收到的URL,如果GraphQLError ,则使用invalid url自定义消息引发GraphQLError

The full shortener/models.py file is shown here:

完整的shortener/models.py文件显示在此处:

shorty/shortener/models.py
矮子/shortener/models.py
from hashlib import md5

from django.db import models
from django.core.validators import URLValidator
from django.core.exceptions import ValidationError

from graphql import GraphQLError


class URL(models.Model):
    full_url = models.URLField(unique=True)
    url_hash = models.URLField(unique=True)
    clicks = models.IntegerField(default=0)
    created_at = models.DateTimeField(auto_now_add=True)

    def clicked(self):
        self.clicks += 1
        self.save()

    def save(self, *args, **kwargs):
        if not self.id:
            self.url_hash = md5(self.full_url.encode()).hexdigest()[:10]

        validate = URLValidator()
        try:
            validate(self.full_url)
        except ValidationError as e:
            raise GraphQLError('invalid url')

        return super().save(*args, **kwargs)

Save and close the file. If you are not running the local server, start it with the python manage.py runserver command.

保存并关闭文件。 如果您没有运行本地服务器,请使用python manage.py runserver命令启动它。

Next, test your new error handling at http://localhost:8000/graphql. Try to create a new URL with an invalid full_url in the GraphiQL interface:

接下来,在http://localhost:8000/graphql测试新的错误处理。 尝试在GraphiQL界面中使用无效的full_url创建一个新URL:

mutation {
  createUrl(fullUrl:"not_valid_url"){
    url {
      id
      fullUrl
      urlHash
      clicks
      createdAt
    }
  }
}

When sending an invalid URL, your exception will be raised with the custom message:

发送无效的URL时,定制消息将引发您的异常:


   
   
Output
{ "errors": [ { "message": "invalid url", "locations": [ { "line": 2, "column": 3 } ], "path": [ "createUrl" ] } ], "data": { "createUrl": null } }

If you look in your terminal where the python manage.py runserver command is running, an error will appear:

如果您在运行python manage.py runserver命令的终端中查看,则会出现错误:


   
   
Output
... graphql.error.located_error.GraphQLLocatedError: invalid url [30/Jan/2020 19:46:32] "POST /graphql/ HTTP/1.1" 200 121

A GraphQL endpoint will always fail with a HTTP 200 status code, which usually signifies success. Remember that, even though GraphQL is built on top of HTTP, it doesn’t use the concepts of HTTP status codes or HTTP methods as REST does.

GraphQL端点将始终失败,并显示HTTP 200状态代码,这通常表示成功。 请记住,即使GraphQL建立在HTTP之上,它也不会像REST那样使用HTTP状态代码或HTTP方法的概念。

With the error handling implemented, you can now put in place a mechanism to filter your Queries, minimizing the information returned by the server.

实施错误处理后,您现在就可以采用一种机制来过滤查询,从而最大程度地减少服务器返回的信息。

步骤7 —实施过滤器 (Step 7 — Implementing Filters)

Imagine you’ve started using the URL shortener to add your own links. After a while, there will be so many entries that finding the right one will become difficult. You can solve this issue using filters.

假设您已开始使用URL缩短器添加自己的链接。 一段时间后,条目将太多,以至于很难找到合适的条目。 您可以使用过滤器解决此问题。

Filtering is a common concept in REST APIs, where usually a Query Parameter with a field and value is appended to the URL. As an example, to filter all the Users named jojo, you could use GET /api/users?name=jojo.

过滤是REST API中的常见概念,通常将带有字段和值的查询参数附加到URL。 例如,要过滤所有名为jojo的用户,可以使用GET /api/users?name=jojo

In GraphQL you will use Query Arguments as filters. They create a nice and clean interface.

在GraphQL中,您将使用查询参数作为过滤器。 他们创建了一个漂亮干净的界面。

You can solve the “hard to find a URL” issue by allowing the client to filter URLs by name using the full_url field. To implement that, open the shortener/schema.py file in your favorite editor.

您可以通过允许客户端使用full_url字段按名称过滤URL来解决“很难找到URL”的问题。 为此,请在您喜欢的编辑器中打开shortener/schema.py文件。

  • vim shortener/schema.py

    vim缩短器/schema.py

First, import the Q method in the highlighted line:

首先,在突出显示的行中导入Q方法:

shorty/shortener/schema.py
矮个子/shortener/schema.py
import graphene
from graphene_django import DjangoObjectType
from django.db.models import Q

from .models import URL
...

This will be used to filter your database query.

这将用于过滤数据库查询。

Next, rewrite the whole Query class with the following content:

接下来,使用以下内容重写整个Query类:

shorty/shortener/schema.py
矮个子/shortener/schema.py
...
class Query(graphene.ObjectType):
    urls = graphene.List(URLType, url=graphene.String())

    def resolve_urls(self, info, url=None, **kwargs):
        queryset = URL.objects.all()

        if url:
            _filter = Q(full_url__icontains=url)
            queryset = queryset.filter(_filter)

        return queryset
...

The modifications you are making are:

您要进行的修改是:

  • Adding the url filter parameter inside the urls variable and resolve_url method.

    urls变量和resolve_url方法内添加url过滤器参数。

  • Inside the resolve_urls, if a parameter named url is given, filtering the database results to return only URLs that contain the value given, using the Q(full_url__icontains=url) method.

    resolve_urls内部,如果给出了名为url的参数,则使用Q(full_url__icontains=url)方法过滤数据库结果以仅返回包含给定值的Q(full_url__icontains=url)

The full shortener/schema.py file is shown here:

完整的shortener/schema.py文件显示在此处:

shorty/shortener/schema.py
矮个子/shortener/schema.py
import graphene
from graphene_django import DjangoObjectType
from django.db.models import Q

from .models import URL


class URLType(DjangoObjectType):
    class Meta:
        model = URL


class Query(graphene.ObjectType):
    urls = graphene.List(URLType, url=graphene.String())

    def resolve_urls(self, info, url=None, **kwargs):
        queryset = URL.objects.all()

        if url:
            _filter = Q(full_url__icontains=url)
            queryset = queryset.filter(_filter)

        return queryset


class CreateURL(graphene.Mutation):
    url = graphene.Field(URLType)

    class Arguments:
        full_url = graphene.String()

    def mutate(self, info, full_url)
        url = URL(full_url=full_url)
        url.save()

        return CreateURL(url=url)


class Mutation(graphene.ObjectType):
    create_url = CreateURL.Field()

Save and close the file. If you are not running the local server, start it with python manage.py runserver.

保存并关闭文件。 如果您没有运行本地服务器,请使用python manage.py runserver启动它。

Test your latest changes at http://localhost:8000/graphql. In the GraphiQL interface, write the following statement. It will filter all the URLs with the word community:

http://localhost:8000/graphql测试最新更改。 在GraphiQL接口中,编写以下语句。 它将使用单词community过滤所有URL:

query {
  urls(url:"community") {
    id
    fullUrl
    urlHash
    clicks
    createdAt
  }
}

The output is only one entry since you just added one URL with the community string in it. If you added more URLs before, your output may vary.

输出只是一个条目,因为您刚刚添加了一个带有community字符串的URL。 如果您之前添加了更多URL,则输出可能会有所不同。


   
   
Output
{ "data": { "urls": [ { "id": "1", "fullUrl": "https://www.digitalocean.com/community", "urlHash": "077880af78", "clicks": 1, "createdAt": "2020-01-30T19:27:36.243900+00:00" } ] } }

Now you have the ability to search through your URLs. However, with too many links, your clients might complain the URL list is returning more data than their apps can handle. To solve this, you will implement pagination.

现在,您可以搜索URL。 但是,由于链接太多,您的客户端可能会抱怨URL列表返回的数据超出其应用程序无法处理的范围。 为了解决这个问题,您将实现分页。

步骤8 —实施分页 (Step 8 — Implementing Pagination)

Clients using your backend might complain that the response time is taking too long or that its size is too big if there are too many URL entries. Even your database may struggle to put together a huge set of information. To solve this issue, you can allow the client to specify how many items it wants within each request using a technique called pagination.

使用您的后端的客户可能会抱怨,如果URL条目太多,响应时间会太长或响应时间太大。 甚至您的数据库也可能难以汇总大量信息。 要解决此问题,您可以允许客户使用称为pagination的技术来指定每个请求中需要多少个项目。

There’s no default way to implement this feature. Even in REST APIs, you might see it in HTTP headers or query parameters, with different names and behaviors.

没有实现此功能的默认方法。 即使在REST API中,您也可能会在HTTP标头或查询参数中看到它,并且使用不同的名称和行为。

In this application, you will implement pagination by enabling two more arguments to the URLs Query: first and skip. first will select the first variable number of elements and skip will specify how many elements should be skipped from the beginning. For example, using first == 10 and skip == 5 gets the first 10 URLs, but skips 5 of them, returning just the remaining 5.

在此应用程序中,您将通过对URL Query启用另外两个参数来实现分页: firstskipfirst将选择第一个可变数量的元素,然后skip将指定从头开始应跳过多少个元素。 例如,使用first == 10skip == 5可获得前10个URL,但跳过其中5个,仅返回其余5个。

Implementing this solution is similar to adding a filter.

实现此解决方案类似于添加过滤器。

Open the shortener/schema.py file:

打开shortener/schema.py文件:

  • vim shortener/schema.py

    vim缩短器/schema.py

In the file, change the Query class by adding the two new parameters into the urls variable and resolve_urls method, highlighted in the following code:

在文件中,通过将两个新参数添加到urls变量和resolve_urls方法中来更改Query类,在以下代码中突出显示:

shorty/shortener/schema.py
矮子/起酥​​油/schema.py
import graphene
from graphene_django import DjangoObjectType
from django.db.models import Q

from .models import URL


class Query(graphene.ObjectType):
    urls = graphene.List(URLType, url=graphene.String(), first=graphene.Int(), skip=graphene.Int())

    def resolve_urls(self, info, url=None, first=None, skip=None, **kwargs):
        queryset = URL.objects.all()

        if url:
            _filter = Q(full_url__icontains=url)
            queryset = queryset.filter(_filter)

        if first:
            queryset = queryset[:first]

        if skip:
            queryset = queryset[skip:]

        return queryset
...

This code uses the newly created first and skip parameters inside the resolve_urls method to filter the database query.

此代码在resolve_urls方法中使用新创建的firstskip参数来过滤数据库查询。

Save and close the file. If you are not running the local server, start it with python manage.py runserver.

保存并关闭文件。 如果您没有运行本地服务器,请使用python manage.py runserver启动它。

To test the pagination, issue the following Query in the GraphiQL interface at http://localhost:8000/graphql:

要测试分页,请在GraphiQL接口的http://localhost:8000/graphql发出以下查询:

query {
  urls(first: 2, skip: 1) {
    id
    fullUrl
    urlHash
    clicks
    createdAt
  }
}

Your URL shortener will return the second URL created in your database:

URL缩短器将返回数据库中创建的第二个URL:


   
   
Output
{ "data": { "urls": [ { "id": "2", "fullUrl": "https://www.digitalocean.com/write-for-donations/", "urlHash": "703562669b", "clicks": 0, "createdAt": "2020-01-30T19:31:10.820062+00:00" } ] } }

This shows that the pagination feature works. Feel free to play around by adding more URLs and testing different sets of first and skip.

这表明分页功能有效。 可以通过添加更多URL并测试不同的firstskip集随意进行操作。

结论 (Conclusion)

The whole GraphQL ecosystem is growing every day, with an active community behind it. It has been proven production-ready by companies like GitHub and Facebook, and now you can apply this technology to your own projects.

整个GraphQL生态系统每天都在增长,背后有一个活跃的社区。 GitHub和Facebook等公司已证明该产品已投入生产,现在您可以将该技术应用于自己的项目。

In this tutorial you created a URL shortener service using GraphQL, Python, and Django, using concepts like Queries and Mutations. But more than that, you now understand how to rely on these technologies to build web applications using the Django web framework.

在本教程中,您使用GraphQL,Python和Django使用查询和突变等概念创建了URL缩短服务。 不仅如此,您现在还了解了如何依靠这些技术来使用Django Web框架构建Web应用程序。

You can explore more about GraphQL and the tools used here in the GraphQL website and the Graphene documentation websites. Also, DigitalOcean has additional tutorials for Python and Django that you can use if you’d like to learn more about either.

您可以在GraphQL网站Graphene文档网站中探索有关GraphQL和此处使用的工具的更多信息。 此外,DigitalOcean还有其他适用于PythonDjango的教程,如果您想了解更多有关这两个的信息,可以使用它们。

翻译自: https://www.digitalocean.com/community/tutorials/how-to-create-a-url-shortener-with-django-and-graphql

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值