LINUX.ORG.RU

[python] Где хранить SQL-запросы?

 


0

1

Делаю для себя одно маленькое приложение. Не использую ORM.
БД - MySQL.
Озадачился таким вопросом - где и как правильно хранить SQL запросы?

сейчас у меня есть класс Query и у него есть атрибуты — К примеру,

class Query:
    get_foo = " \
SELECT * FROM `table` \
INNER JOIN `table2` \
ON `table`.`bar` = `table`.`id` \
WHERE `table`.`foo` = '%s' "

а потом в коде пишу так:

db.cursor.execute(Query.get_foo % foo_value)

Но как-то это очень по-быдлокодовски выглядит. Стыд и позор мне ;)
Помогите тупому барану^W студенту, чтобы не так позорно было...



Последнее исправление: Sosiska (всего исправлений: 1)

во внешних файлах в директории ./sql?

anon1984
()

В пистоне большие фрагменты текста можно вставить в тройные кавычки. А внешие файлы - маздай, не хватало еще на каждый чих по большому дереву проекта бегать.


para_str = «„„this is a long string that is made up of
several lines and non-printable characters such as
TAB ( \t ) and they will show up that way when displayed.
NEWLINEs within the string, whether explicitly given like
this within the brackets [ \n ], or just a NEWLINE within
the variable assignment will also show up.
“„“
print para_str;

Absurd ★★★
()
Ответ на: комментарий от Sosiska

неплохо было бы сделать функцию, которая поэскейпит значения перед тем как засунуть в результирующий запрос.

чем же тебя sqlalchemy не устроила?

anonymous
()
Ответ на: комментарий от mashina

бладж, надо наконец-то дочитать туториал по mysql до конца.

а скажите, хранимые процедуры как-нибудь влияют на производительность БД?

Sosiska
() автор топика
Ответ на: комментарий от Sosiska

А к самому способу хранения запросов(класс Query и его вызов ...execute(Query.query % params) у вас претензий нет?

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

http://stackoverflow.com/questions/775296/python-mysql-with-variables

Absurd ★★★
()
Ответ на: комментарий от anonymous

неплохо было бы сделать функцию

есть такое, но к вопросу не относится.

чем же тебя sqlalchemy не устроила?

с ORM знаком, но хочу сначала сделать проект на чистом SQL, чтобы лучше понимать принципы работы...

Sosiska
() автор топика
Ответ на: комментарий от anonymous

неплохо было бы сделать функцию, которая поэскейпит значения перед тем как засунуть в результирующий запрос.

кстати, да, так делать нельзя

db.cursor.execute(Query.get_foo % foo_value)

есть же специальный интерфейс

db.cursor.execute(Query.get_foo, foo_value)

нужно курить DB API, где написано как всё нужно делать

http://www.python.org/dev/peps/pep-0249/

mashina ★★★★★
()
Ответ на: комментарий от Sosiska

хранимые процедуры как-нибудь влияют на производительность БД?

зависит от БД и случая. Может быть лучше, может хуже, нужно тестировать и смотреть как выходит. Но всяко удобнее сложные запросы выносить в хранимки и из кода просто вызывать их callproc'ом.

mashina ★★★★★
()

а потом в коде пишу так:

В коде ты просто должен вызвать функцию, возвращающую нужные данные. А в ней уже использовать строку, без всяких идиотских Query.

baverman ★★★
()
Ответ на: комментарий от mashina

Но всяко удобнее сложные запросы выносить в хранимки и из кода просто вызывать их callproc'ом.

Удобнее, чем что? Ты сейчас всякой фигни насоветуешь молодому дарованию.

baverman ★★★
()
Ответ на: комментарий от mashina

Но всяко удобнее сложные запросы выносить в хранимки и из кода просто вызывать их callproc'ом.

В том случае если пишешь на говноязыке типа Дельпхи, да хранимки спасают. На пистоне же я думаю проще N запросов подряд дать в пределах одной транзакции.

Absurd ★★★
()
Ответ на: комментарий от baverman

Удобнее, чем что?

чем кидать всё это тупо в код. Да и вопрос не совсем правильный, нужно задваться другим - удобнее чем. Далее нужно смотреть/думать, действительно ли нужны какие-то фичи или сойдёт просто набыдлокодить.

mashina ★★★★★
()
Ответ на: комментарий от baverman

ммм...

Сейчас у меня есть что-то вроде MVC.

Есть, к примеру, класс Foo

class Foo:
    ....
    @staticmethod
    def BuildFromRow(row):
        fields = ['pk','subject','text',...]
        params = dict((k,v) for k,v in zip(fields, row))
        return Foo(**params)
    
    @staticmethod
    def GetByBar(bar):
        ...
        row = db.cursor.execute(Query.get_foo, bar)
        return Foo.BuildFromRow(row)

ну и вызивается это чудо так:

foo = Foo.GetByBar(11)

Это очень плохо меня характеризует?

Sosiska
() автор топика
Ответ на: комментарий от Absurd

На пистоне же я думаю проще

а что такое пистон?

N запросов подряд дать в пределах одной транзакции.

это совсем ортогональный вопрос вопросу о форме хранения самих запросов. Нужно ли делать N запросов в одной транзакции или нет зависит от логики приложения и сделать это можно тупо плейн запросами, через хранимки или ОРМ.. или ещё как то.

mashina ★★★★★
()
Ответ на: комментарий от mashina

это совсем ортогональный вопрос вопросу о форме хранения самих запросов.

Почему-то мне кажется что Python это более высокоуровневый язык чем нечто типа PL/SQL, Transact SQL и вероятно то что приделали к MySQL. Поэтому использование хранимок вероятно замедлит рабочий процесс.

Absurd ★★★
()
Ответ на: комментарий от Absurd

Почему-то мне кажется что Python это более высокоуровневый язык чем нечто типа PL/SQL

SQL/PL это DSL языки. Сравнивать их с питоном в плане высокоуровневости всё равно что озадачиваться вопросом что больше в крокодиле - зелёности или длины.

PL языки бывают разнообразными, есть в т.ч. и pl/python, но не в убогом mysql.

Поэтому использование хранимок вероятно замедлит рабочий процесс.

да, такой вариант вполне возможен, я об этом ниже упомянул. Но это связано с тем, как СУБД анализирует и строит планы выполнения для запросов. Грубо говоря, планы выполнения дла запроса с конкретными параметрами и план для просто точно такого же параметризированного запроса будут различаться, последний может получиться ощутимо менее оптимальным.

mashina ★★★★★
()
Ответ на: комментарий от Sosiska

Думаю, тебе надо сначала ознакомиться с существующими ORM, например джанговским или sqlalchemy (очень-очень нравится как там сделана работа с сессиями и транзакциями). А только потом пробовать делать своё.

Также можешь посмотреть на легкие ORM — SqlObject, peewee и Autumn.

Сейчас опыта никакого не получишь, слишком сложная задача. Итогом будет лишь кривой велосипед.

baverman ★★★
()
Ответ на: комментарий от Absurd

В пистоне большие фрагменты текста можно вставить в тройные кавычки. А внешие файлы - маздай, не хватало еще на каждый чих по большому дереву проекта бегать.

олдскул негодуе

drBatty ★★
()
Ответ на: комментарий от Sosiska

Есть, к примеру, класс Foo

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

Потому что универсальный ORM вроде sqlalchemy даёт определённый оверхэд, просто на современных мощных компах он не так заметен в большинстве случаев. То есть твой подход даже лучше, чем втягивание ORM в проект, но только если ты действительно всё продумал. Потому что иначе твоя штука разрастётся до каких-то огромных размеров.

Ну а свой универсальный ORM написать сложно, особенно новичку. Уж больно много разных факторов надо учесть.

Так что вполне можно оставить как есть. Ну я бы методы GetByFoo превратил в GetByField(cls, field, value), чисто из красоты, а то методов станет много.

И да, имхо classmethod красивее, чем staticmethod, т.к. последний не отличается от просто функции, и выглядит излишеством внутри класса.

anonymous
()
Ответ на: комментарий от anonymous

Спасибо за подробный ответ.
Да, действительно универсальность не требуется. Это всего-лишь мини-форум для потока.

GetByBar -> GetByField хорошая идея - обязательно ее реализую.
//А также пошел читать про classmethod

Sosiska
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.