处理自定义ID字段

当涉及到单个文档端点时,在大多数情况下,除了定义父资源端点之外,您没有任何事情可做。所以假设您配置了 /invoices 端点,这将允许客户端查询基础 invoices 数据库集合。这个 /invoices/<ObjectId> 端点将由框架提供,客户端将使用端点来检索和/或编辑单个文档。默认情况下,当 ID_FIELD 字段属于 ObjectId 类型。

但是,您可能有一些集合,其中唯一标识符不是 ObjectId ,您仍然希望单个文档端点正常工作。别担心,这是可行的,只需要稍加修补。

处理 UUID 领域

在本教程中,我们将考虑一个场景,其中一个数据库集合(发票)使用UUID字段作为唯一标识符。我们希望我们的API公开一个文档端点,比如 /invoices/uuid ,意思是:

/invoices/48c00ee9-4dbe-413f-9fc3-d5f12a91de1c .

我们需要遵循以下步骤:

  1. 创建一个定制的JSonencoder,它能够将UUID序列化为字符串,并将其传递给我们的EVE应用程序。

  2. 添加新的支持 uuid 数据类型,以便正确验证传入的UUID值。

  3. 配置我们的发票端点,以便EVE知道如何正确解析UUID URL。

自定义JSonencoder

EVE默认的JSON序列化程序完全能够序列化像 datetime (序列化为rfc1123字符串,如 Sat, 23 Feb 1985 12:00:00 GMTObjectId 值(也序列化为字符串)。

由于我们正在添加对未知数据类型的支持,因此还需要指示EVE实例如何正确序列化它。这就像对标准进行子类化一样简单。 JSONEncoder 或者,更好的是,Eve自己的 BaseJSONEncoder ,因此我们的自定义序列化程序将保留EVE的所有序列化魔力:

from eve.io.base import BaseJSONEncoder
from uuid import UUID

class UUIDEncoder(BaseJSONEncoder):
    """ JSONEconder subclass used by the json render function.
    This is different from BaseJSONEoncoder since it also addresses
    encoding of UUID
    """

    def default(self, obj):
        if isinstance(obj, UUID):
            return str(obj)
        else:
            # delegate rendering to base class method (the base class
            # will properly render ObjectIds, datetimes, etc.)
            return super(UUIDEncoder, self).default(obj)

UUID 验证

默认情况下,EVE为每个新插入的文档创建一个唯一的标识符,即 ObjectId 类型。这不是我们希望在这个端点发生的事情。在这里,我们希望客户机本身提供唯一的标识符,并且还希望验证它们是UUID类型。为了实现这一点,我们首先需要扩展数据验证层(请参见 数据验证 有关自定义验证的详细信息:

from eve.io.mongo import Validator
from uuid import UUID

class UUIDValidator(Validator):
    """
    Extends the base mongo validator adding support for the uuid data-type
    """
    def _validate_type_uuid(self, value):
        try:
            UUID(value)
            return True
        except ValueError:
            pass

UUID URLs

现在EVE能够呈现和验证UUID值,但它仍然不知道哪些资源将使用这些特性。我们还需要设置 item_url 因此,可以正确解析UUID格式的URL。让我们选择我们的 settings.py 模块化并相应地更新API域:

invoices = {
    # this resource item endpoint (/invoices/<id>) will match a UUID regex.
    'item_url': 'regex("[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}")',
    'schema': {
        # set our _id field of our custom uuid type.
        '_id': {'type': 'uuid'},
    },
}

DOMAIN = {
    'invoices': invoices
}

如果您的所有API资源都将支持UUID作为唯一的文档标识符,那么您可能只需要设置全局 ITEM_URL 为了避免为每个资源端点设置UUID regex。

路过 UUID Eve的果汁

现在所有丢失的部分都在那里了,我们只需要指导Eve如何使用它们。EVE在构建URL映射时需要了解新的数据类型,因此我们需要在开始时传递自定义类,当我们正在实例化应用程序时:

app = Eve(json_encoder=UUIDEncoder, validator=UUIDValidator)

记住,如果使用自定义 ID_FIELD 然后,您不应该依赖mongodb(和eve)来自动生成 ID_FIELD 为你。你应该传递这个值,就像这样:

POST
{"name":"bill", "_id":"48c00ee9-4dbe-413f-9fc3-d5f12a91de1c"}

备注

默认情况下,Eve将PyMongo的 UuidRepresentationstandard 。这允许无缝处理现代的由Python生成的UUID值。您可以通过设置 uuidRepresentation 的价值 MONGO_OPTIONS 如你所愿。有关详细信息,请参阅 PyMongo documentation