构建使用 Azure Cosmos DB 的 Python Flask Web 应用程序

本教程介绍如何使用 Azure Cosmos DB 通过 Azure 应用服务中托管的 Python Flask 应用程序存储和访问数据。 本教程假设读者在 Python 和 Azure 网站的用法方面具有一定的经验。

本数据库教程涵盖以下内容:

  1. 创建并预配 Azure Cosmos DB 帐户。
  2. 创建 Python Flask 应用程序。
  3. 从 Web 应用程序连接并使用 Azure Cosmos DB。
  4. 将 Web 应用程序部署到 Azure 应用服务。

通过学习本教程,将可以构建一个可对轮询进行投票的简单投票应用程序。

屏幕截图:本数据库教程创建的投票应用程序

数据库教程先决条件

在按照本文中的说明操作之前,应确保已安装下列项:

  • 一个 Azure 订阅

    或者,可以将 Azure Cosmos DB 模拟器用于本教程,该模拟器的 URI 为 https://localhost:8081,密钥为:

    C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==
    
  • 已启用 Azure 开发Python 开发Visual Studio 2017。 可以检查是否已安装这些必备组件,并在本地打开“Visual Studio 安装程序”进行安装。

  • Azure SDK for Python 2.7
  • Python 2.7。 可以使用 32 位或 64 位安装。

Important

如果首次安装 Python 2.7,请确保在自定义 Python 2.7.13 屏幕中,选择“向路径添加 python.exe”。

自定义 Python 2.7.11 屏幕的屏幕截图,需要在该屏幕中选择“向路径添加 python.exe”

步骤 1:创建 Azure Cosmos DB 数据库帐户

首先创建一个 Azure Cosmos DB 帐户。 如果已有一个帐户,或者要在本教程中使用 Azure Cosmos DB 模拟器,可以跳到步骤 2:创建新的 Python Flask 应用程序

  1. 在新浏览器窗口中,登录到 Azure 门户
  2. 单击“新建” > “数据库” > “Azure Cosmos DB”。

    Azure 门户“数据库”窗格

  3. 在“新建帐户”页上,输入新 Azure Cosmos DB 帐户的设置。

    设置 建议的值 说明
    ID 输入唯一名称 输入标识此 Azure Cosmos DB 帐户的唯一名称。 由于 documents.azure.cn 将追加到所提供的 ID 后面以创建 URI,因此,请使用唯一但可识别的 ID。

    ID 只能包含小写字母、数字和连字符 (-) 字符,并且必须包含 3 到 50 个字符。
    API SQL API 确定要创建的帐户的类型。 Azure Cosmos DB 提供了三种 API,用于满足应用程序的需求:SQL(文档数据库)、MongoDB(文档数据库)和 Azure 表,每个目前都需要单独的帐户。

    之所以选择 SQL 是因为,在本快速入门中将创建可使用 SQL 语法查询并可通过 SQL API 访问的文档数据库。

    详细了解 SQL API
    订阅 订阅 选择要用于此 Azure Cosmos DB 帐户的 Azure 订阅。
    资源组 新建

    然后输入上面在 ID 中提供的同一唯一名称
    选择“新建”,然后输入帐户的新资源组名称。 为简单起见,可以使用与 ID 相同的名称。
    位置 选择离用户最近的区域 选择要在其中托管 Azure Cosmos DB 帐户的地理位置。 使用离用户最近的位置,使他们能够以最快的速度访问数据。
    启用异地冗余 留空 这将在第二个(配对)区域中创建数据库的复制版本。 将此项留空。
    固定到仪表板 选择 选中此框,以便将新的数据库帐户添加到门户仪表板以便于访问。

    然后单击“创建” 。

    Azure Cosmos DB 的“新建帐户”边栏选项卡

  4. 创建帐户需要几分钟时间。 在创建帐户过程中,门户会在右侧显示“部署 Azure Cosmos DB”磁贴,可能需要向右滚动仪表板才能看到此磁贴。 另外,还会在屏幕顶部附近显示进度条。 你可以查看任一区域来了解进度。

    Azure 门户“通知”窗格

    创建帐户后,会显示“祝贺你!已创建 Azure Cosmos DB 帐户”页。


现在,我们演练如何从头开始新建 Python Flask Web 应用程序。

步骤 2:创建 Python Flask web 应用程序

  1. 在 Visual Studio 的“文件”菜单中,指向“新建”,并单击“项目”。

    会显示“新建项目”对话框 。

  2. 在左窗格中,依次展开“模板”、“Python”,并单击“Web”。
  3. 在中心窗格中选择“Flask Web 项目”,在“名称”框中键入“tutorial”,并单击“确定”。 请记住,Python 包的名称应全部为小写,如 Style Guide for Python Code(Python 代码风格指南)中所述。

    对于新接触 Python Flask 的人员,它是一个 Web 应用程序开发框架,可帮助更快地在 Python 中构建 Web 应用程序。

    Visual Studio 中“新建项目”窗口的屏幕截图,截图上包括左侧突出显示的 Python、中间已选中的 Python Flask Web 项目以及“名称”框中的名称“教程”

  4. 在“Python Tools for Visual Studio”窗口中,单击“安装到虚拟环境中”。

    数据库教程 - Python Tools for Visual Studio 窗口的屏幕截图

  5. 在“添加虚拟环境”窗口中选择“Python 2.7”或“Python 3.5”,在“选择解释器”框中接受其他默认值,并单击“创建”。 此操作将设置项目所需的 Python 虚拟环境。

    数据库教程 - Python Tools for Visual Studio 窗口的屏幕截图

    成功安装环境后,输出窗口会显示 Successfully installed Flask-0.10.1 Jinja2-2.8 MarkupSafe-0.23 Werkzeug-0.11.5 itsdangerous-0.24 'requirements.txt' was installed successfully.

步骤 3:修改 Python Flask Web 应用程序

将 Python Flask 包添加到项目

设置项目后,需要将所需的 Flask 包(包括 pydocumentdb - 用于 DocumentDB 的 Python 软件包)添加到项目。

  1. 在解决方案资源管理器中,打开名为 requirements.txt 的文件并将内容替换为:

     flask==0.9
     flask-mail==0.7.6
     sqlalchemy==0.7.9
     flask-sqlalchemy==0.16
     sqlalchemy-migrate==0.7.2
     flask-whooshalchemy==0.55a
     flask-wtf==0.8.4
     pytz==2013b
     flask-babel==0.8
     flup
     pydocumentdb>=1.0.0
    
  2. 保存 requirements.txt 文件。
  3. 在解决方案资源管理器中,右键单击“env”,并单击“使用 requirements.txt 安装”。

    显示 env (Python 2.7) 已选中的屏幕截图,其中突出显示了列表中的“使用 requirements.txt 安装”

    安装成功后,输出窗口显示以下信息:

     Successfully installed Babel-2.3.2 Tempita-0.5.2 WTForms-2.1 Whoosh-2.7.4 blinker-1.4 decorator-4.0.9 flask-0.9 flask-babel-0.8 flask-mail-0.7.6 flask-sqlalchemy-0.16 flask-whooshalchemy-0.55a0 flask-wtf-0.8.4 flup-1.0.2 pydocumentdb-1.6.1 pytz-2013b0 speaklater-1.3 sqlalchemy-0.7.9 sqlalchemy-migrate-0.7.2
    

    Note

    在相当少见的情况下,可能会在输出窗口中看到失败。 如果出现此情况,请检查错误是否与清理相关。 有时候清理会失败,但安装仍是成功的(在输出窗口中向上滚动以确认这一点)。 可以通过 验证虚拟环境来检查安装。 如果安装失败,但验证成功,则可以继续操作。

验证虚拟环境

我们必须确保正确安装所有内容。

  1. Ctrl+Shift+B 生成解决方案。
  2. 生成成功后,按 F5启动网站。 这会启动 Flask 开发服务器,并启动 Web 浏览器。 应该看到以下页面。

    在浏览器中显示的空 Python Flask Web 开发项目

  3. 在 Visual Studio 中按 Shift+F5 停止调试网站。

创建数据库、集合和文档定义

现在,通过添加新文件并更新其他文件来创建投票应用程序。

  1. 在解决方案资源管理器中,右键单击“教程”项目,并依次单击“添加”、“新建项”。 选择“空 Python 文件”并将该文件命名为 forms.py
  2. 将以下代码添加到 forms.py 文件,并保存该文件。
from flask.ext.wtf import Form
from wtforms import RadioField

class VoteForm(Form):
    deploy_preference  = RadioField('Deployment Preference', choices=[
        ('Web Site', 'Web Site'),
        ('Cloud Service', 'Cloud Service'),
        ('Virtual Machine', 'Virtual Machine')], default='Web Site')

将所需的导入添加到 views.py 中

  1. 在“解决方案资源管理器”中,展开 tutorial 文件夹并打开 views.py 文件。
  2. 将以下导入语句添加到 views.py 文件的顶部,并保存该文件。 这些语句将导入 Azure Cosmos DB 的 PythonSDK 和 Flask 包。

    from forms import VoteForm
    import config
    import pydocumentdb.document_client as document_client
    

创建数据库、集合和文档

  • 还是在 views.py中,将以下代码添加到文件末尾。 这会创建窗体使用的数据库。 不要删除 views.py中任何现有的代码。 仅将其追加到末尾。
@app.route('/create')
def create():
    """Renders the contact page."""
    client = document_client.DocumentClient(config.DOCUMENTDB_HOST, {'masterKey': config.DOCUMENTDB_KEY})

    # Attempt to delete the database.  This allows this to be used to recreate as well as create
    try:
        db = next((data for data in client.ReadDatabases() if data['id'] == config.DOCUMENTDB_DATABASE))
        client.DeleteDatabase(db['_self'])
    except:
        pass

    # Create database
    db = client.CreateDatabase({ 'id': config.DOCUMENTDB_DATABASE })

    # Create collection
    collection = client.CreateCollection(db['_self'],{ 'id': config.DOCUMENTDB_COLLECTION })

    # Create document
    document = client.CreateDocument(collection['_self'],
        { 'id': config.DOCUMENTDB_DOCUMENT,
          'Web Site': 0,
          'Cloud Service': 0,
          'Virtual Machine': 0,
          'name': config.DOCUMENTDB_DOCUMENT 
        })

    return render_template(
       'create.html',
        title='Create Page',
        year=datetime.now().year,
        message='You just created a new database, collection, and document.  Your old votes have been deleted')

读取数据库、集合、文档,并提交窗体

  • 还是在 views.py中,将以下代码添加到文件末尾。 这会设置窗体、读取数据库、集合和文档。 不要删除 views.py中任何现有的代码。 仅将其追加到末尾。
@app.route('/vote', methods=['GET', 'POST'])
def vote(): 
    form = VoteForm()
    replaced_document ={}
    if form.validate_on_submit(): # is user submitted vote  
        client = document_client.DocumentClient(config.DOCUMENTDB_HOST, {'masterKey': config.DOCUMENTDB_KEY})

        # Read databases and take first since id should not be duplicated.
        db = next((data for data in client.ReadDatabases() if data['id'] == config.DOCUMENTDB_DATABASE))

        # Read collections and take first since id should not be duplicated.
        coll = next((coll for coll in client.ReadCollections(db['_self']) if coll['id'] == config.DOCUMENTDB_COLLECTION))

        # Read documents and take first since id should not be duplicated.
        doc = next((doc for doc in client.ReadDocuments(coll['_self']) if doc['id'] == config.DOCUMENTDB_DOCUMENT))

        # Take the data from the deploy_preference and increment our database
        doc[form.deploy_preference.data] = doc[form.deploy_preference.data] + 1
        replaced_document = client.ReplaceDocument(doc['_self'], doc)

        # Create a model to pass to results.html
        class VoteObject:
            choices = dict()
            total_votes = 0

        vote_object = VoteObject()
        vote_object.choices = {
            "Web Site" : doc['Web Site'],
            "Cloud Service" : doc['Cloud Service'],
            "Virtual Machine" : doc['Virtual Machine']
        }
        vote_object.total_votes = sum(vote_object.choices.values())

        return render_template(
            'results.html', 
            year=datetime.now().year, 
            vote_object = vote_object)

    else :
        return render_template(
            'vote.html', 
            title = 'Vote',
            year=datetime.now().year,
            form = form)

创建 HTML 文件

  1. 在解决方案资源管理器中的 tutorial 文件夹中,右键单击 templates 文件夹,并依次单击“添加”、“新建项”。
  2. 选择“HTML 页”,并在名称框中键入 create.html
  3. 重复步骤 1 和步骤 2,以创建另外两个 HTML 文件:results.html 和 vote.html。
  4. 将以下代码添加到 <body> 元素中的 create.html。 它显示一条消息,说明我们创建了新的数据库、集合和文档。

    {% extends "layout.html" %}
    {% block content %}
    <h2>{{ title }}.</h2>
    <h3>{{ message }}</h3>
    <p><a href="{{ url_for('vote') }}" class="btn btn-primary btn-large">Vote &raquo;</a></p>
    {% endblock %}
    
  5. 将以下代码添加到 <body> 元素中的 results.html。 它会显示轮询结果。

    {% extends "layout.html" %}
    {% block content %}
    <h2>Results of the vote</h2>
        <br />
    
    {% for choice in vote_object.choices %}
    <div class="row">
        <div class="col-sm-5">{{choice}}</div>
            <div class="col-sm-5">
                <div class="progress">
                    <div class="progress-bar" role="progressbar" aria-valuenow="{{vote_object.choices[choice]}}" aria-valuemin="0" aria-valuemax="{{vote_object.total_votes}}" style="width: {{(vote_object.choices[choice]/vote_object.total_votes)*100}}%;">
                                {{vote_object.choices[choice]}}
                </div>
            </div>
            </div>
    </div>
    {% endfor %}
    
    <br />
    <a class="btn btn-primary" href="{{ url_for('vote') }}">Vote again?</a>
    {% endblock %}
    
  6. 将以下代码添加到 <body> 元素中的 vote.html。 它会显示轮询并接受投票。 注册投票时,控件权会传递到 views.py 中,Azure Cosmos DB 会在该位置识别投票并相应地追加文档。

    {% extends "layout.html" %}
    {% block content %}
    <h2>What is your favorite way to host an application on Azure?</h2>
    <form action="" method="post" name="vote">
        {{form.hidden_tag()}}
            {{form.deploy_preference}}
            <button class="btn btn-primary" type="submit">Vote</button>
    </form>
    {% endblock %}
    
  7. templates 文件夹中,将 index.html 的内容替换为以下内容。 这会作为你的应用程序的登录页。

    {% extends "layout.html" %}
    {% block content %}
    <h2>Python + Azure Cosmos DB Voting Application.</h2>
    <h3>This is a sample Cosmos DB voting application using PyDocumentDB</h3>
    <p><a href="{{ url_for('create') }}" class="btn btn-primary btn-large">Create/Clear the Voting Database &raquo;</a></p>
    <p><a href="{{ url_for('vote') }}" class="btn btn-primary btn-large">Vote &raquo;</a></p>
    {% endblock %}
    

添加配置文件并更改 __init__.py

  1. 在解决方案资源管理器中,右键单击 tutorial 项目,依次单击“添加”、“新建项”,选择“空 Python 文件”,并将该文件命名为 config.py。 Flask 中的窗体需要此配置文件。 也可将其用于提供机密密钥。 但此教程不需要此密钥。
  2. 将以下代码添加到 config.py,需要在下一步更改 DOCUMENTDB_HOSTDOCUMENTDB_KEY 的值。

    CSRF_ENABLED = True
    SECRET_KEY = 'you-will-never-guess'
    
    DOCUMENTDB_HOST = 'https://YOUR_DOCUMENTDB_NAME.documents.azure.cn:443/'
    DOCUMENTDB_KEY = 'YOUR_SECRET_KEY_ENDING_IN_=='
    
    DOCUMENTDB_DATABASE = 'voting database'
    DOCUMENTDB_COLLECTION = 'voting collection'
    DOCUMENTDB_DOCUMENT = 'voting document'
    
  3. Azure 门户中,依次单击“浏览”、“Azure Cosmos DB 帐户”导航到“密钥”页,双击要使用的帐户名,并单击“概要”区域中的“密钥”按钮。 在“密钥”页中,复制“URI”值并将其粘贴到 config.py 文件中,作为 DOCUMENTDB_HOST 属性的值。
  4. 返回到 Azure 门户,在“密钥”页中,复制“主密钥”或“辅助密钥”的值,并将其粘贴到 config.py 文件,作为 DOCUMENTDB_KEY 属性的值。
  5. __init__.py 文件中添加以下行:

     app.config.from_object('config')
    

    因此,该文件的内容应为:

    from flask import Flask
    app = Flask(__name__)
    app.config.from_object('config')
    import tutorial.views
    
  6. 添加所有文件后,解决方案资源管理器应如下所示:

    Visual Studio 解决方案资源管理器窗口的屏幕截图

步骤 4:本地运行 Web 应用程序

  1. Ctrl+Shift+B 生成解决方案。
  2. 生成成功后,按 F5启动网站。 应会在屏幕上看到以下内容:

    在 Web 浏览器中显示的 Python + Azure Cosmos DB 投票应用程序的屏幕截图

  3. 单击“创建/清除投票数据库” 以生成数据库。

    Web 应用程序的创建页面 — 开发详细信息的屏幕截图

  4. 然后,单击“投票”并选择选项。

    提出了一个投票问题的 Web 应用程序的屏幕截图

  5. 对于所投的每一票,它都增加了相应的计数器。

    投票页面所示的结果的屏幕截图

  6. 按 Shift+F5 停止调试该项目。

步骤 5:将 Web 应用程序部署到 Azure

创建可在本地针对 Azure Cosmos DB 正常工作的完整应用程序后,我们要创建一个 web.config 文件,将服务器上的文件更新为与本地环境匹配,然后在 Azure 中查看已完成的应用。 此过程只能在 Visual Studio 2017 中执行。 如果使用其他 Visual Studio 版本,请参阅发布到 Azure 应用服务

  1. 在 Visual Studio 的“解决方案资源管理器”中,右键单击项目,并选择“添加”>“新建项...”。在显示的对话框中,选择“Azure web.config (Fast CGI)”模板,再选择“确定”。 随后会在项目根目录中创建一个 web.config 文件。

  2. 修改 web.config 中的 <system.webServer> 节,使路径与 Python 安装匹配。 例如,对于 Python 2.7 x64,该条目应如下所示:

    <system.webServer>
        <handlers>
            <add name="PythonHandler" path="*" verb="*" modules="FastCgiModule" scriptProcessor="D:\home\Python27\python.exe|D:\home\Python27\wfastcgi.py" resourceType="Unspecified" requireAccess="Script"/>
        </handlers>
    </system.webServer>
    
  3. web.config 中的 WSGI_HANDLER 条目设置为 tutorial.app,使之与项目名称匹配。

    <!-- Flask apps only: change the project name to match your app -->
    <add key="WSGI_HANDLER" value="tutorial.app"/>
    
  4. 在 Visual Studio 的“解决方案资源管理器”中,展开 tutorial 文件夹,右键单击 static 文件夹,并依次选择“添加”>“新建项...”、“Azure 静态文件 web.config”模板、“确定”。 此操作会在 static 中创建另一个 web.config,用于针对该文件夹禁用 Python 处理。 此配置会将静态文件的请求发送到默认的 Web 服务器,而不使用 Python 应用程序。

  5. 保存文件,右键单击解决方案资源管理器中的项目(确保不要在本地运行它),并选择“发布”。

    解决方案资源管理器中选中的教程的屏幕截图,其中突出显示了“发布”选项

  6. 在“发布”对话框中,依次选择“Azure 应用服务”和“新建”,然后单击“发布”。

    “发布 Web 窗口”的屏幕截图,其中突出显示了“Azure 应用服务”

  7. 在“创建应用服务”对话框中,输入 Web 应用名称、订阅、资源组和应用服务计划,然后单击“创建”。

    “Azure Web 应用窗口”窗口的屏幕截图

  8. 几秒钟后,Visual Studio 会完成将文件复制到服务器的过程,并 在 http://<your app service>.chinacloudsites.cn/ 页上显示“由于发生内部服务器错误,无法显示该页”。

  9. 在 Azure 门户中打开新的应用服务帐户,在导航菜单中向下滚动到“开发工具”部分,选择“扩展”,并单击“+ 添加”。

  10. 在“选择扩展”页上,向下滚动到最近的 Python 2.7 安装并选择 x86 或 x64 位选项,然后单击“确定”接受法律条款。

  11. 使用 Kudu 控制台(可通过 https://<your app service name>.scm.chinacloudsites.cn/DebugConsole 访问)安装应用的 requirements.txt 文件中所列的包。 为此,请在 Kudu 诊断控制台中导航到 Python 文件夹 D:\home\Python27,并根据 Kudu 控制台部分中所述运行以下命令:

    D:\home\Python27>python -m pip install --upgrade -r /home/site/wwwroot/requirements.txt
    
  12. 安装新包后,按“重启”按钮在 Azure 门户中重启应用服务。

    Tip

    如果对应用的 requirements.txt 文件做了任何更改,请务必重新使用 Kudu 控制台来安装该文件中现已列出的所有包。

  13. 完全配置服务器环境后,请在浏览器中刷新页面,随后应会显示该 Web 应用。

    将 Bottle、Flask 和 Django 应用发布到应用服务后的结果

    Tip

    如果该网页未出现,或者仍然出现“由于发生内部服务器错误,无法显示该页” 消息,请在 Kudo 中打开 web.config 文件,将 <httpErrors errorMode="Detailed"></httpErrors> 添加到 system.webServer 节,并刷新页面。 这样就会在浏览器中提供详细的错误输出。

故障排除

如果这是在计算机上运行的第一个 Python 应用程序,请确保下列文件夹(或等效的安装位置)包括在 PATH 变量中:

C:\Python27\site-packages;C:\Python27\;C:\Python27\Scripts;

如果在投票页上收到了错误,并且已将项目命名为 tutorial 以外的名称,请确保 __init__.py 引用以下行中正确的项目名称:import tutorial.view

后续步骤

祝贺! 现已完成第一个使用 Azure Cosmos DB 的 Python Web 应用程序并将其发布到了 Azure。

要将其他功能添加到 Web 应用程序,请查看 Azure Cosmos DB Python SDK中提供的 API。

有关 Azure、Visual Studio 和 Python 的详细信息,请参阅 Python 开发人员中心

有关其他 Python Flask 教程,请参阅 The Flask Mega-Tutorial, Part I: Hello, World!(Flask 大型教程,第 I 部分:Hello, World!)。