DataSet是一个“适合懒人”的数据库包,可以省去很多ORM框架和写SQL语句的麻烦,直接使用Pythonic的方式操作数据库。
首先引入DataSet包:
import dataset
数据库的连接遵循Python的DBurl规范:dialect://user:password@host/dbname。
# 连接SQLite
db = dataset.connect('sqlite:///mydatabase.db')
# 连接database
db = dataset.connect('mysql://user:password@localhost/mydatabase')
# 连接PostgreSQL
db = dataset.connect('postgresql://scott:tiger@localhost:5432/mydatabase')
从源码上来看,依然使用了sqlalchemy的create_engine方法,
self.engine = create_engine(url, **engine_kwargs)
指定数据库中的表时,可以使用类似于字典的语法,当表不存在时,会默认建表。
# 获得user表的实例
table = db['user']
核心方法是create_table,当表不存在现有数据库时,会调用Table类,在数据库建表,Table类的核心是_sync_table和_sync_columns,根据传入的数据修改表结构和建表。
def create_table(self, table_name, primary_id=None, primary_type=None):
assert not isinstance(primary_type, six.string_types), \
'Text-based primary_type support is dropped, use db.types.'
table_name = normalize_table_name(table_name)
with self.lock:
if table_name not in self._tables:
self._tables[table_name] = Table(self, table_name,
primary_id=primary_id,
primary_type=primary_type,
auto_create=True)
return self._tables.get(table_name)
有了table类,就可以执行增删改查的操作了:
# 插入一条新数据
table.insert(dict(name='John Doe', age=46, country='China'))
# dataset会在插入一条没有的列的数据时,会自动创建没有的列
table.insert(dict(name='Jane Doe', age=37, country='France', gender='female'))
# 更新所有name=John Doe的数据
table.update(dict(name='John Doe', age=47), ['name'])
# 删除name=John Doe的数据,如果没有传入值,则会删除所有表中数据
table.delete(name='John Doe')
# 如果更新的数据key存在会执行update操作,否则插入一条新的列
table.upsert(dict(id=10, title='I am a banana!'), ['id'])
all方法返回所有数据
users = db['user'].all()
并且将Select语句抽象为find方法:
# 查询表中country='China'的数据
chinese_users = table.find(country='China')
# 获得指定的name='John Doe'的一条数据
john = table.find_one(name='John Doe')
# 批量查询id=1, id=3, id=7的数据
winners = table.find(id=[1, 3, 7])
# 执行比较操作符
elderly_users = table.find(age={'>=': 70})
possible_customers = table.find(age={'between': [21, 80]})
# 直接使用sqlalchemy的方法
elderly_users = table.find(table.table.columns.age >= 70)
最后也提供query方法直接使用SQL语句:
result = db.query('SELECT country, COUNT(*) c FROM user GROUP BY country')
for row in result:
print(row['country'], row['c'])
对于数据库,免不了事务操作。DataSet使用上下文管理器,自动管理commit和关闭连接:
with dataset.connect() as tx:
tx['user'].insert(dict(name='John Doe', age=46, country='China'))
其等价于:
db = dataset.connect()
db.begin()
try:
db['user'].insert(dict(name='John Doe', age=46, country='China'))
db.commit()
except:
db.rollback()
源码中则是实现了enter__和__exit方法。
def __enter__(self):
"""Start a transaction."""
self.begin()
return self
def __exit__(self, error_type, error_value, traceback):
"""End a transaction by committing or rolling back."""
if error_type is None:
try:
self.commit()
except Exception:
with safe_reraise():
self.rollback()
else:
self.rollback()
除了对数据进行操作外,DataSet还支持对元数据进行管理,调用tables方法可以返回数据库里所有表的表名,table类的columns方法则可以查看所有列名。
>>> print(db.tables)
[u'user']
>>> print(db['user'].columns)
[u'id', u'country', u'age', u'name', u'gender']