SQLAlchemy/jsonpatch - как сделать пути исправлений нечувствительными к регистру?

Я пытался найти документацию для jsonpatch==1.16 о том, как сделать пути PATCH нечувствительными к регистру. Проблема в том, что:

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

Кажется, что столбец DB (MySQL / MariaDB) также точно равен firstname, а не, например, Firstname или FirstName. Когда я меняю путь в JSON на /FirstName, то есть столбец БД, патч работает нормально. Но я не уверен, что в этом случае вы должны использовать CamelCase в JSON? Это кажется немного нестандартным.

Как я могу сделать 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


person Juha Untinen    schedule 07.09.2017    source источник


Ответы (1)


Что ж, ответ таков: да, вы можете добавить сопоставление. Вот моя реализация с некоторыми аннотациями:

Обработчик конечной точки (например, 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
person Juha Untinen    schedule 08.09.2017