Использование SQLite 3 с Flask
В Flask вы можете легко реализовать открытие подключений к базе данных по требованию и закрытие их при уничтожении контекста (обычно в конце запроса).
Вот простой пример того, как можно использовать SQLite 3 с Flask:
import sqlite3
from flask import g
DATABASE = '/path/to/database.db'
def get_db():
db = getattr(g, '_database', None)
if db is None:
db = g._database = sqlite3.connect(DATABASE)
return db
@app.teardown_appcontext
def close_connection(exception):
db = getattr(g, '_database', None)
if db is not None:
db.close()
Теперь, для использования базы данных, приложению необходимо иметь активный контекст приложения (что всегда верно, если в работе есть запрос) или создать контекст приложения самостоятельно. В этот момент можно использовать функцию get_db для получения текущего подключения к базе данных. При уничтожении контекста подключение к базе данных будет разорвано.
Примечание: если вы используете Flask 0.9 или более старую версию, вам нужно использовать flask._app_ctx_stack.top вместо g, так как объект flask.g был привязан к запросу, а не к контексту приложения.
Пример:
@app.route('/')
def index():
cur = get_db().cursor()
...
Примечание
Пожалуйста, имейте в виду, что функции обработки завершения запроса и контекста приложения всегда выполняются, даже если обработчик перед запросом завершился неудачно или никогда не выполнялся. Из-за этого нам нужно убедиться, что база данных существует перед её закрытием.
Подключение по требованию
Преимущество этого подхода (подключение при первом использовании) заключается в том, что подключение будет открыто только если это действительно необходимо. Если вы хотите использовать этот код вне контекста запроса, вы можете использовать его в оболочке Python, открыв контекст приложения вручную:
with app.app_context():
# now you can use get_db()
Легкий доступ к запросам
Теперь в каждой функции обработки запроса вы можете получить доступ к get_db() для получения текущего открытого подключения к базе данных. Для упрощения работы с SQLite полезна функция фабрики строк. Она выполняется для каждого результата, возвращаемого из базы данных, чтобы преобразовать результат. Например, для получения словарей вместо кортежей это можно вставить в функцию get_db которую мы создали выше:
def make_dicts(cursor, row):
return dict((cursor.description[idx][0], value)
for idx, value in enumerate(row))
db.row_factory = make_dicts
Это заставит модуль sqlite3 возвращать словари для этого подключения к базе данных, с которыми гораздо приятнее работать. Ещё проще, мы можем поместить это в get_db вместо этого:
db.row_factory = sqlite3.Row
Это будет использовать объекты Row вместо словарей для возврата результатов запросов. Это объекты namedtuple, поэтому мы можем получить доступ к ним по индексу или по ключу. Например, предположим, что у нас есть объект sqlite3.Row под названием r для строк id, FirstName, LastName и MiddleInitial.
>>> # You can get values based on the row's name >>> r['FirstName'] John >>> # Or, you can get them based on index >>> r[1] John # Row objects are also iterable: >>> for value in r: ... print(value) 1 John Doe M
Кроме того, рекомендуется предоставить функцию запроса, которая комбинирует получение курсора, выполнение и извлечение результатов:
def query_db(query, args=(), one=False):
cur = get_db().execute(query, args)
rv = cur.fetchall()
cur.close()
return (rv[0] if rv else None) if one else rv
Эта полезная функция в сочетании с фабрикой строк делает работу с базой данных намного приятнее, чем просто использование объектов курсора и подключения.
Вот как вы можете её использовать:
for user in query_db('select * from users'):
print user['username'], 'has the id', user['user_id']
Или если вам нужен только один результат:
user = query_db('select * from users where username = ?',
[the_username], one=True)
if user is None:
print 'No such user'
else:
print the_username, 'has the id', user['user_id']
Для передачи переменных частей в оператор SQL используйте знак вопроса в операторе и передайте аргументы в качестве списка. Никогда не добавляйте их непосредственно в оператор SQL с форматированием строк, так как это позволяет атаковать приложение с помощью SQL-инъекций.
Начальные схемы
Реляционные базы данных нуждаются в схемах, поэтому приложения часто поставляют файл schema.sql, который создаёт базу данных. Хорошо предоставить функцию, которая создаёт базу данных на основе этой схемы. Эта функция может сделать это за вас:
def init_db():
with app.app_context():
db = get_db()
with app.open_resource('schema.sql', mode='r') as f:
db.cursor().executescript(f.read())
db.commit()
Вы затем можете создать такую базу данных из оболочки Python:
>>> from yourapplication import init_db >>> init_db()
© 2007–2021 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/2.0.x/patterns/sqlite3/