本快速入门介绍如何从 Python 应用程序访问 Azure Cosmos DB API for Table 。 Azure Cosmos DB for Table 是一种无架构数据存储,允许应用程序在云中存储结构化 NoSQL 数据。 由于数据存储在无架构设计中,因此将具有新特性的对象添加到表中时,系统会自动向表中添加新属性(列)。 Python 应用程序可以使用 适用于 Python 的 Azure 数据表 SDK 包访问 Azure Cosmos DB for Table。

示例应用程序是用 Python 3.7 或更高版本 编写的,不过这些原则适用于所有 Python 3.7+ 应用程序。 可以使用 Visual Studio Code 作为 IDE。

如果还没有 Azure 订阅 ,可以在开始前创建一个 免费帐户

示例应用程序

可以从存储库 https://github.com/Azure-Samples/msdocs-azure-tables-sdk-python-flask 克隆或下载本教程的示例应用程序。

git clone https://github.com/Azure-Samples/msdocs-azure-tables-sdk-python-flask.git

示例存储库中包含 1-starter-app2-completed-app 示例文件夹。 1-starter-app 具有一些功能,可让你完成标记了“#TODO”的行。 本文中显示的代码片段是完成 1-starter-app 的建议附加代码。

已完成的示例应用程序使用天气数据作为示例来演示 API for Table 的功能。 表示天气观察值的对象使用 API for Table 进行存储和检索,其中就包括存储具有额外属性的对象以演示 API for Table 的无架构功能。 下图显示了在浏览器中运行的本地应用程序,其中显示了存储在 Azure Cosmos DB for Table 中的天气数据。

1 - 创建 Azure Cosmos DB 帐户

首先需要创建一个 Azure Cosmos DB Tables API 帐户,该帐户将包含应用程序中使用的表。 使用 Azure 门户、Azure CLI 或 Azure PowerShell 创建帐户。

Azure 门户 Azure CLI Azure PowerShell 在“创建 Azure Cosmos DB 帐户 - Azure 表”页上填写表单,如下所示。
  • 通过选择“资源组”下的“新建”链接,为名为 rg-msdocs-tables-sdk-demo 的存储帐户创建一个新资源组。
  • 为存储帐户指定名称 cosmos-msdocs-tables-sdk-demo-XYZ,其中的 XYZ 是三个任意的随机字符,用于创建唯一的帐户名称。 Azure Cosmos DB 帐户名称必须为 3 到 44 个字符长,并且只能包含小写字母、数字或连字符 (-)。
  • 选择存储帐户的区域。
  • 选择“标准”性能。
  • 在“容量模式”下,为此示例选择“预配吞吐量”。
  • 对于此示例,请在“应用免费层折扣”下选择“应用”。
  • 选择屏幕底部的“查看 + 创建”按钮,然后选择摘要屏幕上的“创建”以创建 Azure Cosmos DB 帐户。 此过程可能需要数分钟。
  • 使用 az cosmosdb create 命令来创建 Cosmos DB 帐户。 必须包含 --capabilities EnableTable 选项才能在 Azure Cosmos DB 中启用表存储。 由于所有 Azure 资源必须包含在资源组中,因此以下代码片段还会为 Azure Cosmos DB 帐户创建资源组。

    Azure Cosmos DB 帐户名称的长度必须介于 3 到 44 个字符之间,并且只能包含小写字母、数字和连字符 (-) 字符。 此外,Azure Cosmos DB 帐户名称在整个 Azure 中必须唯一。

    可以在 Azure Cloud Shell 中或装有 Azure CLI 的工作站上运行 Azure CLI 命令。

    Azure Cosmos DB 帐户创建过程通常需要几分钟才能完成。

    LOCATION='eastus'
    RESOURCE_GROUP_NAME='rg-msdocs-tables-sdk-demo'
    COSMOS_ACCOUNT_NAME='cosmos-msdocs-tables-sdk-demo-123'    # change 123 to a unique set of characters for a unique name
    az group create \
        --location $LOCATION \
        --name $RESOURCE_GROUP_NAME
    az cosmosdb create \
        --name $COSMOS_ACCOUNT_NAME \
        --resource-group $RESOURCE_GROUP_NAME \
        --capabilities EnableTable
    

    Azure Cosmos DB 帐户使用 New-AzCosmosDBAccount cmdlet 来创建。 必须包含 -ApiKind "Table" 选项才能在 Azure Cosmos DB 中启用表存储。 由于所有 Azure 资源必须包含在资源组中,因此以下代码片段还会为 Azure Cosmos DB 帐户创建资源组。

    Azure Cosmos DB 帐户名称的长度必须介于 3 到 44 个字符之间,并且只能包含小写字母、数字和连字符 (-) 字符。 Azure Cosmos DB 帐户名称还必须在 Azure 中是唯一的。

    Azure PowerShell 命令可以在 Azure Cloud Shell 中或是安装了 Azure PowerShell 的工作站上运行。

    Azure Cosmos DB 帐户创建过程通常需要几分钟才能完成。

    $location = 'eastus'
    $resourceGroupName = 'rg-msdocs-tables-sdk-demo'
    $cosmosAccountName = 'cosmos-msdocs-tables-sdk-demo-123'  # change 123 to a unique set of characters for a unique name
    # Create a resource group
    New-AzResourceGroup `
        -Location $location `
        -Name $resourceGroupName
    # Create an Azure Cosmos DB 
    New-AzCosmosDBAccount `
        -Name $cosmosAccountName `
        -ResourceGroupName $resourceGroupName `
        -Location $location `
        -ApiKind "Table"
    

    2 - 创建表

    接下来,需要在 Azure Cosmos DB 帐户中创建表,以供应用程序使用。 与传统数据库不同,只需指定表的名称,无需指定表中的属性(列)。 将数据加载到表中时,属性(列)会根据需要自动创建。

    Azure 门户 Azure CLI Azure PowerShell 在Azure 门户,导航到 Azure Cosmos DB 帐户的概述页。
  • 可以通过在顶部搜索栏中键入 Azure Cosmos DB 帐户的名称 (cosmos-msdocs-tables-sdk-demo-XYZ) 并在资源标题下进行查看,导航到 Azure Cosmos DB 帐户的概述页。

  • 选择 Azure Cosmos DB 帐户的名称以转到概述页。

    az cosmosdb table create \ --account-name $COSMOS_ACCOUNT_NAME \ --resource-group $RESOURCE_GROUP_NAME \ --name $COSMOS_TABLE_NAME \ --throughput 400 # Create the table for the application to use New-AzCosmosDBTable ` -Name $cosmosTableName ` -AccountName $cosmosAccountName ` -ResourceGroupName $resourceGroupName

    3 - 获取 Azure Cosmos DB 连接字符串

    若要访问 Azure Cosmos DB 中的表,你的应用需要 CosmosDB 存储帐户的表连接字符串。 可以使用 Azure 门户、Azure CLI 或 Azure PowerShell 检索该连接字符串。

    Azure 门户 Azure CLI Azure PowerShell

    要使用 Azure CLI 获取主连接字符串,请使用 az cosmosdb keys list 命令并指定选项 --type connection-strings。 此命令使用 JMESPath 查询,以便仅显示主表连接字符串。

    # This gets the primary connection string
    az cosmosdb keys list \
        --type connection-strings \
        --resource-group $RESOURCE_GROUP_NAME \
        --name $COSMOS_ACCOUNT_NAME \
        --query "connectionStrings[?description=='Primary Table Connection String'].connectionString" \
        --output tsv
    

    要使用 Azure PowerShell 获取主连接字符串,请使用 Get-AzCosmosDBAccountKey cmdlet。

    # This gets the primary connection string
    $(Get-AzCosmosDBAccountKey `
        -ResourceGroupName $resourceGroupName `
        -Name $cosmosAccountName `
        -Type "ConnectionStrings")."Primary Table Connection String"
    

    Azure Cosmos DB 帐户的连接字符串被视为应用机密,必须像其他应用机密或密码一样加以保护。

    4 - 安装适用于 Python 的 Azure 数据表 SDK

    创建 Azure Cosmos DB 帐户后,下一步是安装适用于 Python 的 Microsoft Azure 数据表 SDK。 有关安装该 SDK 的详细信息,请参阅 GitHub 上适用于 Python 的数据表 SDK 存储库中的 README.md 文件。

    使用 pip 安装适用于 Python 的 Azure 表客户端库:

    pip install azure-data-tables
    

    不要忘记在 1-starter-app2-completed-app 文件夹中安装 requirements.txt

    5 - 在 .env 文件中配置 Table 客户端

    从 Azure 门户复制你的 Azure Cosmos DB 帐户连接字符串,并使用复制的连接字符串创建 TableServiceClient 对象。 切换到 1-starter-app2-completed-app 文件夹。 无论从哪个应用开始,都需要在 .env 文件中定义环境变量。

    # Configuration Parameters
    conn_str = "A connection string to an Azure Cosmos DB account."
    table_name = "WeatherData"
    project_root_path = "Project abs path"
    

    Azure SDK 使用客户端对象与 Azure 通信,以对 Azure 执行不同的操作。 TableServiceClient 对象用于与 Azure Cosmos DB for Table 通信。 应用程序通常只有一个 TableServiceClient,并且每个表都有一个 TableClient

    例如,以下代码使用环境变量中的连接字符串创建 TableServiceClient 对象。

    self.conn_str = os.getenv("conn_str")
    self.table_service = TableServiceClient.from_connection_string(self.conn_str)
    

    6 - 实现 Azure Cosmos DB 表操作

    示例应用的所有 Azure Cosmos DB 表操作都在 TableServiceHelper 类中实现,该类位于 webapp 目录下的 helper 文件中。 需要在此文件的顶部导入 TableServiceClient 类才能使用 azure.data.tables Python 客户端库中的对象。

    from azure.data.tables import TableServiceClient
    

    TableServiceHelper 类的开头,创建一个构造函数并添加用于 TableClient 对象的成员变量,以允许将 TableClient 对象注入该类。

    def __init__(self, table_name=None, conn_str=None):
        self.table_name = table_name if table_name else os.getenv("table_name")
        self.conn_str = conn_str if conn_str else os.getenv("conn_str")
        self.table_service = TableServiceClient.from_connection_string(self.conn_str)
        self.table_client = self.table_service.get_table_client(self.table_name)
    

    筛选从表返回的行

    若要筛选从表返回的行,可以将 OData 样式筛选器字符串传递到 query_entities 方法。 例如,如果要获取 2021 年 7 月 1 日午夜到 2021 年 7 月 2 日午夜(含)之间的所有芝加哥天气读数,则传入以下筛选器字符串。

    PartitionKey eq 'Chicago' and RowKey ge '2021-07-01 12:00 AM' and RowKey le '2021-07-02 12:00 AM'
    

    你可以在编写筛选器部分的 azure-data-tables 网站中查看相关的 OData 筛选器运算符。

    将 request.args 参数传递到 TableServiceHelper 类中的 query_entity 方法时,它会为每个非 null 属性值创建一个筛选器字符串。 它随后会使用“and”子句将所有值联接在一起,以创建合并筛选器字符串。 此合并筛选器字符串会传递到 TableClient 对象上的 query_entities 方法,仅返回与筛选器字符串匹配的行。 可以在代码中使用类似方法,根据应用程序的要求构造合适的筛选器字符串。

    def query_entity(self, params):
        filters = []
        if params.get("partitionKey"):
            filters.append("PartitionKey eq '{}'".format(params.get("partitionKey")))
        if params.get("rowKeyDateStart") and params.get("rowKeyTimeStart"):
            filters.append("RowKey ge '{} {}'".format(params.get("rowKeyDateStart"), params.get("rowKeyTimeStart")))
        if params.get("rowKeyDateEnd") and params.get("rowKeyTimeEnd"):
            filters.append("RowKey le '{} {}'".format(params.get("rowKeyDateEnd"), params.get("rowKeyTimeEnd")))
        if params.get("minTemperature"):
            filters.append("Temperature ge {}".format(params.get("minTemperature")))
        if params.get("maxTemperature"):
            filters.append("Temperature le {}".format(params.get("maxTemperature")))
        if params.get("minPrecipitation"):
            filters.append("Precipitation ge {}".format(params.get("minPrecipitation")))
        if params.get("maxPrecipitation"):
            filters.append("Precipitation le {}".format(params.get("maxPrecipitation")))
        return list(self.table_client.query_entities(" and ".join(filters)))
    

    使用 TableEntity 对象插入数据

    将数据添加到表的最简单方法是使用 TableEntity 对象。 在此示例中,数据会从输入模型对象映射到 TableEntity 对象。 输入对象中表示气象站名称和观察日期/时间的属性分别映射到 PartitionKeyRowKey 属性,这些属性共同构成表中行的唯一键。 输入模型对象上的额外属性随后会映射到 TableEntity 对象上的字典属性。 最后,TableClient 对象上的 create_entity 方法用于将数据插入表中。

    修改示例应用程序中的 insert_entity 函数,以包含以下代码。

    def insert_entity(self):
        entity = self.deserialize()
        return self.table_client.create_entity(entity)
    @staticmethod
    def deserialize():
        params = {key: request.form.get(key) for key in request.form.keys()}
        params["PartitionKey"] = params.pop("StationName")
        params["RowKey"] = "{} {}".format(params.pop("ObservationDate"), params.pop("ObservationTime"))
        return params
    

    使用 TableEntity 对象更新插入数据

    如果尝试向表中插入的行具有该表中已存在的分区键/行键组合,则会收到错误。 因此,在向表添加行时,通常最好使用 upsert_entity 而不是 create_entity 方法。 如果表中已存在给定分区键/行键组合,则 upsert_entity 方法会更新现有行。 否则,行会添加到表中。

    def upsert_entity(self):
        entity = self.deserialize()
        return self.table_client.upsert_entity(entity)
    @staticmethod
    def deserialize():
        params = {key: request.form.get(key) for key in request.form.keys()}
        params["PartitionKey"] = params.pop("StationName")
        params["RowKey"] = "{} {}".format(params.pop("ObservationDate"), params.pop("ObservationTime"))
        return params
    

    使用变量属性插入或更新插入数据

    使用 Azure Cosmos DB for Table 的一个好处是,如果要加载到表的对象包含任何新属性,那这些属性会自动添加到表中并且值存储在 Azure Cosmos DB 中。 无需如同传统数据库中一样,运行 ALTER TABLE 等 DDL 语句来添加列。

    在处理可能会随着时间推移添加或修改需要捕获的数据的数据源时,或者在不同的输入向应用程序提供不同的数据时,此模型可使应用程序具有灵活性。 在示例应用程序中,我们可以模拟一个不仅发送基本天气数据,而且还发送一些额外值的气象站。 首次将具有这些新属性的对象存储在表中时,对应属性(列)会自动添加到表中。

    若要使用 API for Table 插入或更新插入此类对象,请将可扩充对象的属性映射到 TableEntity 对象,并根据需要对 TableClient 对象使用 upsert_entitycreate_entity 方法。

    在示例应用程序中,upsert_entity 函数还可实现使用变量属性插入或更新插入数据的功能

    def insert_entity(self):
        entity = self.deserialize()
        return self.table_client.create_entity(entity)
    def upsert_entity(self):
        entity = self.deserialize()
        return self.table_client.upsert_entity(entity)
    @staticmethod
    def deserialize():
        params = {key: request.form.get(key) for key in request.form.keys()}
        params["PartitionKey"] = params.pop("StationName")
        params["RowKey"] = "{} {}".format(params.pop("ObservationDate"), params.pop("ObservationTime"))
        return params
    

    可以通过对 TableClient 对象调用 update_entity 方法来更新实体。

    在示例应用中,此对象会传递到 TableClient 类中的 upsert_entity 方法。 它更新该实体对象,并使用 upsert_entity 方法将更新保存到数据库。

    def update_entity(self):
        entity = self.update_deserialize()
        return self.table_client.update_entity(entity)
    @staticmethod
    def update_deserialize():
        params = {key: request.form.get(key) for key in request.form.keys()}
        params["PartitionKey"] = params.pop("StationName")
        params["RowKey"] = params.pop("ObservationDate")
        return params
    

    若要从表中删除实体,请使用对象的分区键和行键对 TableClient 对象调用 delete_entity 方法。

    def delete_entity(self):
        partition_key = request.form.get("StationName")
        row_key = request.form.get("ObservationDate")
        return self.table_client.delete_entity(partition_key, row_key)
    

    7 - 运行代码

    运行示例应用程序以与 Azure Cosmos DB for Table 交互。 例如,从 2-completed-app 文件夹开始,安装了要求项后,可以使用:

    python3 run.py webapp
    

    有关运行示例应用程序的详细信息,请参阅示例存储库根路径中的 README.md 文件。

    首次运行应用程序时没有数据,因为表为空。 使用应用程序顶部的任何按钮将数据添加到表。

    选择“使用表实体插入”按钮会打开一个对话框,使你可以使用 TableEntity 对象插入或更新插入新行。

    选择“使用可扩展数据插入”按钮后,将会打开一个对话框,在其中可以插入具有自定义属性的对象,并演示 Azure Cosmos DB for Table 如何根据需要自动将属性(列)添加到表中。 使用“添加自定义字段”按钮添加一个或多个新属性并演示此功能。

    使用“插入示例数据”按钮将一些示例数据加载到 Azure Cosmos DB 表中。

  • 对于 1-starter-app 示例文件夹,至少需要完成 submit_transaction 函数的代码,才能使示例数据插入正常工作。

  • 示例数据从 sample_data.json 文件加载。 .env 变量 project_root_path 告知应用在何处查找此文件。 例如,如果从 1-starter-app2-completed-app 文件夹运行应用程序,请将 project_root_path 设置为“”(空白)。

    若要使用 Azure CLI 删除资源组,请结合要删除的资源组的名称使用 az group delete 命令。 删除某个资源组后,还会删除该资源组中包含的所有 Azure 资源。

    az group delete --name $RESOURCE_GROUP_NAME
    

    若要使用 Azure PowerShell 删除资源组,请结合要删除的资源组的名称使用 Remove-AzResourceGroup 命令。 删除某个资源组后,还会删除该资源组中包含的所有 Azure 资源。

    Remove-AzResourceGroup -Name $resourceGroupName
    

    在本快速入门教程中,已了解如何创建 Azure Cosmos DB 帐户、使用数据资源管理器创建表和运行应用。 现在可以使用 API for Table 进行数据查询了。

    使用 API for Table 查询 Azure Cosmos DB

  •