CockroachDB是一个分布式的关系型数据库,使用户可以不受硬件限制地扩展他们的应用和生产软件。CockroachDB Serverless是开始使用这个关系型数据库的最快方式。它只需要两个步骤:使用你的GitHub账户注册,然后使用与你的系统操作系统相关的连接信息连接你的集群。
由于CockroachDB功能丰富的对象关系映射(ORM)让我们可以使用流畅的面向对象的API与数据库进行交互,因此将CockroachDB集成到Django应用程序中是无缝的。
在这篇文章中,我们将通过使用Django ORM构建一个简单的应用程序,通过CockroachCloud与CockroachDB进行通信,来探索CockroachDB和Django的合作情况。然后我们将把我们的应用程序部署到Heroku。
最终的应用将是一个游戏排行榜,它可以让用户输入关于他们游戏的信息,然后将这些数据存储在数据库中。然后,用户界面检索这些数据,以显示用户玩了哪些游戏,玩了多少小时,以及更多信息。
在学习本教程时,熟悉Python和Django会有所帮助。还需要注意的是,该文章使用Python 3.8或Python 3.9作为推荐的Python版本。而且,如果你想看最终的文件,该应用程序的源代码可以通过GitHub获得。
如何设置CockroachDB和安装Django
在本教程中,我们需要确保我们注册了一个CockroachDB账户。
为了启动我们的应用程序,我们首先要在系统中安装pip ,以便能够安装python包。这篇文档提供了如何根据所使用的操作系统安装pip 的步骤。
接下来,我们创建一个名为cockroachDB 的项目目录。在这个目录中,我们创建一个虚拟环境,venv ,并激活它。然后我们安装Django,如下图所示。
mkdir cockroachDB
cd cockroachDB
python3 -m venv venv
source venv/bin/activate
pip install django==3.2.9
注意,在创建虚拟环境时,我们需要根据所使用的操作系统,使用以下命令之一来激活环境。
- Linux/MacOS:使用source
venv/bin/activate - Windows:如果你使用基于cmd的终端,使用
\venv\Scripts\activate',如果你运行PowerShell,使用'.\venv\Scripts\activate.ps1'
设置好应用程序后,我们继续创建一个名为game 的Django项目和一个名为core 的Django应用程序。
django-admin startproject game .
python3 manage.py startapp core
我们需要记住将Django应用添加到项目的game/settings.py 文件中的已安装应用列表中,如下图所示。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'core.apps.CoreConfig', #Add
]
我们首先运行python manage.py migrate 来应用迁移。然后,我们使用python manage.py runserver ,执行应用程序,它为默认的Django应用程序提供服务,就像下面的截图。
如何添加CockroachDB(而不是SQLite)
Django默认使用SQLite,甚至在我们创建一个新的应用程序时也会生成一个新的SQLite数据库。然而,我们想使用CockroachDB,所以我们需要建立一个集群并创建一个数据库供我们的应用程序使用。
首先,在我们的CockroachDB无服务器账户中,我们进入创建集群页面,选择CockroachDB无服务器作为我们的首选类型。然后,我们在集群页面上点击创建你的免费集群来创建一个集群。
另一个可用的计划是Dedicated,这是一个基于高级的计划,具有附加功能,允许用户拥有多区域的能力。当创建一个免费集群时,我们可以选择保留默认参数。这些参数包括云提供商、区域、支出限额和集群名称。
创建集群后,CockroachDB Serverless会弹出一个连接信息框。在这里,我们用基于操作系统的默认SQL用户创建一个集群连接。我们从选择你的操作系统下拉菜单中选择适当的选项。
请注意,连接信息包含一个密码,这个密码将只提供一次。我们需要确保保存这个字符串的密码,因为我们以后会用到它。
cockroach sql --url='postgres://:@:26257/.defaultdb?sslmode=verify-full&sslrootcert=/cc-c
a.crt'
接下来,我们使用提供的命令下载CockroachDB客户端和CA证书。它应该看起来像下面的例子。
curl --create-dirs -o ~/.postgresql/root.crt -O
https://cockroachlabs.cloud/clusters//cert
我们使用命令cockroach sql --url ,使用我们之前保存的连接字符串连接到我们的数据库。连接字符串的例子如下所示。
cockroach sql --url
'postgresql://:@:26257/defaultdb?sslmode=verify-full&sslrootcert='$HOME'/.postgresql/root.crt&options=--cluster=-'
我们应该看到类似这样的输出。
现在,我们在sql shell中为我们的应用程序创建一个名为game 的数据库。我们用下面的命令来做这件事。
> CREATE DATABASE game;
使用该命令退出。
> \q.
接下来,我们用下面的命令在CockroachDB应用程序的根目录下创建certs 文件夹。
mkdir certs
然后,我们将root.crt 文件复制到certs 文件夹中,自定义该文件的路径。
cp -p $HOME/.postgresql/root.crt /path/to/cockroachDB/certs
接下来,我们需要将certs 目录添加到.gitignore 文件中,这样我们的证书就不会在GitHub上出现。
首先,我们通过终端在项目的根目录下输入touch 命令来创建.gitignore 文件。
touch .gitignore
然后,我们将certs/ 加入到.gitignore 文件中。
如何安装在Django中使用CockroachDB的依赖项
为了在Django中使用CockroachDB,我们需要使用pip :django,psycopg2,dj-database-url, 和django-cockroachdb 来安装一些依赖项。我们还需要安装一些额外的依赖项,这些依赖项将在将我们的应用程序部署到Heroku时使用:django-heroku,gunicorn, 和whitenoise 。我们用下面的命令一次性安装它们。
pip install psycopg2-binary dj-database-url django-cockroachdb==3.2.1 django-crispy-forms django-on-heroku django-environ whitenoise gunicorn
安装完依赖关系后,我们使用命令pip freeze > requirements.txt 来创建requirement.txt 文件,并列出我们应用程序的依赖关系。
我们的requirements.txt 文件如下。
asgiref==3.4.1
dj-database-url==0.5.0
Django==3.2.9
django-cockroachdb==3.2.1
django-crispy-forms==1.14.0
django-on-heroku==1.1.2
gunicorn==20.1.0
psycopg2-binary==2.9.3
pytz==2021.3
sqlparse==0.4.2
whitenoise==5.3.0
确保主要的django-cockroachdb 和django 版本对应。例如,django-cockroachdb 3.2.x 是与django 3.2.x.
请注意,为了使其发挥作用,我们需要确保我们已经创建了虚拟环境并激活了它,就像我们在本教程前面所做的那样。
如何配置CockroachDB
有三种方法可以将我们的应用程序连接到CockroachDB:命令行、连接字符串或连接参数。我们将在这个应用程序中使用连接参数。
然后,在game/settings.py ,我们添加CockcoachDB数据库。
import os
import environ
import dj_database_url
# reading .env file
env = environ.Env()
environ.Env.read_env()
………………….
DATABASES = {
'default': {
'ENGINE': 'django_cockroachdb',
'NAME': env('DATABASE_NAME'),
'USER': env('DATABASE_USER'),
'PASSWORD': env('DATABASE_PASS'),
'HOST': env('DATABASE_HOST'),
'PORT': env('DATABASE_PORT'),
},
}
在上面的代码中,我们首先导入os ,environ ,和dj_database_url ,因为database_url 需要它们。然后通过pip install django-environ ,安装env() ,并通过创建一个实例使其可读。
代码将所有的数据库凭证放在game/.env 文件中。
SECRET_KEY是Django部署到Heroku时的一个要求。DATABASE_NAME是游戏,是我们在SQL shell中创建的数据库。我们从CockroachDB账户的连接参数标签中的连接信息中复制数据库名称的准确组合。我们首先需要选择数据库名称,并在连接信息对话框的设置部分将其从defaultdb改为game,如下面的截图。
DATABASE_USER和DATABASE_PASS来自我们之前保存的连接字符串(我们用来连接数据库的字符串)。- 我们将使用的
DATABASE_HOST是free-tier7.aws-eu-west-1.cockroachlabs.cloud。 - CockroachDB的
DATABASE_PORT是26257。
连接参数中的数据库端口如下所示。
下面是一个game/.env 文件的例子。
SECRET_KEY=""
DATABASE_NAME="xxxx-xxx.game" # xxx-xxx is the combination from Connection parameter
DATABASE_USER=""
DATABASE_PASS=""
DATABASE_PORT="26257"
DATABASE_HOST="free-tier7.aws-eu-west-1.cockroachlabs.cloud"
如何建立游戏排行榜的网络应用
现在,我们将实现一个带有游戏排行榜的简单Web应用。该应用程序有模型、视图和模板。模型包含字段和关于其内容的信息。视图处理使用请求和响应来操作模型的逻辑。应用程序将逻辑渲染到模板上,当服务器运行时,模板可以将结果输出到浏览器上。
设置模型
首先,在应用程序的cockroachDB/core/models.py 文件中,我们添加一个游戏类。
from django.db import models
class Game(models.Model):
"""
Game model class.
"""
name = models.CharField(max_length=100)
viewer_hour = models.PositiveIntegerField()
hours_streamed = models.PositiveIntegerField()
acv_num = models.PositiveIntegerField()
creators = models.PositiveIntegerField()
streams_num = models.PositiveIntegerField()
def __str__(self):
return f'{self.name}'
当用户查看管理面板时,神奇的string __str__() ,返回游戏的名称而不是类的名称。
这个不起眼的类是我们应用程序与CockroachDB所有互动的关键。使用Game类,Django可以创建一个迁移,连接到我们的CockroachDB数据库并创建一个表来存储排行榜数据。
设置视图
在cockroachDB/core/views.py 文件中,我们首先导入Game模型,然后使用基于Django类的视图创建视图。我们创建了两个视图:一个视图列出了数据库中的条目和用户通过表单提交的条目,另一个是一个创建视图,使用户能够使用表单输入一些数据。
from django.shortcuts import render
from django.views.generic import ListView, CreateView
from .models import Game
class GameListView(ListView):
"""
Class-Based View showing the user information and game details.
"""
model = Game
template_name = 'core/index.html'
context_object_name = 'games'
paginate_by = 10
class GameCreateView(CreateView):
"""
Class-Based view detailing how to create user's information.
"""
model = Game
fields = ['name', 'viewer_hour', 'hours_streamed', 'acv_num', 'creators', 'streams_num']
上面的GameListView 代码定义了模板名称和用于迭代模板数据的上下文对象名称。GameCreateView ,没有定义模板名称。相反,我们使用默认的基于类的视图命名惯例/_.html 。上面的代码还指定了表单的字段。
设置路由
在创建模板之前,我们在应用程序中创建了一个cockroachDB/core/urls.py 文件来路由视图路径。在cockroachDB/core/urls.py ,我们导入视图并实现它们,像这样。
from django.urls import path
from .views import GameListView, GameCreateView
urlpatterns = [
path('', GameListView.as_view(), name='home'),
path('new/', GameCreateView.as_view(), name='game-create'),
]
在项目的game/urls.py ,我们通过导入include来传递应用程序的路径urls.py ,并像这样实现它。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('core.urls')),
]
创建模板
为了创建模板,我们创建了一个名为cockroachDB/core/templates 的目录,里面有一个名为core 的目录。
注意,这种架构是Django的惯例。我们可以用或不用它来制作模板,但建议使用它。
我们首先创建cockroachDB/core/templates/core/base.html 模板,以便其他模板可以继承它。
在cockroachDB/core/templates/core/base.html 文件中,我们可以使用Bootstrap 5、Font Awesome和CSS,通过导入内容交付网络(CDN)来实现快速风格化。然后,我们创建导航条并传递模板块,使其具有可扩展性。代码实现如下。
{% load static %}
Top Games LeadBoard
Top Games Leaderboard
{% block content %}{% endblock content %}
上面的代码加载静态,这样应用程序就可以访问在静态文件夹中的CSS。
显示数据
为了显示用户条目和数据库数据,我们在cockroachDB/core/templates/core/index.html 文件中创建一个表,并对上下文类对象进行迭代。首先,我们需要扩展base.html 文件并在模板块中传递表,像这样。
{% extends 'core/base.html' %}
{% block content %}
{% for game in games %}
{% endfor %}
#NameViewer HoursHours StreamedACVCreatorsStreams{{page_obj.start_index|add:forloop.counter0}}{{game.name}}{{game.viewer_hour}}{{game.hours_streamed}}{{game.acv_num}}{{game.creators}}{{game.streams_num}}
{% endblock content %}
创建一个表单
我们需要创建一个模板表单来直接向应用程序添加数据。django-crispy-forms 应用程序有助于使表单看起来很好。首先,我们使用命令pip install django-crispy-forms ,通过终端安装表单控制的应用程序。然后,我们将crispy_forms 添加到cockroachDB/game/settings.py 文件中的已安装应用程序列表中,如下图所示。
…….
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'core.apps.CoreConfig',
'crispy_forms', #Add
]
…….
我们还将下面的设置模板包添加到cockroachDB/game/settings.py 文件中。
#setting template pack
CRISPY_TEMPLATE_PACK = 'bootstrap4'
接下来,我们将以下代码添加到cockroachDB/core/templates/core/game_form.html ,以创建表单。
{% extends 'core/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
{% csrf_token %}
Game Form
{{ form | crispy}}
Submit
{% endblock %}
该代码像以前一样扩展了cockroachDB/core/templates/core/base.html ,然后加载crispy-forms 标签并创建表单。
在浏览器中,该表单看起来像这样。
改进用户界面
一个模范的用户界面(UI)设计应该在导航条上有一个图标,用来向应用程序添加数据。条目也需要分页,所以我们对cockroachDB/core/templates/core/base.html 文件进行了这些修改。
{% load static %}
Top Games Leaderboard
Top Games Leaderboard
{% if page_obj.has_previous %}
{% endif %}
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
{% if page_obj.has_next %}
{% endif %}
{% block content %}{% endblock content %}
用户现在可以使用表单添加信息,而应用程序将这些信息存储在数据库中。
为了进一步改善用户界面,让我们创建一些CSS。在应用程序的核心目录下,我们创建一个名为static 的文件夹。在这个文件夹中,我们创建另一个名为css 的目录,然后创建一个名为core.css 的文件。
mkdir static && cd static
mkdir css && cd css
touch core.css
在core.css 文件中,我们添加以下CSS。
/* Google Fonts */
@import url('https://fonts.googleapis.com/css2?family=Abel&display=swap');
/* Navbar styles */
body {
font-family: 'Abel', sans-serif;
background: #fafafa;
color: #333333;
}
.navbar-brand {
font-weight: bold;
}
.game-table {
margin-bottom: 10%;
}
/* Game form */
.content-section {
background: #ffffff;
padding: 10px 20px;
border: 1px solid #dddddd;
border-radius: 3px;
margin-bottom: 20px;
font-size: 17px;
margin-top: 20px;
padding-bottom: 30px;
}
.list-color.td {
color: #a2afb8;
}
重定向用户
在通过表单输入数据后,我们想把用户重定向到索引页,在那里显示所有的数据。为了实现重定向,我们去core/models.py 文件并导入反向函数。然后,我们添加下面这个函数来处理重定向。
from django.urls import reverse
# ...existing code
# Handles redirect
def get_absolute_url(self):
return reverse('home')
迁移数据库
我们已经添加了我们的应用程序需要运行的所有代码。剩下的就是生成并运行一个迁移,在CockroachDB中为我们的游戏数据制作一个表。
让我们通过导航到我们项目的根目录并运行来迁移我们的数据库。
python manage.py makemigrations core
python manage.py migrate
如果我们在CockroachDB账户中检查我们的数据库,我们可以看到我们的表。
就这样了!我们已经创建了数据库表,我们的应用程序已经准备好了。通过运行以下命令启动开发服务器。
python manage.py runserver
我们在网页浏览器中导航到http://localhost:8000,在那里我们会看到一个空表。这是因为我们还没有在数据库中添加任何游戏。现在让我们来做这件事。
我们加载http://localhost:8000/new,打开我们先前添加的游戏创建表格。我们添加一些游戏,然后导航回http://localhost:8000。我们应该看到像这样的东西。
如何部署应用程序
要将应用程序部署到Heroku,我们首先需要确保Heroku CLI已经安装在我们的本地系统中。我们的应用程序还需要一些依赖项来在Heroku中托管:django-heroku ,gunicorn ,和whitenoise ,这些是我们之前安装的。Django在生产中不提供静态文件,所以我们将使用whitenoise 来启用这一支持。
配置依赖性
我们在项目的根目录下创建一个名为Procfile 的文件,并在该文件中添加web:gunicorn game.wsgi (`game`是项目名称)。这个规范表明,我们的应用程序是一个使用gunicorn ,一个Web服务器获取的Web应用程序。
在我们的game/settings.py 文件中,然后在文件顶部的导入部分添加django-heroku的导入。
#...existing imports
import django_on_heroku
我们还需要添加django_on_heroku.settings(locals()) 来激活Django-Heroku,并添加STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') 来配置我们的静态资产。在这一点上,settings.py 文件看起来像这样。
import os
import environ
import django_on_heroku
import dj_database_url
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# reading .env file
env = environ.Env()
environ.Env.read_env()
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env('SECRET_KEY')
# SECURITY WARNING: don't run with debug turned on in production!
# DEBUG = os.environ['DEBUG']
DEBUG = True
ALLOWED_HOSTS = ['*']
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'core.apps.CoreConfig',
'crispy_forms',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'game.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'game.wsgi.application'
DATABASES = {
'default': {
'ENGINE': 'django_cockroachdb',
'NAME': env('DATABASE_NAME'),
'USER': env('DATABASE_USER'),
'PASSWORD': env('DATABASE_PASS'),
'HOST': env('DATABASE_HOST'),
'PORT': env('DATABASE_PORT'),
},
}
# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
USE_THOUSAND_SEPARATOR = True
THOUSAND_SEPARATOR=','
DECIMAL_SEPARATOR='.'
NUMBER_GROUPING=3
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'
#setting template pack
CRISPY_TEMPLATE_PACK = 'bootstrap4'
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
django_on_heroku.settings(locals())
现在我们已经配置好了我们的依赖关系,我们到终端输入以下命令来初始化Git并创建我们的应用程序。
git init
heroku login
heroku create djangocockroachdb
在Heroku中创建应用程序的同时也建立了一个名为heroku 的远程,我们需要在这里推送应用程序。为了添加和提交更改,并将应用程序推送到Heroku,我们输入以下命令。
git add -A && git commit -m "feat: initial commit"
git push heroku main
默认情况下,Git会创建一个名为master 的分支,但你可以通过使用git branch -M main 来改变这个名字,变成一个首选的名字,如main 。
我们在game/settings.py 文件中添加部署的应用程序的链接到ALLOWED_HOSTS ,像这样。
ALLOWED_HOSTS = ['djangocockroachdb.herokuapp.com']
将文件推送到Heroku
接下来,我们添加文件,提交,并将其推送到远程heroku 。下面是一个例子。
git add -A && git commit -m "feat: update commit"
git push heroku main
首先,我们需要禁用collectstatic ,输入命令heroku config:set DISABLE_COLLECTSTATIC=1 ,并使用heroku config:set 选项将.env 文件中声明的变量添加到Heroku中,像这样。
heroku config:set SECRET_KEY=
heroku config:set DATABASE_NAME=
heroku config:set DATABASE_USER=
heroku config:set DATABASE_PASS=
heroku config:set DATABASE_PORT=26257
heroku config:set DEBUG=True
heroku config:set DATABASE_HOST=free-tier7.aws-eu-west-1.cockroachlabs.cloud
我们也可以通过Heroku仪表板中的设置,通过Config var 标签直接将变量添加到Heroku中。在添加了我们的.env 值之后,Config var 应该看起来像这样的图片。
由于我们在配置数据库时没有使用CockroachDB的连接字符串,我们需要进行数据库迁移来注册我们的数据库模式,像这样。
heroku run python manage.py makemigrations core
heroku run python manage.py migrate
为了确认应用程序的部署是否没有任何错误,我们在终端运行命令heroku open 。输出结果应该是这样的。
CockroachDB Serverless将我们的数据保存在云端,因此我们可以从任何地方访问我们的游戏排行榜信息。
接下来的步骤
现在我们已经创建了一个简单的Django应用程序,使用CockroachDB--通过CockroachDB Serverless--作为数据库,并将该应用程序部署到Heroku。在使用CockroachDB的连接字符串时,我们不需要迁移我们的数据库。
现在你知道了Django和CockroachDB的合作情况,你可以通过添加更多字段或显示多个用户的信息来改进你的应用程序。这段代码也可以为任何独特的新应用提供基础,在无服务器数据库中存储和访问信息。
注册一个CockroachDB账户,开始构建你自己的由CockroachDB无服务器数据库支持的Django网络应用。