Python sqlite3.PARSE_DECLTYPES 常量
上次修改时间:2025 年 4 月 15 日
这份全面的指南探讨了 Python 的 sqlite3.PARSE_DECLTYPES 常量,它可以在从 SQLite 数据库检索数据时实现自动类型转换。我们将涵盖它的用法、优点和实际示例。
基本定义
sqlite3.PARSE_DECLTYPES 常量与 sqlite3.connect 一起使用,以启用基于列声明的类型转换。设置后,SQLite 将尝试将值转换为与列的声明类型匹配的 Python 类型。
主要特征:它与 detect_types 参数一起使用,支持标准的 Python 类型,如 datetime.date,并且需要在表定义中进行正确的列类型声明。
PARSE_DECLTYPES 的基本用法
这是一个简单的示例,演示如何使用 PARSE_DECLTYPES 自动转换日期值类型。
import sqlite3
import datetime
# Connect with PARSE_DECLTYPES enabled
with sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES) as conn:
cursor = conn.cursor()
# Create table with DATE type declaration
cursor.execute('''CREATE TABLE events
(id INTEGER PRIMARY KEY, name TEXT, event_date DATE)''')
# Insert current date
today = datetime.date.today()
cursor.execute("INSERT INTO events (name, event_date) VALUES (?, ?)",
('Meeting', today))
# Retrieve and verify type
cursor.execute("SELECT event_date FROM events")
retrieved_date = cursor.fetchone()[0]
print(f"Type of retrieved date: {type(retrieved_date)}") # datetime.date
print(f"Date matches original: {retrieved_date == today}") # True
此示例展示了 PARSE_DECLTYPES 如何自动将 SQLite DATE 值转换为 Python datetime.date 对象。转换发生在数据检索期间。
请注意正确声明列类型(在本例中为 DATE)的重要性,以便转换正常工作。如果没有类型声明,则不会发生转换。
使用 DATETIME 值
当在表架构中正确声明时,PARSE_DECLTYPES 也可以处理 datetime 值。
import sqlite3
from datetime import datetime
with sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES) as conn:
cursor = conn.cursor()
# Create table with TIMESTAMP type declaration
cursor.execute('''CREATE TABLE logs
(id INTEGER PRIMARY KEY, message TEXT,
created_at TIMESTAMP)''')
# Insert current datetime
now = datetime.now()
cursor.execute("INSERT INTO logs (message, created_at) VALUES (?, ?)",
('System started', now))
# Retrieve and verify datetime
cursor.execute("SELECT created_at FROM logs")
retrieved_dt = cursor.fetchone()[0]
print(f"Type: {type(retrieved_dt)}") # datetime.datetime
print(f"Value: {retrieved_dt}")
print(f"Microseconds preserved: {retrieved_dt.microsecond == now.microsecond}")
此示例演示了将 TIMESTAMP 列自动转换为 Python datetime.datetime 对象。转换保留所有 datetime 组件,包括微秒。
关键要求是在表架构中将列声明为 TIMESTAMP。 诸如 DATETIME 之类的其他声明也适用于此转换。
与 PARSE_COLNAMES 结合使用
PARSE_DECLTYPES 可以与 PARSE_COLNAMES 结合使用,以实现更灵活的类型转换场景。
import sqlite3
from decimal import Decimal
# Register converter for DECIMAL type
sqlite3.register_converter("DECIMAL", lambda x: Decimal(x.decode('utf-8')))
with sqlite3.connect(':memory:',
detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES) as conn:
cursor = conn.cursor()
# Create table with mixed types
cursor.execute('''CREATE TABLE products
(id INTEGER PRIMARY KEY, name TEXT,
price DECIMAL, weight REAL)''')
# Insert data with decimal value
cursor.execute("INSERT INTO products (name, price, weight) VALUES (?, ?, ?)",
('Laptop', '1299.99', 2.5))
# Query with type hints in column names
cursor.execute('''SELECT price AS "price [DECIMAL]",
weight AS "weight [REAL]"
FROM products''')
product = cursor.fetchone()
print(f"Price type: {type(product[0])}") # decimal.Decimal
print(f"Weight type: {type(product[1])}") # float
此示例展示了如何结合使用两种解析模式。 PARSE_DECLTYPES 处理来自列声明的 DECIMAL 类型,而 PARSE_COLNAMES 允许在查询中使用类型提示。
我们还演示了为 DECIMAL 类型注册自定义转换器,该转换器将字符串值转换为 Python Decimal 对象。
处理 NULL 值
PARSE_DECLTYPES 正确处理 NULL 值,无需转换尝试,从而保持 Python 的 None 作为数据库 NULL。
import sqlite3
from datetime import date
with sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES) as conn:
cursor = conn.cursor()
cursor.execute('''CREATE TABLE tasks
(id INTEGER PRIMARY KEY, description TEXT,
due_date DATE, completed DATE)''')
# Insert data with NULL date
cursor.execute('''INSERT INTO tasks (description, due_date, completed)
VALUES (?, ?, ?)''',
('Write report', date(2025, 6, 15), None))
# Retrieve and check NULL handling
cursor.execute("SELECT due_date, completed FROM tasks")
due, completed = cursor.fetchone()
print(f"Due date type: {type(due)}") # datetime.date
print(f"Completed type: {type(completed)}") # NoneType
print(f"Is completed None: {completed is None}") # True
此示例演示了,即使对于使用 DATE 类型声明的列,类型列中的 NULL 值在检索时仍为 Python None。
类型转换仅针对非 NULL 值发生,从而使该行为对于数据库架构中的可空列是安全的。
自定义类型转换
您可以注册自定义转换器,以将 PARSE_DECLTYPES 扩展到您自己的 Python 类型。
import sqlite3
import json
from typing import Dict
# Define custom type and converter
def dict_converter(value: bytes) -> Dict:
return json.loads(value.decode('utf-8'))
# Register the converter
sqlite3.register_converter("JSON", dict_converter)
with sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES) as conn:
cursor = conn.cursor()
# Create table with JSON type
cursor.execute('''CREATE TABLE configs
(id INTEGER PRIMARY KEY, name TEXT, settings JSON)''')
# Insert dictionary as JSON
settings = {'theme': 'dark', 'notifications': True, 'timeout': 30}
cursor.execute("INSERT INTO configs (name, settings) VALUES (?, ?)",
('User Preferences', json.dumps(settings)))
# Retrieve and verify automatic conversion
cursor.execute("SELECT settings FROM configs")
retrieved = cursor.fetchone()[0]
print(f"Type: {type(retrieved)}") # dict
print(f"Theme: {retrieved['theme']}") # dark
print(f"Original == Retrieved: {settings == retrieved}") # True
此示例展示了如何通过注册自定义转换器来处理 SQLite 中的 JSON 数据。 JSON 列类型会自动转换为 Python 字典。
转换器函数接收值作为字节,并且必须返回转换后的 Python 对象。 在这里,我们使用 JSON 序列化进行转换。
使用 Time 值
PARSE_DECLTYPES 也可以将 TIME 列转换为 Python datetime.time 对象。
import sqlite3
from datetime import time
with sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES) as conn:
cursor = conn.cursor()
# Create table with TIME type
cursor.execute('''CREATE TABLE schedule
(id INTEGER PRIMARY KEY, event TEXT,
start_time TIME, end_time TIME)''')
# Insert time values
start = time(9, 30)
end = time(17, 0)
cursor.execute('''INSERT INTO schedule (event, start_time, end_time)
VALUES (?, ?, ?)''',
('Workday', start, end))
# Retrieve and verify times
cursor.execute("SELECT start_time, end_time FROM schedule")
retrieved_start, retrieved_end = cursor.fetchone()
print(f"Start type: {type(retrieved_start)}") # datetime.time
print(f"End type: {type(retrieved_end)}") # datetime.time
print(f"Start matches: {retrieved_start == start}") # True
print(f"End matches: {retrieved_end == end}") # True
此示例演示了将 TIME 列自动转换为 Python datetime.time 对象。 转换保留所有时间组件。
与其他时间类型一样,必须在表架构中将列正确声明为 TIME,以便转换自动工作。
最佳实践
- 始终声明列类型: PARSE_DECLTYPES 依赖于正确的类型声明
- 注册自定义转换器: 扩展功能以满足您的特定需求
- 正确处理 NULL: 使用可空列进行测试
- 与 PARSE_COLNAMES 结合使用: 为了获得最大的灵活性
- 记录类型转换: 使该行为在您的代码库中清晰明了
资料来源
作者
列出所有 Python 教程。