How to install thing
- Download and install ActivePython
- Open Command Prompt
- Type
pypm install thing
Lastest release
- <pre>
/ /__ ___ /__ / : /:/ / / /::| | /::
/:/:__/:/: /__ __/://__/ /:/ |:| /__/:/__/_:__
/:/ /__/ /__:/:/ / //:/ / /__|:|/:/ / : //__/
/:/ / ::/ / ::/__/ |:/:/ / ::__/__/ /:/ / :__ |::/ / :/:/ /
/:/ / /__/ /:/ / ::/ / /__/ /__/ /__/
</pre>
# Thing 是什么?
Thing是一个基于SQLAlchemy的配置简单、使用简单且灵活的ORM。
# 使用方法
举个简单的例子,假如有3个表:comment, post, user, 3个表的字段分别是:
comment表: ` +---------+------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+------------------+------+-----+---------+----------------+ | id | int(11) unsigned | NO | PRI | NULL | auto_increment | | user_id | int(11) | YES | MUL | NULL | | | post_id | int(11) | YES | MUL | NULL | | | content | text | YES | | NULL | | +---------+------------------+------+-----+---------+----------------+ `
post表: ` +---------+------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+------------------+------+-----+---------+----------------+ | id | int(11) unsigned | NO | PRI | NULL | auto_increment | | user_id | int(11) | YES | MUL | NULL | | | created | int(11) | YES | | NULL | | | content | text | YES | | NULL | | | title | varchar(255) | YES | | NULL | | +---------+------------------+------+-----+---------+----------------+ `
user表: ` +-------+------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+------------------+------+-----+---------+----------------+ | id | int(11) unsigned | NO | PRI | NULL | auto_increment | | name | varchar(30) | YES | | NULL | | +-------+------------------+------+-----+---------+----------------+ `
## 定义Model
先来看看目录结构 ` ├── __init.py__ ├── conn.py # 用于数据库连接 ├── models │ ├── __init__.py │ ├── comment.py │ ├── post.py │ ├── user.py └── test.py ` test.py就是进行测试的地方,先来看看各个model的内容:
### comment.py
``` from thing import thing
- class Comment(thing.Thing):
- _belongs_to = {
- 'post': {
- 'model': 'models.post.Post', 'foreign_key': 'post_id', },
- 'author': {
- 'model': 'models.user.User', 'foreign_key': 'user_id', },
}
### post.py
``` from thing import thing
- class Post(thing.Thing):
- _belongs_to = {
- 'author': {
- 'model': 'models.user.User', 'foreign_key': 'user_id', }
}
- _has_many = {
- 'comments': {
- 'model': 'models.comment.Comment', 'foreign_key': 'user_id', }
}
### user.py
``` from thing import thing
- class User(thing.Thing):
- _has_many = {
- 'posts': {
- 'model': 'models.post.Post', 'foreign_key': 'user_id' },
- 'comments': {
- 'model': 'models.comment.Comment', 'foreign_key': 'user_id' }
}
再来看看conn.py
### conn.py
``` from thing import thing
- config = {
- 'db': {
- 'master': {
- 'url': 'mysql://root:123456@127.0.0.1:3306/test?charset=utf8', 'echo': False, },
- 'slave': {
- 'url': 'mysql://root:123456@127.0.0.1:3306/test?charset=utf8', 'echo': False, },
},
- 'redis': {
- 'host': 'localhost', 'port': 6379, 'db': 1, },
- 'thing': {
- 'debug': True, }
}
thing.Thing.config(config) ```
OK,万事具备,开工!
``` import conn from models.comment import Comment from models.user import User from models.post import Post
# -------- 插入数据 -------- user = User() user.name = 'foo' user.save() # 或者 user = User(name='foo').save()
# -------- 获取数据 -------- user = User().find(1) print user.name
# -------- 获取关联数据 ------- posts = User().find(1).posts.findall() # 如果要设置offset / limit, 在findall里加入参数即可 # posts = User().find(1).posts.findall(offset = 0, limit = 20)
# ------- 删除数据 ------- User().find(1).delete()
# ------- 更新数据 ------- user = User().find(1) user.name = 'bar' user.save() ```
# 动态查询
这个是受Rails影响,觉得很方便就拿来了。比如 `Post().count_by_user_id(3)`,就可以找到user_id为3的用户发表的文章数量。要获取`user_id`为3的用户发表的文章,可以`Post().findall_by_user_id(3, limit=20)`,比起`Post().where('user_id', '=', 3).findall()`更加简洁和明了。
# 关于性能和缓存
Thing内置了Redis作为缓存,你甚至都不需要知道Redis的存在,正常该怎么用还怎么用,Thing会自动处理缓存的生成、读取、过期、删除等操作。
假设表post里有5条数据,在获取每条post后,还想获取该post对应的用户信息,代码如下:
``` posts = Post().findall(limit=5)
- for post in posts:
- print post.author
在开启Debug的情况下,可以在终端看到如下显示:
` DEBUG - [cost:0.0032] - SELECT post.id, post.user_id, post.created, post.content, post.title FROM post ORDER BY post.id DESC LIMIT :param_1 OFFSET :param_2 DEBUG - Cache Read: thing.User:1 {u'id': 1, u'name': u'lzyy'} DEBUG - Cache Read: thing.User:1 {u'id': 1, u'name': u'lzyy'} DEBUG - Cache Read: thing.User:1 {u'id': 1, u'name': u'lzyy'} DEBUG - Cache Read: thing.User:1 {u'id': 1, u'name': u'lzyy'} DEBUG - Cache Read: thing.User:1 {u'id': 1, u'name': u'lzyy'} `
可以看到用户的信息都是从缓存中读取的,所以不用担心n+1的问题。 假如用户的信息被更新,缓存也会自动更新。
# 其他
- 配置信息里的`master`和`slave`为必选项,可以相同。Thing会根据不同的查询,自动找到对应的db。如find/findall会找slave,update/delete会找master。
- 配置信息里的redis项为必选项。
- 动态查询目前支持`find_by`, findall_by, findall_in, count_by
- 内置了8个钩子,会在相应的事件发生时被调用,分别是:`_before_insert`,`_after_insert`,`_before_update`,`_after_update`,`_before_delete`,`_after_delete`,`_before_find`,`_after_find`,可以在子类里覆盖这些方法来实现自己的逻辑。
- 复杂的SQL可以使用`execute`方法,返回的结果是SQLAlchemy的ResultProxy
- 如果要一次更新多处的话,可以使用`updateall`方法,`Post().where('user_id', '=', 1).updateall(user_id=2)`
- 表名如果和小写的类名不一样的话,可以在子类里重新设置`_tablename`
- 每个表一定要有主键,默认为`id`,可以在子类里重新设置`_primary_key`
- 支持has_many和belongs_to,可以在子类里定义`_has_many`和`_belongs_to`
- 没有`join`方法
# ChangeLog
## 0.3.3 * 修复无法从pip安装的bug * 修复安装时对redis-py的依赖 * import thing`变为`from thing import thing
## 0.3.2 * 修复了并发情况下会出现「Exception _mysql_exceptions.ProgrammingError: (2014, "Commands out of sync; you can't run this command now"」错误。 * Redis缓存变为可配置项。如果不想要Redis的话,在config里取消`Redis`配置即可。
## 0.3.1 * 取消了对Validation的支持 * 取消了对Sharding和Partition的支持 * 取消了事件分发机制