На этом шаге мы рассмотрим особенности обработки результатов запроса.
Для обработки результата запроса применяются следующие методы объекта-курсора:
>>> import pyodbc >>> s = "DRIVER={MySQL ODBC 5.3 Unicode Driver};SERVER=localhost;" >>> s += "UID=root;DATABASE=python;CHARSET=utf8" >>> con = pyodbc.connect(s, autocommit=True, unicode_results=True) >>> cur = con.cursor() >>> cur.execute("SELECT * FROM `rubr`") <pyodbc.Cursor object at 0x02445560> >>> row = cur.fetchone() >>> row.id_rubr # Доступ по названию поля 1 >>> print(row.name_rubr) # Доступ по названию поля Программирование >>> print(row[1]) # Доступ по индексу поля Программирование >>> cur.fetchone() (2, 'Поисковые \' " порталы') >>> print(cur.fetchone()) None
Как видно из примера, объект Row, возвращаемый методом fetchone(), позволяет получить значение как по индексу, так и по названию поля, которое представляет собой атрибут этого объекта и поэтому указывается через точку. Если вывести полностью содержимое объекта, то возвращается кортеж со значениями. Так как при подключении в параметре unicode_results мы указали значение True, все строковые значения возвращаются в виде Unicode-строк;
Количество элементов, выбираемых за один раз, задается с помощью необязательного параметра - если он не указан, используется значение атрибута arraysize объекта-курсора. Если количество записей в результате запроса меньше указанного количества элементов, то количество элементов списка будет соответствовать оставшемуся количеству записей. Если записей больше нет, метод возвращает пустой список. Пример:
>>> cur.execute ("SELECT * FROM `rubr`") <pyodbc.Cursor object at 0x02445560> >>> cur.arraysize 1 >>> row = cur.fetchmany()[0] >>> print(row.name_rubr) Программирование >>> cur.fetchmany(2) [(2, 'Поисковые \' " порталы')] >>> cur.fetchmany() []
>>> cur.execute ("SELECT * FROM `rubr`") <pyodbc.Cursor object at 0x02445560> >>> rows = cur.fetchall() >>> rows [(1, 'Программирование'), (2, 'Поисковые \' " порталы')] >>> print (rows[0].name_rubr) Программирование >>> cur.fetchall() []
Объект-курсор поддерживает итерационный протокол, поэтому можно перебрать записи с помощью цикла for, указав объект-курсор в качестве параметра:
>>> cur.execute ("SELECT * FROM `rubr`") <pyodbc.Cursor object at 0x02445560> >>> for row in cur: print (row.name_rubr) Программирование Поисковые ' " порталы
Объект-курсор поддерживает несколько атрибутов:
>>> cur.execute ("""UPDATE `rubr` SET `name_rubr`='Поисковые порталы' WHERE `id_rubr`=2""") <pyodbc.Cursor object at 0x02445560> >>> cur.rowcount 1 >>> cur.execute("SELECT * FROM `rubr` WHERE `id_rubr`=2") <pyodbc.Cursor object at 0x02445560> >>> print(cur.fetchone().name_rubr) Поисковые порталы
>>> cur.execute ("SELECT * FROM `rubr`") <pyodbc.Cursor object at 0x02445560> >>> cur.description (('id_rubr', <class 'int'>, None, 10, 10, 0, True), ('name_rubr', <>class 'str'>, None, 255, 255, 0, True))
Мы уже не раз говорили, что передавать значения, введенные пользователем, необходимо через второй параметр метода execute(). Если данные не обработать и подставить в SQL-запрос, то пользователь получит возможность видоизменить запрос и, например, зайти в закрытый раздел без ввода пароля. В качестве примера составим SQL-запрос с помощью форматирования и зайдем под учетной записью пользователя без ввода пароля:
>>> user = "unicross@mail.ru'/*" >>> passw ="*/ '" >>> sql = """SELECT * FROM `user` WHERE `email`='%s' AND `passw`='%s'""" % (user, passw) >>> cur.execute(sql) <pyodbc.Cursor object at 0x02445560> >>> cur.fetchone() (1, 'unicross@mail.ru', 'passwordl')
Как видно из результата, мы получили доступ, не зная пароля. После форматирования SQL-запрос будет выглядеть следующим образом:
SELECT * FROM `user` WHERE `email`='unicross@mail.ru'/*' AND `passw`=*/ ''
Все, что расположено между /* и */, является комментарием. В итоге SQL-запрос будет выглядеть так:
SELECT * FROM `user` WHERE `email`='unicross@mail.ru' ''
Никакая проверка пароля в этом случае вообще не производится. Достаточно знать логин пользователя - и можно войти без пароля. Если данные передавать через второй параметр метода execute(), то все специальные символы будут экранированы, и пользователь не сможет видоизменить SQL-запрос:
>>> user = "unicross@mail.ru'/*" >>> passw ="*/ '" >>> sql = "SELECT * FROM `user` WHERE `email`=? AND `passw`=?" >>> cur.execute(sql, (user, passw)) <pyodbc.Cursor object at 0x02445560> >>> print (cur.fetchone()) None
После подстановки значений SQL-запрос будет выглядеть следующим образом:
SELECT * FROM `user` WHERE `email`='unicross@mail.ru\'/*' AND `passw`='*/ \''
В результате все опасные символы оказались экранированы.
Со следующего шага мы начнем знакомиться с библиотекой Pillow.