Подтвердить что ты не робот

SQL Alchemy ORM возвращает один столбец, как избежать обычной обработки сообщений

Я использую SQL Alchemy ORM, и я нахожу, когда возвращаю один столбец, я получаю такие результаты:

[(result,), (result_2,)] # etc...

С таким набором я считаю, что я должен делать это часто:

results = [r[0] for r in results] # So that I just have a list of result values

Это не то, что "плохо", потому что мои результирующие наборы, как правило, небольшие, но если бы это было не так, это могло бы добавить значительные накладные расходы. Самое главное, что я чувствую, что это загромождает источник, и пропустить этот шаг - довольно распространенная ошибка, с которой я сталкиваюсь.

Есть ли способ избежать этого дополнительного шага?

Относительно в стороне: это поведение орма кажется неудобным в этом случае, но в другом случае, когда мой результирующий набор был, [(id, value)], он заканчивается следующим образом:

[(result_1_id, result_1_val), (result_2_id, result_2_val)]

Тогда я могу просто сделать:

results = dict(results) # so I have a map of id to value

У этого есть преимущество, чтобы сделать смысл полезным шагом после возвращения результатов.

Является ли это действительно проблемой или я просто являюсь nitpick, и пост-обработка после получения набора результатов имеет смысл для обоих случаев? Я уверен, что мы можем думать о некоторых других обычных операциях пост-обработки, чтобы сделать набор результатов более полезным в коде приложения. Есть ли высокая производительность и удобные решения по всем направлениям или неудовлетворительная постпроцессорность и просто требуется для разных применений приложений?

Когда мое приложение действительно может использовать объекты, возвращаемые SQL Alchemy ORM, кажется очень полезным, но в тех случаях, когда я не могу или не могу, не так много. Это просто общая проблема ORM в целом? Мне лучше не использовать слой ORM в таких случаях?

Я предполагаю, что должен показать пример реальных запросов orm, о которых я говорю:

session.query(OrmObj.column_name).all()

или

session.query(OrmObj.id_column_name, OrmObj.value_column_name).all()

Конечно, в реальном запросе обычно есть некоторые фильтры и т.д.

4b9b3361

Ответ 1

Python zip в сочетании с оператором расширения inline - это довольно удобное решение для этого:

>>> results = [('result',), ('result_2',), ('result_3',)]
>>> zip(*results)
[('result', 'result_2', 'result_3')]

Затем вам нужно только один раз указать индекс [0]. Для такого короткого списка ваше понимание выполняется быстрее:

>>> timeit('result = zip(*[("result",), ("result_2",), ("result_3",)])', number=10000)
0.010490894317626953
>>> timeit('result = [ result[0] for result in [("result",), ("result_2",), ("result_3",)] ]', number=10000)
0.0028390884399414062

Однако для более длинных списков zip должен быть быстрее:

>>> timeit('result = zip(*[(1,)]*100)', number=10000)
0.049577951431274414
>>> timeit('result = [ result[0] for result in [(1,)]*100 ]', number=10000)
0.11178708076477051

Итак, это зависит от вас, чтобы определить, что лучше для вашей ситуации.

Ответ 2

Один из способов уменьшить беспорядок в источнике - это повторить так:

results = [r for (r, ) in results]

Хотя это решение на один символ длиннее, чем при использовании оператора [], я думаю, что это проще на глазах.

Чтобы еще меньше помех, удалите скобки. Это усложняет чтение кода, замечая, что вы на самом деле обрабатываете кортежи:

results = [r for r, in results]

Ответ 3

Я тоже боролся с этим, пока не понял его так же, как любой другой запрос:

for result in results:
     print result.column_name

Ответ 4

Я нашел следующее более читаемое, также включает ответ для dict (в Python 2.7):

d = {id_: name for id_, name in session.query(Customer.id, Customer.name).all()}
l = [r.id for r in session.query(Customer).all()]

Для единственного значения заимствования из другого ответа:

l = [name for (name, ) in session.query(Customer.name).all()]

Сравните со встроенным решением zip, адаптированным к списку:

l = list(zip(*session.query(Customer.id).all())[0])

который в мое время обеспечивает только улучшение скорости на 4%.

Ответ 5

Мое решение выглядит так:)

def column(self):
    for column, *_ in Model.query.with_entities(Model.column).all():
        yield column

ПРИМЕЧАНИЕ: только py3.