Рубрики
Без рубрики

sqlite3 – встроенная реляционная база данных

Автор оригинала: Doug Hellmann.

Цель:

Реализует встроенную реляционную базу данных с поддержкой SQL.

Модуль sqlite3 реализует интерфейс, совместимый с Python DB-API 2.0 для SQLite. , реляционная база данных внутри процесса. SQLite предназначен для встраивания в приложения вместо использования отдельной серверной программы базы данных, такой как MySQL, PostgreSQL или Oracle. Он быстрый, тщательно протестированный и гибкий, что делает его подходящим для создания прототипов и развертывания в производстве некоторых приложений.

Создание базы данных

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

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

sqlite3_createdb.py

import os
import sqlite3

db_filename  'todo.db'

db_is_new  not os.path.exists(db_filename)

conn  sqlite3.connect(db_filename)

if db_is_new:
    print('Need to create schema')
else:
    print('Database exists, assume schema does, too.')

conn.close()

Двойной запуск сценария показывает, что он создает пустой файл, если он не существует.

$ ls *.db

ls: *.db: No such file or directory

$ python3 sqlite3_createdb.py

Need to create schema

$ ls *.db

todo.db

$ python3 sqlite3_createdb.py

Database exists, assume schema does, too.

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

Таблица проекта

Столбец

Тип

Описание

имя

текст

Название проекта

описание

текст

Подробное описание проекта

срок

Дата

Срок сдачи всего проекта

Таблица задач

Столбец

Тип

Описание

я бы

номер

Уникальный идентификатор задачи

приоритет

целое число

Числовой приоритет, чем ниже, тем важнее

Детали

текст

Полная информация о задаче

положение дел

текст

Статус задачи (одно из «новых», «ожидающих», «выполнено» или «отменено»).

срок

Дата

Срок выполнения этой задачи

Complete_on

Дата

Когда задача была выполнена.

проект

текст

Название проекта для этой задачи.

Определение данных Язык определения данных (DDL) для создания таблиц:

todo_schema.sql.

-- Schema for to-do application examples.

-- Projects are high-level activities made up of tasks
create table project (
    name        text primary key,
    description text,
    deadline    date
);

-- Tasks are steps that can be taken to complete a project
create table task (
    id           integer primary key autoincrement not null,
    priority     integer default 1,
    details      text,
    status       text,
    deadline     date,
    completed_on date,
    project      text not null references project(name)
);

<Код> executycript () Метод Connection может использоваться для запуска инструкций DDL для создания схемы.

sqlite3_create_schema.py

import os
import sqlite3

db_filename  'todo.db'
schema_filename  'todo_schema.sql'

db_is_new  not os.path.exists(db_filename)

with sqlite3.connect(db_filename) as conn:
    if db_is_new:
        print('Creating schema')
        with open(schema_filename, 'rt') as f:
            schema  f.read()
        conn.executescript(schema)

        print('Inserting initial data')

        conn.executescript("""
        insert into project (name, description, deadline)
        values ('pymotw', 'Python Module of the Week',
                '2016-11-01');

        insert into task (details, status, deadline, project)
        values ('write about select', 'done', '2016-04-25',
                'pymotw');

        insert into task (details, status, deadline, project)
        values ('write about random', 'waiting', '2016-08-22',
                'pymotw');

        insert into task (details, status, deadline, project)
        values ('write about sqlite3', 'active', '2017-07-31',
                'pymotw');
        """)
    else:
        print('Database exists, assume schema does, too.')

После создания таблиц несколько INSERT COMPARY CONQUARY создают образец проекта и соответствующие задачи. Программа «Код»> SQLite3 Command Line может использоваться для изучения содержимого базы данных.

$ rm -f todo.db
$ python3 sqlite3_create_schema.py

Creating schema
Inserting initial data

$ sqlite3 todo.db 'select * from task'

1|1|write about select|done|2016-04-25||pymotw
2|1|write about random|waiting|2016-08-22||pymotw
3|1|write about sqlite3|active|2017-07-31||pymotw

Получение данных

Чтобы получить значения, сохраненные в таблице «Код»> «Код»> «Код»> «Таблица», из системы Python, создайте CURSOR из соединения с базой данных. Курсор производит постоянный вид данных и является основным средством взаимодействия с помощью системы транзакционной базы данных, такими как SQLite.

sqlite3_select_tasks.py

import sqlite3

db_filename  'todo.db'

with sqlite3.connect(db_filename) as conn:
    cursor  conn.cursor()

    cursor.execute("""
    select id, priority, details, status, deadline from task
    where project = 'pymotw'
    """)

    for row in cursor.fetchall():
        task_id, priority, details, status, deadline  row
        print('{:2d} [{:d}] {:<25} [{:<8}] ({})'.format(
            task_id, priority, details, status, deadline))

Запрос представляет собой два шагового процесса. Во-первых, запустите запрос с помощью EXECUTE () , чтобы сообщить о базе данных двигателя, какие данные для сбора. Затем используйте <код> Fetchall () для получения результатов. Возвращаемое значение представляет собой последовательность кортежей, содержащих значения для столбцов, включенных в <код> Выберите пункт запроса.

$ python3 sqlite3_select_tasks.py

 1 [1] write about select        [done    ] (2016-04-25)
 2 [1] write about random        [waiting ] (2016-08-22)
 3 [1] write about sqlite3       [active  ] (2017-07-31)

Результаты могут быть получены по одному за раз с <Код> Fetchone () , или в партиях фиксированного размера с <код> fetchmany () .

sqlite3_select_variations.py

import sqlite3

db_filename  'todo.db'

with sqlite3.connect(db_filename) as conn:
    cursor  conn.cursor()

    cursor.execute("""
    select name, description, deadline from project
    where name = 'pymotw'
    """)
    name, description, deadline  cursor.fetchone()

    print('Project details for {} ({})\n  due {}'.format(
        description, name, deadline))

    cursor.execute("""
    select id, priority, details, status, deadline from task
    where project = 'pymotw' order by deadline
    """)

    print('\nNext 5 tasks:')
    for row in cursor.fetchmany(5):
        task_id, priority, details, status, deadline  row
        print('{:2d} [{:d}] {:<25} [{:<8}] ({})'.format(
            task_id, priority, details, status, deadline))

Значение, переданное <код> fetchmany () – это максимальное количество элементов для возврата. Если доступны меньше элементов, возвращаемая последовательность будет меньше максимального значения.

$ python3 sqlite3_select_variations.py

Project details for Python Module of the Week (pymotw)
  due 2016-11-01

Next 5 tasks:
 1 [1] write about select        [done    ] (2016-04-25)
 2 [1] write about random        [waiting ] (2016-08-22)
 3 [1] write about sqlite3       [active  ] (2017-07-31)

Запрос метаданных

Спецификация DB-API 2.0 говорит, что после того, как Execute () был вызван, курсор должен установить свой атрибут <код> для хранения информации о данных Это будет возвращено методами извлечения. Спецификация API говорит, что значение описания является последовательностью кортежей, содержащих имя столбца, типа, размер дисплея, внутренний размер, точность, масштаб и флаг, который говорит, принимаются ли нулевые значения.

sqlite3_cursor_description.py

import sqlite3

db_filename  'todo.db'

with sqlite3.connect(db_filename) as conn:
    cursor  conn.cursor()

    cursor.execute("""
    select * from task where project = 'pymotw'
    """)

    print('Task table has these columns:')
    for colinfo in cursor.description:
        print(colinfo)

Поскольку SQLITE3 не поддерживает ограничения типа или размеров на данных, вставленных в базу данных, заполняется только значение имени столбца.

$ python3 sqlite3_cursor_description.py

Task table has these columns:
('id', None, None, None, None, None, None)
('priority', None, None, None, None, None, None)
('details', None, None, None, None, None, None)
('status', None, None, None, None, None, None)
('deadline', None, None, None, None, None, None)
('completed_on', None, None, None, None, None, None)
('project', None, None, None, None, None, None)

Рядные объекты

По умолчанию значения, возвращаемые методами Fetch как «строки» из базы данных, являются кортежи. Звонящий отвечает за познание порядка столбцов в запросе и извлечения отдельных значений из кортежа. Когда число значений в запросе растет или код, работающий с данными, распространяется в библиотеке, обычно проще работать с объектом и значениями доступа, используя их имена столбцов. Таким образом, число и порядок содержимого кортежа могут сочетаться со временем, поскольку запрос отредактирован, а код в зависимости от результатов запроса менее вероятно сломается.

<Код> Соединение Объекты имеют ROW_FACTORY , что позволяет вызовому коду управлять типом объекта, созданного для представления каждой строки в наборе результатов запроса. SQLITE3 также включает в себя класс ряд , предназначенный для использования в качестве завода строки. Значения столбцов могут быть доступны через ROW экземпляров, используя индекс столбца или имя.

sqlite3_row_factory.py

import sqlite3

db_filename  'todo.db'

with sqlite3.connect(db_filename) as conn:
    # Change the row factory to use Row
    conn.row_factory  sqlite3.Row

    cursor  conn.cursor()

    cursor.execute("""
    select name, description, deadline from project
    where name = 'pymotw'
    """)
    name, description, deadline  cursor.fetchone()

    print('Project details for {} ({})\n  due {}'.format(
        description, name, deadline))

    cursor.execute("""
    select id, priority, status, deadline, details from task
    where project = 'pymotw' order by deadline
    """)

    print('\nNext 5 tasks:')
    for row in cursor.fetchmany(5):
        print('{:2d} [{:d}] {:<25} [{:<8}] ({})'.format(
            row['id'], row['priority'], row['details'],
            row['status'], row['deadline'],
        ))

Эта версия SQLITE3_SELECT_VARIATIONS.PY Пример была переписана с использованием экземпляров ROW вместо кортежей. Строка из таблицы проекта по-прежнему напечатана путем доступа к значениям столбцов через положение, но оператор PRINT для задач использует поиск ключевых слов, поэтому не имеет значения, что порядок столбцов в запросе имеет был изменен.

$ python3 sqlite3_row_factory.py

Project details for Python Module of the Week (pymotw)
  due 2016-11-01

Next 5 tasks:
 1 [1] write about select        [done    ] (2016-04-25)
 2 [1] write about random        [waiting ] (2016-08-22)
 3 [1] write about sqlite3       [active  ] (2017-07-31)

Использование переменных с запросами

Использование запросов, определенных как буквальные строки, встроенные в программу, негибко. Например, когда в базу данных добавляется другой проект, запрос, чтобы показать пять лучших задач, должны быть обновлены для работы с любым проектом. Один из способов добавления большей гибкости – это создать оператор SQL с нужным запросом, объединяя значения в Python. Тем не менее, построение строки запроса таким образом опасна и следует избегать. Неспособность правильно избежать специальных символов в вариабельных частях запроса, может привести к ошибкам SQL разборки или хуже, класс уязвимостей безопасности, известных как атаки SQL-инъекций , которые позволяют злоумышленникам выполнить произвольные операторы SQL в базе данных.

Правильный способ использовать динамические значения с запросами через переменные хоста , переданный в <код> execute () наряду с инструкцией SQL. Значение заполнителя в SQL заменяется значением переменной хоста при выполнении оператора. Использование переменных хоста вместо вставки произвольных значений в SQL перед тем, как ее анализируют, избегает атак для инъекций, поскольку нет вероятности, что ненадежные значения будут влиять на то, как SQL проанализирован. SQLite поддерживает две формы для запросов с заполняющими, позиционными и названием.

Позиционные параметры

Марк вопросительного знака (<код>? ) обозначает позиционный аргумент, передаваемый Execute () как член кортежа.

sqlite3_argument_positional.py

import sqlite3
import sys

db_filename  'todo.db'
project_name  sys.argv[1]

with sqlite3.connect(db_filename) as conn:
    cursor  conn.cursor()

    query  """
    select id, priority, details, status, deadline from task
    where project = ?
    """

    cursor.execute(query, (project_name,))

    for row in cursor.fetchall():
        task_id, priority, details, status, deadline  row
        print('{:2d} [{:d}] {:<25} [{:<8}] ({})'.format(
            task_id, priority, details, status, deadline))

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

$ python3 sqlite3_argument_positional.py pymotw

 1 [1] write about select        [done    ] (2016-04-25)
 2 [1] write about random        [waiting ] (2016-08-22)
 3 [1] write about sqlite3       [active  ] (2017-07-31)

Названные параметры

Используйте названные параметры для более сложных запросов с большим количеством параметров или где некоторые параметры повторяются несколько раз в запросе. Назначенные параметры префиксированы с толстой кишкой (например, <код>: param_name ).

sqlite3_argument_named.py

import sqlite3
import sys

db_filename  'todo.db'
project_name  sys.argv[1]

with sqlite3.connect(db_filename) as conn:
    cursor  conn.cursor()

    query  """
    select id, priority, details, status, deadline from task
    where project = :project_name
    order by deadline, priority
    """

    cursor.execute(query, {'project_name': project_name})

    for row in cursor.fetchall():
        task_id, priority, details, status, deadline  row
        print('{:2d} [{:d}] {:<25} [{:<8}] ({})'.format(
            task_id, priority, details, status, deadline))

Ни позиционные, ни именованные параметры не должны быть указаны или сбежать, поскольку они даны специальное лечение по анализатору запросов.

$ python3 sqlite3_argument_named.py pymotw

 1 [1] write about select        [done    ] (2016-04-25)
 2 [1] write about random        [waiting ] (2016-08-22)
 3 [1] write about sqlite3       [active  ] (2017-07-31)

Параметры запроса могут использоваться с Выбрать , <код> вставить и <код> обновления утверждения. Они могут появиться в любой части запроса, где буквальное значение является законным.

sqlite3_argument_update.py

import sqlite3
import sys

db_filename  'todo.db'
id  int(sys.argv[1])
status  sys.argv[2]

with sqlite3.connect(db_filename) as conn:
    cursor  conn.cursor()
    query  "update task set status = :status where id = :id"
    cursor.execute(query, {'status': status, 'id': id})

Этот оператор UPDATE использует два именованных параметра. Значение ID используется для поиска правильной строки для модификации, и значение Status записано на таблицу.

$ python3 sqlite3_argument_update.py 2 done
$ python3 sqlite3_argument_named.py pymotw

 1 [1] write about select        [done    ] (2016-04-25)
 2 [1] write about random        [done    ] (2016-08-22)
 3 [1] write about sqlite3       [active  ] (2017-07-31)

Обливая загрузка

Чтобы применить такую же инструкцию SQL для большого набора данных, используйте EXECUTEMANY () . Это полезно для загрузки данных, поскольку он избегает зацикливания по входам в Python и позволяет базовой библиотеке применить оптимизацию петли. Этот пример программы считывает список задач из файла Comma-разделенного значения, используя модуль CSV и загружает их в базу данных.

sqlite3_load_csv.py

import csv
import sqlite3
import sys

db_filename  'todo.db'
data_filename  sys.argv[1]

SQL  """
insert into task (details, priority, status, deadline, project)
values (:details, :priority, 'active', :deadline, :project)
"""

with open(data_filename, 'rt') as csv_file:
    csv_reader  csv.DictReader(csv_file)

    with sqlite3.connect(db_filename) as conn:
        cursor  conn.cursor()
        cursor.executemany(SQL, csv_reader)

Образец файла данных <код> tasks.csv содержит:

deadline,project,priority,details
2016-11-30,pymotw,2,"finish reviewing markup"
2016-08-20,pymotw,2,"revise chapter intros"
2016-11-01,pymotw,1,"subtitle"

Запуск программы производит:

$ python3 sqlite3_load_csv.py tasks.csv
$ python3 sqlite3_argument_named.py pymotw

 1 [1] write about select        [done    ] (2016-04-25)
 5 [2] revise chapter intros     [active  ] (2016-08-20)
 2 [1] write about random        [done    ] (2016-08-22)
 6 [1] subtitle                  [active  ] (2016-11-01)
 4 [2] finish reviewing markup   [active  ] (2016-11-30)
 3 [1] write about sqlite3       [active  ] (2017-07-31)

Определение новых типов столбцов

SQLite имеет нативную поддержку для целочисленных, плавающих точек и текстовых столбцов. Данные этих типов автоматически преобразуются SQLite3 от представления Python в значение, которое можно сохранить в базе данных, и снова, по мере необходимости. Целочисленные значения загружаются из базы данных в <Код> INT или Long переменных, в зависимости от размера значения. Текст сохраняется и извлекается как STR , если только <код> Text_Factory для Connection не был изменен.

Хотя SQLite поддерживает несколько типов данных внутри, <код> SQLite3 включает в себя средства для определения пользовательских типов, чтобы позволить приложению Python хранить любые виды данных в столбце. Преобразование для типов, кроме тех, кто поддерживается по умолчанию, включен в соединение с базой данных с использованием DETETT_TYPES . Используйте PARSE_DECLTYPES Если столбец был объявлен, используя нужный тип, когда таблица была определена.

sqlite3_date_types.py

import sqlite3
import sys

db_filename  'todo.db'

sql  "select id, details, deadline from task"


def show_deadline(conn):
    conn.row_factory  sqlite3.Row
    cursor  conn.cursor()
    cursor.execute(sql)
    row  cursor.fetchone()
    for col in ['id', 'details', 'deadline']:
        print('  {:<8}  {!r:<26} {}'.format(
            col, row[col], type(row[col])))
    return


print('Without type detection:')
with sqlite3.connect(db_filename) as conn:
    show_deadline(conn)

print('\nWith type detection:')
with sqlite3.connect(db_filename,
                     detect_typessqlite3.PARSE_DECLTYPES,
                     ) as conn:
    show_deadline(conn)

<Код> SQLite3 предоставляет преобразователи для столбцов Date и Timestamp, используя классы <код> Дата и DateTime из модуля DateTime, чтобы представлять значения в Python. Обе преобразователи, связанные с датами, включаются автоматически при включении обнаружения типа.

$ python3 sqlite3_date_types.py

Without type detection:
  id        1                          
  details   'write about select'       
  deadline  '2016-04-25'               

With type detection:
  id        1                          
  details   'write about select'       
  deadline  datetime.date(2016, 4, 25) 

Две функции должны быть зарегистрированы для определения нового типа. Адаптер принимает объект Python в качестве ввода и возвращает строку байтов, которая может быть сохранена в базе данных. Конвертер принимает строку из базы данных и возвращает объект Python. Используйте REGIGN_ADAPTER () Чтобы определить функцию адаптера и <код> register_Converter () для функции преобразователя.

sqlite3_custom_type.py

import pickle
import sqlite3

db_filename  'todo.db'


def adapter_func(obj):
    """Convert from in-memory to storage representation.
    """
    print('adapter_func({})\n'.format(obj))
    return pickle.dumps(obj)


def converter_func(data):
    """Convert from storage to in-memory representation.
    """
    print('converter_func({!r})\n'.format(data))
    return pickle.loads(data)


class MyObj:

    def __init__(self, arg):
        self.arg  arg

    def __str__(self):
        return 'MyObj({!r})'.format(self.arg)


# Register the functions for manipulating the type.
sqlite3.register_adapter(MyObj, adapter_func)
sqlite3.register_converter("MyObj", converter_func)

# Create some objects to save.  Use a list of tuples so
# the sequence can be passed directly to executemany().
to_save  [
    (MyObj('this is a value to save'),),
    (MyObj(42),),
]

with sqlite3.connect(
        db_filename,
        detect_typessqlite3.PARSE_DECLTYPES) as conn:
    # Create a table with column of type "MyObj"
    conn.execute("""
    create table if not exists obj (
        id    integer primary key autoincrement not null,
        data  MyObj
    )
    """)
    cursor  conn.cursor()

    # Insert the objects into the database
    cursor.executemany("insert into obj (data) values (?)",
                       to_save)

    # Query the database for the objects just saved
    cursor.execute("select id, data from obj")
    for obj_id, obj in cursor.fetchall():
        print('Retrieved', obj_id, obj)
        print('  with type', type(obj))
        print()

Этот пример использует MAYLE для сохранения объекта в строку, которая может быть сохранена в базе данных, полезной методике для хранения произвольных объектов, но один, который не позволяет запросу на основе атрибутов объекта. Real Object-Relational Mapper Mapper , таких как sqlalchemy , что хранилищ значений атрибутов в своих собственных столбцах будут более полезными для большое количество данных.

$ python3 sqlite3_custom_type.py

adapter_func(MyObj('this is a value to save'))

adapter_func(MyObj(42))

converter_func(b'\x80\x03c__main__\nMyObj\nq\x00)\x81q\x01}q\x02X\x0
3\x00\x00\x00argq\x03X\x17\x00\x00\x00this is a value to saveq\x04sb
.')

converter_func(b'\x80\x03c__main__\nMyObj\nq\x00)\x81q\x01}q\x02X\x0
3\x00\x00\x00argq\x03K*sb.')

Retrieved 1 MyObj('this is a value to save')
  with type 

Retrieved 2 MyObj(42)
  with type 

Определение типов для колонн

Существует два источника для получения информации о данных для запроса. Оригинальная таблица декларации может использоваться для идентификации типа реального столбца, как показано ранее. Спецификатор типа также может быть включен в <код> Выберите пункт самого запроса, используя форму <код> как «имя [TYPE]» .

sqlite3_custom_type_column.py

import pickle
import sqlite3

db_filename  'todo.db'


def adapter_func(obj):
    """Convert from in-memory to storage representation.
    """
    print('adapter_func({})\n'.format(obj))
    return pickle.dumps(obj)


def converter_func(data):
    """Convert from storage to in-memory representation.
    """
    print('converter_func({!r})\n'.format(data))
    return pickle.loads(data)


class MyObj:

    def __init__(self, arg):
        self.arg  arg

    def __str__(self):
        return 'MyObj({!r})'.format(self.arg)


# Register the functions for manipulating the type.
sqlite3.register_adapter(MyObj, adapter_func)
sqlite3.register_converter("MyObj", converter_func)

# Create some objects to save.  Use a list of tuples so we
# can pass this sequence directly to executemany().
to_save  [
    (MyObj('this is a value to save'),),
    (MyObj(42),),
]

with sqlite3.connect(
        db_filename,
        detect_typessqlite3.PARSE_COLNAMES) as conn:
    # Create a table with column of type "text"
    conn.execute("""
    create table if not exists obj2 (
        id    integer primary key autoincrement not null,
        data  text
    )
    """)
    cursor  conn.cursor()

    # Insert the objects into the database
    cursor.executemany("insert into obj2 (data) values (?)",
                       to_save)

    # Query the database for the objects just saved,
    # using a type specifier to convert the text
    # to objects.
    cursor.execute(
        'select id, data as "pickle [MyObj]" from obj2',
    )
    for obj_id, obj in cursor.fetchall():
        print('Retrieved', obj_id, obj)
        print('  with type', type(obj))
        print()

Используйте DETETT_TYPES Флаг <Код> PARSE_COLNAMES Когда тип является частью запроса вместо исходной определения таблицы.

$ python3 sqlite3_custom_type_column.py

adapter_func(MyObj('this is a value to save'))

adapter_func(MyObj(42))

converter_func(b'\x80\x03c__main__\nMyObj\nq\x00)\x81q\x01}q\x02X\x0
3\x00\x00\x00argq\x03X\x17\x00\x00\x00this is a value to saveq\x04sb
.')

converter_func(b'\x80\x03c__main__\nMyObj\nq\x00)\x81q\x01}q\x02X\x0
3\x00\x00\x00argq\x03K*sb.')

Retrieved 1 MyObj('this is a value to save')
  with type 

Retrieved 2 MyObj(42)
  with type 

Транзакции

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

Сохранение изменений

Изменения в базе данных, через INSERT или UPDATE Заявления, необходимо сохранить явную вызов <код> Commit () . Это требование дает заявку возможность внести несколько связанных изменений вместе, поэтому они хранятся на атомно вместо постепенно, и избегает ситуации, когда частичные обновления видны различными клиентами, соединяющимися с базой данных одновременно.

Эффект вызова Commit () можно увидеть с помощью программы, которая использует несколько подключений к базе данных. Новый строк вставляется с первым соединением, а затем сделаны две попытки, чтобы прочитать его обратно, используя отдельные соединения.

sqlite3_transaction_commit.py

import sqlite3

db_filename  'todo.db'


def show_projects(conn):
    cursor  conn.cursor()
    cursor.execute('select name, description from project')
    for name, desc in cursor.fetchall():
        print('  ', name)


with sqlite3.connect(db_filename) as conn1:
    print('Before changes:')
    show_projects(conn1)

    # Insert in one cursor
    cursor1  conn1.cursor()
    cursor1.execute("""
    insert into project (name, description, deadline)
    values ('virtualenvwrapper', 'Virtualenv Extensions',
            '2011-01-01')
    """)

    print('\nAfter changes in conn1:')
    show_projects(conn1)

    # Select from another connection, without committing first
    print('\nBefore commit:')
    with sqlite3.connect(db_filename) as conn2:
        show_projects(conn2)

    # Commit then select from another connection
    conn1.commit()
    print('\nAfter commit:')
    with sqlite3.connect(db_filename) as conn3:
        show_projects(conn3)

Когда SHOW_PROJECTS () вызывается перед CONN1 , результаты зависят от того, какое соединение используется. Поскольку изменение было сделано через CONN1 , он видит измененные данные. Тем не менее, CONN2 не делает. После совершения новое соединение <код> CONN3 видит вставленную строку.

$ python3 sqlite3_transaction_commit.py

Before changes:
   pymotw

After changes in conn1:
   pymotw
   virtualenvwrapper

Before commit:
   pymotw

After commit:
   pymotw
   virtualenvwrapper

Отбрасывать изменения

Непоступные изменения также могут быть отброшены полностью с использованием ROLLBACK () . COMBIT () и ROLLBACK () методы обычно вызываются из разных частей того же Try: кроме Block, с ошибками, запускающими откат.

sqlite3_transaction_rollback.py

import sqlite3

db_filename  'todo.db'


def show_projects(conn):
    cursor  conn.cursor()
    cursor.execute('select name, description from project')
    for name, desc in cursor.fetchall():
        print('  ', name)


with sqlite3.connect(db_filename) as conn:

    print('Before changes:')
    show_projects(conn)

    try:

        # Insert
        cursor  conn.cursor()
        cursor.execute("""delete from project
                       where name = 'virtualenvwrapper'
                       """)

        # Show the settings
        print('\nAfter delete:')
        show_projects(conn)

        # Pretend the processing caused an error
        raise RuntimeError('simulated error')

    except Exception as err:
        # Discard the changes
        print('ERROR:', err)
        conn.rollback()

    else:
        # Save the changes
        conn.commit()

    # Show the results
    print('\nAfter rollback:')
    show_projects(conn)

После звонка <код> отката () изменения в базе данных больше не присутствуют.

$ python3 sqlite3_transaction_rollback.py

Before changes:
   pymotw
   virtualenvwrapper

After delete:
   pymotw
ERROR: simulated error

After rollback:
   pymotw
   virtualenvwrapper

Уровни изоляции

<Код> SQLite3 поддерживает три режима блокировки, называемые уровнями изоляции , которые контролируют методику, используемую для предотвращения несовместимых изменений между соединениями. Уровень изоляции устанавливается путем пропускания строки в виде Isolation_level Argage, когда соединение открывается, поэтому разные соединения могут использовать разные значения.

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

sqlite3_isolation_levels.py

import logging
import sqlite3
import sys
import threading
import time

logging.basicConfig(
    levellogging.DEBUG,
    format'%(asctime)s (%(threadName)-10s) %(message)s',
)

db_filename  'todo.db'
isolation_level  sys.argv[1]


def writer():
    with sqlite3.connect(
            db_filename,
            isolation_levelisolation_level) as conn:
        cursor  conn.cursor()
        cursor.execute('update task set priority = priority + 1')
        logging.debug('waiting to synchronize')
        ready.wait()  # synchronize threads
        logging.debug('PAUSING')
        time.sleep(1)
        conn.commit()
        logging.debug('CHANGES COMMITTED')


def reader():
    with sqlite3.connect(
            db_filename,
            isolation_levelisolation_level) as conn:
        cursor  conn.cursor()
        logging.debug('waiting to synchronize')
        ready.wait()  # synchronize threads
        logging.debug('wait over')
        cursor.execute('select * from task')
        logging.debug('SELECT EXECUTED')
        cursor.fetchall()
        logging.debug('results fetched')


if __name__  '__main__':
    ready  threading.Event()

    threads  [
        threading.Thread(name'Reader 1', targetreader),
        threading.Thread(name'Reader 2', targetreader),
        threading.Thread(name'Writer 1', targetwriter),
        threading.Thread(name'Writer 2', targetwriter),
    ]

    [t.start() for t in threads]

    time.sleep(1)
    logging.debug('setting ready')
    ready.set()

    [t.join() for t in threads]

Темы синхронизируются с помощью объекта Code> из модуля Threading. Функция WRISTER () подключается и вносит изменения в базу данных, но не совершает перед событиями. Функция Reader () подключается, затем ждет, чтобы запросить базу данных до тех пор, пока не произойдет событие синхронизации.

Отложенный

Уровень изоляции по умолчанию <код> отложено . Использование Deferred Mode блокирует базу данных, но только после начала изменения. Все предыдущие примеры используют отложенный режим.

$ python3 sqlite3_isolation_levels.py DEFERRED

2016-08-20 17:46:26,972 (Reader 1  ) waiting to synchronize
2016-08-20 17:46:26,972 (Reader 2  ) waiting to synchronize
2016-08-20 17:46:26,973 (Writer 1  ) waiting to synchronize
2016-08-20 17:46:27,977 (MainThread) setting ready
2016-08-20 17:46:27,979 (Reader 1  ) wait over
2016-08-20 17:46:27,979 (Writer 1  ) PAUSING
2016-08-20 17:46:27,979 (Reader 2  ) wait over
2016-08-20 17:46:27,981 (Reader 1  ) SELECT EXECUTED
2016-08-20 17:46:27,982 (Reader 1  ) results fetched
2016-08-20 17:46:27,982 (Reader 2  ) SELECT EXECUTED
2016-08-20 17:46:27,982 (Reader 2  ) results fetched
2016-08-20 17:46:28,985 (Writer 1  ) CHANGES COMMITTED
2016-08-20 17:46:29,043 (Writer 2  ) waiting to synchronize
2016-08-20 17:46:29,043 (Writer 2  ) PAUSING
2016-08-20 17:46:30,044 (Writer 2  ) CHANGES COMMITTED

Немедленный

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

$ python3 sqlite3_isolation_levels.py IMMEDIATE

2016-08-20 17:46:30,121 (Reader 1  ) waiting to synchronize
2016-08-20 17:46:30,121 (Reader 2  ) waiting to synchronize
2016-08-20 17:46:30,123 (Writer 1  ) waiting to synchronize
2016-08-20 17:46:31,122 (MainThread) setting ready
2016-08-20 17:46:31,122 (Reader 1  ) wait over
2016-08-20 17:46:31,122 (Reader 2  ) wait over
2016-08-20 17:46:31,122 (Writer 1  ) PAUSING
2016-08-20 17:46:31,124 (Reader 1  ) SELECT EXECUTED
2016-08-20 17:46:31,124 (Reader 2  ) SELECT EXECUTED
2016-08-20 17:46:31,125 (Reader 2  ) results fetched
2016-08-20 17:46:31,125 (Reader 1  ) results fetched
2016-08-20 17:46:32,128 (Writer 1  ) CHANGES COMMITTED
2016-08-20 17:46:32,199 (Writer 2  ) waiting to synchronize
2016-08-20 17:46:32,199 (Writer 2  ) PAUSING
2016-08-20 17:46:33,200 (Writer 2  ) CHANGES COMMITTED

Эксклюзивный

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

$ python3 sqlite3_isolation_levels.py EXCLUSIVE

2016-08-20 17:46:33,320 (Reader 1  ) waiting to synchronize
2016-08-20 17:46:33,320 (Reader 2  ) waiting to synchronize
2016-08-20 17:46:33,324 (Writer 2  ) waiting to synchronize
2016-08-20 17:46:34,323 (MainThread) setting ready
2016-08-20 17:46:34,323 (Reader 1  ) wait over
2016-08-20 17:46:34,323 (Writer 2  ) PAUSING
2016-08-20 17:46:34,323 (Reader 2  ) wait over
2016-08-20 17:46:35,327 (Writer 2  ) CHANGES COMMITTED
2016-08-20 17:46:35,368 (Reader 2  ) SELECT EXECUTED
2016-08-20 17:46:35,368 (Reader 2  ) results fetched
2016-08-20 17:46:35,369 (Reader 1  ) SELECT EXECUTED
2016-08-20 17:46:35,369 (Reader 1  ) results fetched
2016-08-20 17:46:35,385 (Writer 1  ) waiting to synchronize
2016-08-20 17:46:35,385 (Writer 1  ) PAUSING
2016-08-20 17:46:36,386 (Writer 1  ) CHANGES COMMITTED

Поскольку первый писатель начал вносить изменения, читатели и второй писатель блокируют, пока он не совершит. <Код> Sleep () Sleep () Call представляет искусственную задержку в потоке писателя, чтобы подчеркнуть тот факт, что другие соединения блокируются.

Автопроизводство

<Код> isolation_level параметр для соединения также может быть установлен на <код> Нет , чтобы включить режим AutoCommit. С включенным AutoCommit каждый EXECUTE () CALL COUNTROUS приведен немедленно при откровении оператора. Режим AutoCommit подходит для коротких транзакций, таких как те, которые вставляют небольшое количество данных в одну таблицу. База данных заблокирована как можно меньше времени, поэтому существует меньше шансов на утверждение между потоками.

В SQLITE3_AUTOCOMMIT.PY , явный вызов Commit () был удален, и уровень изоляции устанавливается на <код> Нет , но иначе одинаково Как <код> sqlite3_isolation_levels.py . Выходная мощность отличается, однако, поскольку оба писателя темы завершают их работу до того, как любой читатель запускает запрос.

$ python3 sqlite3_autocommit.py

2016-08-20 17:46:36,451 (Reader 1  ) waiting to synchronize
2016-08-20 17:46:36,451 (Reader 2  ) waiting to synchronize
2016-08-20 17:46:36,455 (Writer 1  ) waiting to synchronize
2016-08-20 17:46:36,456 (Writer 2  ) waiting to synchronize
2016-08-20 17:46:37,452 (MainThread) setting ready
2016-08-20 17:46:37,452 (Reader 1  ) wait over
2016-08-20 17:46:37,452 (Writer 2  ) PAUSING
2016-08-20 17:46:37,452 (Reader 2  ) wait over
2016-08-20 17:46:37,453 (Writer 1  ) PAUSING
2016-08-20 17:46:37,453 (Reader 1  ) SELECT EXECUTED
2016-08-20 17:46:37,454 (Reader 2  ) SELECT EXECUTED
2016-08-20 17:46:37,454 (Reader 1  ) results fetched
2016-08-20 17:46:37,454 (Reader 2  ) results fetched

Базы данных в памяти

SQLite поддерживает управление всей базой данных в RAM, а не полагаться на файл диска. Базы данных в памяти полезны для автоматического тестирования, где база данных не нужно сохранять между тестовыми прогонами, или при экспериментировании с схемой или другими функциями базы данных. Чтобы открыть базу данных в памяти, используйте строку <код> ‘: «Память:» вместо имени файла при создании Connection . Каждый <код> ‘: память: « соединение создает отдельный экземпляр базы данных, поэтому изменения, сделанные курсором в одном, не влияют на другие соединения.

Экспорт содержимого базы данных

Содержимое базы данных в памяти может быть сохранена с помощью Iterdump () Метод Connection . Итератор, возвращенный <код> iTerdump () производит серию строк, которые вместе создают инструкции SQL для воссоздания состояния базы данных.

sqlite3_iterdump.py

import sqlite3

schema_filename  'todo_schema.sql'

with sqlite3.connect(':memory:') as conn:
    conn.row_factory  sqlite3.Row

    print('Creating schema')
    with open(schema_filename, 'rt') as f:
        schema  f.read()
    conn.executescript(schema)

    print('Inserting initial data')
    conn.execute("""
    insert into project (name, description, deadline)
    values ('pymotw', 'Python Module of the Week',
            '2010-11-01')
    """)
    data  [
        ('write about select', 'done', '2010-10-03',
         'pymotw'),
        ('write about random', 'waiting', '2010-10-10',
         'pymotw'),
        ('write about sqlite3', 'active', '2010-10-17',
         'pymotw'),
    ]
    conn.executemany("""
    insert into task (details, status, deadline, project)
    values (?, ?, ?, ?)
    """, data)

    print('Dumping:')
    for text in conn.iterdump():
        print(text)

ITERDUMP () также можно использовать с базами данных, сохраненными в файлах, но наиболее полезно для сохранения базы данных, которая не будет сохранена иначе. Этот выход был отредактирован, чтобы соответствовать странице, оставаясь синтаксически правильным.

$ python3 sqlite3_iterdump.py

Creating schema
Inserting initial data
Dumping:
BEGIN TRANSACTION;
CREATE TABLE project (
    name        text primary key,
    description text,
    deadline    date
);
INSERT INTO "project" VALUES('pymotw','Python Module of the
Week','2010-11-01');
DELETE FROM "sqlite_sequence";
INSERT INTO "sqlite_sequence" VALUES('task',3);
CREATE TABLE task (
    id           integer primary key autoincrement not null,
    priority     integer default 1,
    details      text,
    status       text,
    deadline     date,
    completed_on date,
    project      text not null references project(name)
);
INSERT INTO "task" VALUES(1,1,'write about
select','done','2010-10-03',NULL,'pymotw');
INSERT INTO "task" VALUES(2,1,'write about
random','waiting','2010-10-10',NULL,'pymotw');
INSERT INTO "task" VALUES(3,1,'write about
sqlite3','active','2010-10-17',NULL,'pymotw');
COMMIT;

Использование функций Python в SQL

SQL Syntax поддерживает функции вызова во время запросов, либо в списке столбцов, либо <Код> Где Пункт Выберите оператор . Эта функция позволяет обработать данные, прежде чем возвращать ее из запроса, и может использоваться для преобразования между различными форматами, выполняют расчеты, которые будут неуклюжеными в чистом виде SQL, и повторно используют код приложения.

sqlite3_create_function.py

import codecs
import sqlite3

db_filename  'todo.db'


def encrypt(s):
    print('Encrypting {!r}'.format(s))
    return codecs.encode(s, 'rot-13')


def decrypt(s):
    print('Decrypting {!r}'.format(s))
    return codecs.encode(s, 'rot-13')


with sqlite3.connect(db_filename) as conn:

    conn.create_function('encrypt', 1, encrypt)
    conn.create_function('decrypt', 1, decrypt)
    cursor  conn.cursor()

    # Raw values
    print('Original values:')
    query  "select id, details from task"
    cursor.execute(query)
    for row in cursor.fetchall():
        print(row)

    print('\nEncrypting...')
    query  "update task set details = encrypt(details)"
    cursor.execute(query)

    print('\nRaw encrypted values:')
    query  "select id, details from task"
    cursor.execute(query)
    for row in cursor.fetchall():
        print(row)

    print('\nDecrypting in query...')
    query  "select id, decrypt(details) from task"
    cursor.execute(query)
    for row in cursor.fetchall():
        print(row)

    print('\nDecrypting...')
    query  "update task set details = decrypt(details)"
    cursor.execute(query)

Функции выставляются с использованием Create_Function () Метод Connection . Параметры являются названием функции (поскольку его следует использовать изнутри SQL), количество аргументов, которые принимает функцию, и функция Python для выставления.

$ python3 sqlite3_create_function.py

Original values:
(1, 'write about select')
(2, 'write about random')
(3, 'write about sqlite3')
(4, 'finish reviewing markup')
(5, 'revise chapter intros')
(6, 'subtitle')

Encrypting...
Encrypting 'write about select'
Encrypting 'write about random'
Encrypting 'write about sqlite3'
Encrypting 'finish reviewing markup'
Encrypting 'revise chapter intros'
Encrypting 'subtitle'

Raw encrypted values:
(1, 'jevgr nobhg fryrpg')
(2, 'jevgr nobhg enaqbz')
(3, 'jevgr nobhg fdyvgr3')
(4, 'svavfu erivrjvat znexhc')
(5, 'erivfr puncgre vagebf')
(6, 'fhogvgyr')

Decrypting in query...
Decrypting 'jevgr nobhg fryrpg'
Decrypting 'jevgr nobhg enaqbz'
Decrypting 'jevgr nobhg fdyvgr3'
Decrypting 'svavfu erivrjvat znexhc'
Decrypting 'erivfr puncgre vagebf'
Decrypting 'fhogvgyr'
(1, 'write about select')
(2, 'write about random')
(3, 'write about sqlite3')
(4, 'finish reviewing markup')
(5, 'revise chapter intros')
(6, 'subtitle')

Decrypting...
Decrypting 'jevgr nobhg fryrpg'
Decrypting 'jevgr nobhg enaqbz'
Decrypting 'jevgr nobhg fdyvgr3'
Decrypting 'svavfu erivrjvat znexhc'
Decrypting 'erivfr puncgre vagebf'
Decrypting 'fhogvgyr'

Запрос с регулярными выражениями

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

SELECT * FROM table
WHERE column REGEXP '.*pattern.*'

Эти примеры ассоциируют функцию с REGEX () для тестирования значений с использованием модуля Python RE.

sqlite3_regex.py

import re
import sqlite3

db_filename  'todo.db'


def regexp(pattern, input):
    return bool(re.match(pattern, input))


with sqlite3.connect(db_filename) as conn:
    conn.row_factory  sqlite3.Row
    conn.create_function('regexp', 2, regexp)
    cursor  conn.cursor()

    pattern  '.*[wW]rite [aA]bout.*'

    cursor.execute(
        """
        select id, priority, details, status, deadline from task
        where details regexp :pattern
        order by deadline, priority
        """,
        {'pattern': pattern},
    )

    for row in cursor.fetchall():
        task_id, priority, details, status, deadline  row
        print('{:2d} [{:d}] {:<25} [{:<8}] ({})'.format(
            task_id, priority, details, status, deadline))

Выходные данные – это все задачи, где столбец сведений соответствует шаблону.

$ python3 sqlite3_regex.py

 1 [9] write about select        [done    ] (2016-04-25)
 2 [9] write about random        [done    ] (2016-08-22)
 3 [9] write about sqlite3       [active  ] (2017-07-31)

Пользовательские агрегации

Функция агрегации собирает много индивидуальных данных и обобщает его каким-либо образом. Примеры встроенных функций агрегации являются <Код> AVG () (среднее значение), <код> min () , <код> max () , а также <код> ) .

API для агрегаторов, используемых SQLite3 , определяется в терминах класса с двумя методами. Метод STEP () вызывается один раз для каждого значения данных, поскольку запрос обрабатывается. Метод вызывается один раз в конце запроса и должен вернуть совокупное значение. Этот пример реализует агрегатор для арифметического режима . Возвращает значение, которое появляется чаще всего на входе.

sqlite3_create_aggregate.py

import sqlite3
import collections

db_filename  'todo.db'


class Mode:

    def __init__(self):
        self.counter  collections.Counter()

    def step(self, value):
        print('step({!r})'.format(value))
        self.counter[value]  1

    def finalize(self):
        result, count  self.counter.most_common(1)[0]
        print('finalize() -> {!r} ({} times)'.format(
            result, count))
        return result


with sqlite3.connect(db_filename) as conn:
    conn.create_aggregate('mode', 1, Mode)

    cursor  conn.cursor()
    cursor.execute("""
    select mode(deadline) from task where project = 'pymotw'
    """)
    row  cursor.fetchone()
    print('mode(deadline) is:', row[0])

Класс агрегатора зарегистрирован с CREATE_AGGRETY () Метод Connection . Параметры – это имя функции (поскольку его следует использовать изнутри SQL), количество аргументов Step () Method требует метода, а класс для использования.

$ python3 sqlite3_create_aggregate.py

step('2016-04-25')
step('2016-08-22')
step('2017-07-31')
step('2016-11-30')
step('2016-08-20')
step('2016-11-01')
finalize() -> '2016-11-01' (1 times)
mode(deadline) is: 2016-11-01

Резьба и совместное использование подключения

Для исторических причин, связанных со старыми версиями SQLite, Connection объектов, нельзя совместно использовать между потоками. Каждый поток должен создать собственное подключение к базе данных.

sqlite3_threading.py

import sqlite3
import sys
import threading
import time

db_filename  'todo.db'
isolation_level  None  # autocommit mode


def reader(conn):
    print('Starting thread')
    try:
        cursor  conn.cursor()
        cursor.execute('select * from task')
        cursor.fetchall()
        print('results fetched')
    except Exception as err:
        print('ERROR:', err)


if __name__  '__main__':
    with sqlite3.connect(db_filename,
                         isolation_levelisolation_level,
                         ) as conn:
        t  threading.Thread(name'Reader 1',
                             targetreader,
                             args(conn,),
                             )
        t.start()
        t.join()

Попытки поделиться соединением между потоками результата в результате исключения.

$ python3 sqlite3_threading.py

Starting thread
ERROR: SQLite objects created in a thread can only be used in that
same thread.The object was created in thread id 140735234088960
and this is thread id 123145307557888

Ограничение доступа к данным

Хотя SQLite не имеет элементов управления доступа пользователя, найденных в других, более крупных, реляционных базах данных, у него есть механизм ограничения доступа к столбцам. Каждое соединение может установить функцию авторизации , чтобы предоставить или запрещать доступ к столбцам во время выполнения на основе любых желаемых критериев. Функция авторизации вызывается во время анализа операторов SQL и передается пять аргументов. Первый – код действий, указывающий, что выполняется тип работы (чтение, запись, удаление и т. Д.). Остальные аргументы зависят от кода действия. Для SQLITE_READ Операции, аргументы – это имя таблицы, имя столбца, местоположение в SQL, где происходит доступ (основной запрос, триггер и т. Д.), А <код> Нет .

sqlite3_set_authorizer.py

import sqlite3

db_filename  'todo.db'


def authorizer_func(action, table, column, sql_location, ignore):
    print('\nauthorizer_func({}, {}, {}, {}, {})'.format(
        action, table, column, sql_location, ignore))

    response  sqlite3.SQLITE_OK  # be permissive by default

    if action  sqlite3.SQLITE_SELECT:
        print('requesting permission to run a select statement')
        response  sqlite3.SQLITE_OK

    elif action  sqlite3.SQLITE_READ:
        print('requesting access to column {}.{} from {}'.format(
            table, column, sql_location))
        if column  'details':
            print('  ignoring details column')
            response  sqlite3.SQLITE_IGNORE
        elif column  'priority':
            print('  preventing access to priority column')
            response  sqlite3.SQLITE_DENY

    return response


with sqlite3.connect(db_filename) as conn:
    conn.row_factory  sqlite3.Row
    conn.set_authorizer(authorizer_func)

    print('Using SQLITE_IGNORE to mask a column value:')
    cursor  conn.cursor()
    cursor.execute("""
    select id, details from task where project = 'pymotw'
    """)
    for row in cursor.fetchall():
        print(row['id'], row['details'])

    print('\nUsing SQLITE_DENY to deny access to a column:')
    cursor.execute("""
    select id, priority from task where project = 'pymotw'
    """)
    for row in cursor.fetchall():
        print(row['id'], row['details'])

В этом примере используется <код> sqlite_ignore , чтобы заставить строки из task. Он также предотвращает все доступ к Taske.Pority Column, возвращая <код> sqlite_deny , который, в свою очередь, вызывает sqlite для повышения исключения.

$ python3 sqlite3_set_authorizer.py

Using SQLITE_IGNORE to mask a column value:

authorizer_func(21, None, None, None, None)
requesting permission to run a select statement

authorizer_func(20, task, id, main, None)
requesting access to column task.id from main

authorizer_func(20, task, details, main, None)
requesting access to column task.details from main
  ignoring details column

authorizer_func(20, task, project, main, None)
requesting access to column task.project from main
1 None
2 None
3 None
4 None
5 None
6 None

Using SQLITE_DENY to deny access to a column:

authorizer_func(21, None, None, None, None)
requesting permission to run a select statement

authorizer_func(20, task, id, main, None)
requesting access to column task.id from main

authorizer_func(20, task, priority, main, None)
requesting access to column task.priority from main
  preventing access to priority column
Traceback (most recent call last):
  File "sqlite3_set_authorizer.py", line 53, in 
    """)
sqlite3.DatabaseError: access to task.priority is prohibited

Возможные коды действий доступны в качестве постоянных в SQLite3 с префиксом имени <код> SQLite _ . Каждый тип оператора SQL может быть помечен, а доступ к отдельным столбцам также можно контролировать.

Смотрите также

  • Стандартная библиотечная документация для SQLite3
  • pep 249 – Спецификация DB API 2.0 (стандартный интерфейс для модулей, которые обеспечивают Доступ к реляционным базам данных.)
  • sqlite – Официальный сайт библиотеки SQLite.
  • Slow – магазин ключей для сохранения произвольных объектов Python.
  • sqlalchemy – популярный объект-реляционный Mapper, который поддерживает SQLite среди многих других реляционных баз данных.