SQLAlchemy / jsonpatch - 如何使补丁路径不区分大小写?

时间:2017-09-07 23:52:14

标签: python-3.x sqlalchemy flask-sqlalchemy json-patch

我一直试图为jsonpatch==1.16找到一些关于如何使PATCH路径不区分大小写的文档。问题是:

PATCH /users/123
[
    {"op": "add", "path": "/firstname", "value": "Spammer"}
]

似乎要求DB(MySQL / MariaDB)列也完全firstname,而不是FirstnameFirstName。当我将JSON中的路径更改为/FirstName(这是DB列的内容)时,补丁工作正常。但我不确定你是否应该在这种情况下在JSON中使用CamelCase?这看起来有点不合标准。

如何使jsonpatch至少不区分大小写?或者,是否有某种方法可以在中间插入一些映射,例如:

def users_mapping(self, path):
    select = {
        "/firstname": "FirstName",
        "/lastname": "last_name",  # Just an example
    }
    return select.get(path, None)

使用Python 3.5,SQLAlchemy 1.1.13和Flask-SQLAlchemy 2.2

1 个答案:

答案 0 :(得分:0)

嗯,答案是:是的,你可以添加映射。这是我的实现和一些注释:

端点处理程序(例如PATCH /news/123):

def patch(self, news_id):
    """Change an existing News item partially using an instruction-based JSON, 
    as defined by: https://tools.ietf.org/html/rfc6902
    """
    news_item = News.query.get_or_404(news_id)
    self.patch_item(news_item, request.get_json())
    db.session.commit()

    # asdict() comes from dictalchemy method make_class_dictable(news)
    return make_response(jsonify(news_item.asdict()), 200)

它调用的方法:

# news = the db.Model for News, from SQLAlchemy
# patchdata = the JSON from the request, like this:
# [{"op": "add", "path": "/title", "value": "Example"}]
def patch_item(self, news, patchdata, **kwargs):
    # Map the values to DB column names
    mapped_patchdata = []
    for p in patchdata:
        # Replace eg. /title with /Title
        p = self.patch_mapping(p)
        mapped_patchdata.append(p)

    # This follows the normal JsonPatch procedure
    data = news.asdict(exclude_pk=True, **kwargs)
    # The only difference is that I pass the mapped version of the list
    patch = JsonPatch(mapped_patchdata)
    data = patch.apply(data)
    news.fromdict(data)

映射实现:

def patch_mapping(self, patch):
    """This is used to map a patch "path" or "from" to a custom value.
    Useful for when the patch path/from is not the same as the DB column name.

    Eg.
    PATCH /news/123
    [{ "op": "move", "from": "/title", "path": "/author" }]

    If the News column is "Title", having "/title" would fail to patch 
    because the case does not match. So the mapping converts this:
        { "op": "move", "from": "/title", "path": "/author" }
    To this:
        { "op": "move", "from": "/Title", "path": "/Author" }
    """

    # You can define arbitrary column names here.
    # As long as the DB column is identical, the patch will work just fine.
    mapping = {
        "/title": "/Title",
        "/contents": "/Contents",
        "/author": "/Author"
    }

    mutable = deepcopy(patch)
    for prop in patch:
        if prop == "path" or prop == "from":
            mutable[prop] = mapping.get(patch[prop], None)
    return mutable