使用SQLObject
Monday, June 2nd, 2008使用SQLObject
译者: | gashero |
---|
- 1 导入模块
- 2 定义MySQL使用的URI连接
- 3 连接
- 4 定义一个表格类
- 5 创建表格
- 6 自动索引
- 7 创建一个对象
- 8 空值
- 9 查询
- 10 开启调试显示
- 11 set方法
- 12 懒惰的更新
- 13 一对多联系
- 14 多对多联系
- 15 选择多个对象(查询)
- 16 selectBy方法
- 17 sqlmeta类
- 18 使用sqlmeta
- 19 SQLObject
- 20 自定义对象
- 21 参考手册(Reference)
- 22 Col类,定义列
- 23 列类型
- 24 两个类/表之间的关系
- 25 多连接和SQL多连接:一对多
1 导入模块
from sqlobject import *
2 定义MySQL使用的URI连接
mysqluri="mysql://user:password@host:port/database"
端口号为3306,一定要指定的。否则按照旧式连接方法里面,端口port属性设为None,就会抛出TypeError异常,因为要求必须是一个整数类型的端口号。如果按照新式的URI方式连接,如果不指定端口号则port默认为0,也会出现连接失败的问题。
sqlite的连接:
sqlite:///full/path/to/database sqlite:/C|full/path/to/database sqlite:/:memory:
postgre数据库的连接:
postgres://user@host/database?debug=&cache= postgres://host:5432/database
3 连接
conn=connectionForURI(mysqluri) sqlhub.processConnection=conn
4 定义一个表格类
class Person(SQLObject): firstName=StringCol() middleInitial=StringCol(length=1,default=None) lastName=StringCol()
如果没有定义sqlhub,则需要使用 Person._connection=conn 来指定连接。
5 创建表格
Person.createTable()
可以指定参数ifNotExists=True,仅仅在表格不存在时才创建这个表格。
6 自动索引
自动给出一个叫做id的索引,所以不需要人为指定。
在MySQL中定义是:
INT PRIMARY KEY AUTO_INCREMENT
需要使用这个字段时,使用.id属性。
7 创建一个对象
就是创建类的实例:
Person(firstName="John",lastName="Doe")
在SQLObject中的NULL/None并不是代表缺省。NULL代表完全不同的事物、正文或者是人。有时NULL也代表缺省(default),有时代表不适用,有时代表未知。如果希望缺省一个值,可以使用NULL或其他。
SQLObject的default不同于数据库的default。SQLObject从不使用数据库的default。
注意,创建一个对象时,构造方法的参数必须要指定列名,也就是映射类的属性名,否则会出现异常。
8 空值
如果在Person的实例中省略了firstName和lastName则会产生错误,因为没有赋予缺省值。如果是赋予了缺省值的如middleInitial字段,则会被设为NULL值,等同于数据库的None。
9 查询
可以使用类的.get(n)方法得到已经存在的实例。
当创建一个对象时,SQLObject会自动将其存入数据库,而不像其他系统那样,需要手动提交修改。另外,对已有对象的属性修改也会直接存入数据库。
列可以按照属性来存取。注意,对象是独一无二的(unique),如果两次获取同一ID的记录,则获得的是同一对象。这种机制可以确保多个线程存取 同一对象时的一致性。当然,多个线程之间可以不共享对象实例。但是在使用事务(transaction)时,因为事务的隔离性而不成立。
10 开启调试显示
同步显示SQL语句和调试状态。建立连接时使用debug选项:
mysql://user:passwd@host:port/database?debug=t
或:
Person._connection.debug=True
还可以选用的其他选项包括debugOutput(缺省为False),cache(True),autoCommit(True),debugThreading(False)。
在可以看到SQL语句的情况下可以清除的理解工作过程。只需在连接URI中加入”?debug=t”即可。或者设置debug属性。这样,所有的SQL语句都会打印到控制台。这是可靠的,也推荐使用。
11 set方法
用于微弱的提高性能,一次指定多个属性,如:
>>> p.set(firstName="Robert",lastName="Hope Jr.")
12 懒惰的更新
缺省时,每修改一个属性就会导致一个UPDATE的发生,或者每次调用 .set() 时。如果想要避免(avoid)这种仿佛的更新,加入 _lazyUpdate=True 到类定义。这样只有在每次调用 inst.syncUpdate() 或者 obj.sync() 时才写入更新, .sync() 也同时会取出数据库中的最新数据,而 .syncUpdate() 并不这样做。
如果一个实例含有”.sqlmeta.dirty”属性,就是用来指示含有未提交数据的属性。则插入动作会立即提交,这时是没有办法延迟提交的。
13 一对多联系
就是需要建立外键。例如一个地址本类,需要建立外键对应到Person类。
class Address(SQLObject): street=StringCol() city=StringCol() state=StringCol(length=2) zip=StringCol(length=9) person=ForeignKey('Person') Address.createTable()
这样通过ForeignKey()方法建立对Person类的外键。实际上是引用了Person对象。实际是按照类的名字(字符串)来引用一个类。数据库中对应person_id列,对应指向person列。
注意:SQLObject使用字符串来引用一个类是因为很多时候也许一个类还不存在。class关键字作为一个命令,在导入一个模块时才执行,并绑定类的名字和类。所以为了确保类之间的引用正确,在所有的类都装载完成之后才建立类之间的联系。
在需要一个人Person对应多个地址时,可用如下连接:
class Person(SQLObject): ... addresses=MultipleJoin('Address')
在我们已经拥有了Person类的情况下,可以用如下方式修改:
Person.sqlmeta.addJoin(MultipleJoin('Address',joinMethodName='addresses'))
大多数时候可以在创建SQLObject类之后再修改他们。在类定义中使用*Col对象属性等同于使用类方法addColumn()。
然后我们就可以使用自动联系aPerson.addresses,这将会返回一个列表。例如:
>>> p.addresses [] >>> Address(street='123 W Main St',city='Smallsville', ... state="MN",zip='55407',person=p) <Address 1 ...> >>> p.addresses [<Address 1 ...>]
多连接(Multiple Join)类似于关系连接(Related Join),返回结果的列表。你可能更喜欢得到SelectResults对象,可以使用SQLMultipleJoin和SQLRelatedJoin。
14 多对多联系
这个例子中包含用户(user)和角色(role)两个对象,其间包含多对多联系,将使用RelatedJoin来实现。
class User(SQLObject): class sqlmeta: #user是一些数据库的保留字,所以用了别名 table="user_table" username=StringCol(alternateID=True,length=20) #暂时先定义这个,其他还可以有很多字段 role=RelatedJoin("Role") class Role(SQLObject): name=StringCol(alternateID=True,length=20) users=RelatedJoin('User") User.createTable() Role.createTable()
注意:使用sqlmeta类。这个类用于存储多种元信息(metadata)。这是SQLObject 0.7中新引入的特性。查看Class sqlmeta节了解详细。
使用:
bob=User(username="bob") tim=User(username="tim") admin=Role(name='admin') editor=Role(name='editor') bob.addRole(admin) bob.addRole(editor) tim.addRole(editor) >>> bob.roles [<Role 1 name="admin">, <Role 2 name='editor'>] >>> tim.roles [<Role 2 name='editor'>] >>> admin.users [<User 1 username='bob'>] >>> editor.users [<User 1 username='bob'>, <User 2 username='tim'>]
这会自动生成一个中间表role_user。用来同时引用其他类。这个表不会成为一个暴露(expose)的类,这个表的行也不会等同于Python对象。这种多对多的关系完全被隐藏了。
如果想要自己创建中间表,用来增加一些字段,可以查看标准的SQLObject的add/remove方法来工作。假设你可以提供连接列和其他类的 正确连接,也无法通过这些方法插入扩展信息,而且也无法设置默认值。(Assuming that you are providing the join with the correct joinColumn and otherColumn arguments, be aware it’s not possible to insert extra data via such methods, nor will they set any default value.)。
如前述的User/Role系统,如果创建了UserRole中间表,通过创建两个外键来建立MTM(多对多Many-to-Many)联系,并且 附加了DateTimeCol类型的字段(缺省为当前时间)。那么这个列在使用addRole()方法加入role之前会保持为空。
你可能会注意到列加入了扩展保留字alternateID。可以使用alternateID=True来确保该字段的值唯一(uniquely)。 有如确保用户名必须唯一一样。这个标识符会成为主键,且可以访问的。对于这种字段,如果添加了相同值,则会抛出异常 pysqlite2.dbapi2.IntegrityError: column [列名] is not unique。
注意:SQLObject必须确保主键是唯一且不可改变的。可以通过SQLObject来改变主键,但是你要自己提供确保数据一致性的机制。正是因为这个原因,才推荐使用无意义的整数ID,这样可以确保在未来改变时比较安全。
一个alternateID类创建一个类方法,形如byUsername来对应一个叫做username的列(也可以使用alternateMethodName关键字参数来重载)。如下使用:
>>> User.byUsername('bob') <User 1 username='bob'> >>> Role.byName('admin') <Role 1 name='admin'>
15 选择多个对象(查询)
查询才是真正有用的东西,比显示联系重要的多。select是一个类方法,可以按照如下方式使用:
>>> Person._connection.debug=True >>> peeps=Person.select(Person.q.firstName=="John") >>> list(peeps) 1/Select : 使用的SQL语句 1/COMMIT : auto [<Person 1 firstName='John' ...>]
这个例子放回使用John作为firstName的所有人。一个使用表达式的复杂例子:
>>> peeps=Person.select( ... AND(Address.q.personID==Person.q.id, ... Address.q.zip.startswith('504'))) >>> list(peeps) .............. []
属性q用于给出存取特定对象的结构化查询子句。所有被q所引用的列名将会转换成SQL语句。当然也可以手工生成SQL语句:
>>> peeps=Person.select("""address.id=person.id AND ... address.zip LIKE '504%'""", clauseTable=['address'])
注意必须使用clauseTable(子表)来指定子表。如果使用q属性,SQLObject会自动计算出(figure out)所需要使用的扩展信息类。
你也可以使用MyClass.sqlrepr来手工指定任何SQL语句,而在使用q属性时是自动指定的。
还可以使用orderBy关键字创建select语句中的”ORDER BY”。orderBy获取一个字符串,表示数据库的列名,例如Person.q.firstName。也可以使用”-colname”来反向排序。或者 调用MyClass.select().reversed()。
也可以使用类实例的_defaultOrder属性指定缺省的排序列。如果在这时需要获得未排序的结果,使用orderBy=None。
select的结果是一个生成器(generator),可以用于后续调用。所以SQL仅在列出选择结果时才执行,或者使用list()返回所有结 果时。当列举查询结果时,每次取回一个行。这种方法可以在返回结果很大时避免将所有结果放入内存。也可以使用.reversed()而不必获得所有结果实 体,取而代之的是自动修改了SQL语句来获得需要的结果。
还可以对查询结果分片。这将会修改SQL语句,所以peeps[:10]将会把”LIMIT 10″加入SQL语句中。如果切片无法反映到SQL(如peeps[:-10]),则执行查询之后,对查询结果列表进行操作。当然,这只是会出现在使用负索引时。
大多数情况会得到多个查询结果对象。如果不希望这样,可以加入关键字MyClass.select(…,distinct=True),对应SQL中的SELECT DISTINCT。
你也可以通过count得到查询结果的个数,比如MyClass.select().count()。这将会导致一个COUNT(*)查询。这时并不会从数据库中取得对象,而仅仅是获得结果数量。
在少数特别注重效率的时候,效率实际上是依赖于批处理的使用方法。提高排序和查找效率的好办法是使用索引。且缓存比切片更好。
在这种情况下缓存意味着响应所有的结果。可以使用list(MyClass.select(…))来实现。可以在规定的时间内保存查询结果,来让用户分页查看结果。这样,第一次查询会看上去花费更多的时间,但是后面的页面显示却非常快速。
更多关于查询子表的问题参见”SQLBuilder documentation”。
16 selectBy方法
除了.select之外的另一个选择是.selectBy。按照如下工作:
>>> peeps=Person.selectBy(firstName="John",lastName="Doe")
每个关键字对应一个列,且所有的键值对都是以AND进行逻辑连接。返回结果是SelectResult。所以可以切片,计数,排序等等。
17 sqlmeta类
这是在SQLObject 0.7中引入的,允许使用一种清晰的方式指定数据库的元数据,而不需要使用类的命名空间中的属性来指定。
有一些特别的属性可以用在这个类当中,可以用于改变类的行为。他们包括:
- table 数据库的表名,是从style派生而来的,仅用于没有指定类名时。如果没有指定名字,且没有定义可选的style,则标准方式是指定MixedCase为mixed_case。
- idName 指定数据库表的主键名,如未指定时继承自style。缺省为id。
- idType 设置ID时的强制函数。缺省为int。
- style 一个样式(style)对象,这个对象允许使用其他算法翻译Python属性和类名称与数据库列名和表名之间的对应关系。参考”Changing the Naming Style”了解更多。它是一个IStyle实例的接口。
- lazyUpdate 布尔值,缺省为False。如果为True,那么改变属性时不会自动更新查询。而等待调用inst.syncUpdates()或inst.sync()时才执行更新。
- defaultOrder 查询数据时的缺省排序方式。
- cacheValues 布尔值,缺省为True。如果为True,保存在行中的值一直缓存到inst.expire()被调用。如果设为False,属性值不会被缓存,所以每次 存取一个属性的值都会使用查询来返回结果。如果需要处理多进程并发处理时,也许需要这样。当然也可以使用事务(transactions),这不是默认 的。
- registry SQLObject使用字符串来连接一个类,且这些类必须避开模块名,而又是又会出现在不同的系统中的命名冲突。这个属性提供了类的命名空间。
- fromDatabase 布尔值,缺省为False。如果为True,创建一个类时会自动查询数据库的各个列,如果有缺失的列则自动加上。
- columns 形如{columnName:anSOColInstance}形式的字典。可以通过只读属性获取列的信息。
- columnList columns的列表,用于需要一个有序而牢固的列信息列表时使用。
- columnDefinitions 类似columns的字典,但是包含列的原始定义信息。并非是特定类的,且没有逻辑。
- joins 这个类的所有联系对象。
- indexes 这个类的所有索引。
- createSQL 创建表之后的SQL查询。createSQL可以是单行的SQL命令或者是一些SQL命令组成的列表,或者是按照数据库名(dbNames)和值组成的字典,值可以是单行SQL或者是SQL列表。这经常用于ALTER TABLE命令来修改表定义。
- expired 布尔值。如果为True,那么下次存取对象列属性时,将会执行查询。
在上一版本的SQLObject中这些属性是作为类的属性而直接存在的,属性名前加上一个下划线。现在推荐将代码改成新的样式(style)。这些旧的方法在SQLObject 0.8释出时将不再支持。
注意:当继承SQLObject时,sqlmeta属性不会继承。也无法通过sqlmeta.columns词典访问父类列对象。
18 使用sqlmeta
按照如下代码:
class MyClass(SQLObject): class sqlmeta: lazyUpdate=True cacheValues=False columnA=StringCol() columnB=IntCol() def _set_attr1(self,value): #设置值时需要做的事情 def _get_attr1(self): #取得值时需要作的事情
如上定义将会创建表my_class(表名在更改style属性时会有所不同),包含两个列columnA和columnB。还有第三个可以被存取 的属性MyClass.attr1。sqlmeta改变了MyClass的行为,可以延迟更新,并告知不要使用缓存,所以每次请求信息时都会查询数据库。
19 SQLObject
除了sqlmeta和列规范之外,其他的特定属性可以设置在类中。这些属性可以用除了_connection属性之外都可以在sqlmeta中定义。如果在SQLObject 0.7中使用,可以得到不赞成使用的警告。最好及时修改代码来保持对未来的兼容。
- _connection 使用的连接对象,从DBConnection类实现。也可以在包定义中使用__connection__供使用,但是必须确保在类定义之前定义 __connection__。也可以在实例创建时传递connection对象,有如transaction中描述的那样。如果已经定义了 sqlhub.processConnection,则会忽略这个属性而使用sqlhub。如果只有少数几个类使用相同的连接是有好处的,除了 (besides)使用了多种类型。
- _table 这是旧样式(style)的属性,等同于sqlmeta类中的table属性。
- _joins 同上,对应于sqlmeta的joins属性。
- _cacheValues 同上,对应于sqlmeta的cacheValues属性。
- _idName 同上,对应于sqlmeta的idName属性。
- _style 同上,对应于sqlmeta的style属性。
20 自定义对象
自定义类往往需要一些自定义方法,但是需要注意一些细节。
初始化对象:
有两种方式实例化SQLObject对象,从数据库引出和插入数据库。相同的是都要创建Python对象。这导致了__init__的微笑差异。
一般来说,不需要更改__init__。作为替换的_init方法,可以在引出或插入之后执行。方法定义如同_init(self,id, connection=None,selectResults=None),也许你喜欢使用_init(self,*args,**kw)的形式。注意, 如果重载方法,一定要调用SQLObject._init(self,*args,**kw)。
添加魔术属性:
你可以使用任何已有的技术来定义这种新样式中的方法,包括classmethod(类方法),static(静态方法),和property(属 性),而且还可以使用捷径。比如你有一个方法名以_set_、_get_、_del_、_doc_开始,它将会被用于创建属性。所以,如果对应 Person的ID下包含图像在/var/people/images目录下,可以使用:
class Person(SQLObject): # ... def imageFilename(self): return 'images/person-%s.jpg'%self.id def _get_image(self): if not os.path.exists(self.imageFilename()): return None f=open(self.imageFilename()) v=f.read() f.close() return v def _set_image(self,value): f=open(self.imageFilename(),'w') f.write(value) f.close() def _del_image(self,value): os.unlink(self.imageFilename())
然后,可以像使用普通属性(attribute)一样使用.image属性(property)。对它的修改也会直接反映到文件系统当中。这是保存无意义数据的好方法。
同样也可以传递一个image关键字参数到构造方法或者set方法,形如Person(…,image=imageText)。所有的方法 (_get_、_set_等)都是可选的,你可以使用其中的任何一个而省略其他的。这样如果只定义了_get_attr方法,那么attr属性就是只读 的。
重载列属性:
重载数据库列属性时有些复杂。例如(for instance),想要在改变一个人名字的时候执行特定代码。在大多数系统中你需要自己实现这个功能,然后再调用父类的代码。但是父类(SQLObject)并不知道子类的列。
SQLObject创建了形如_set_lastName的方法定义你的列,当时当你再次想要使用时却发现父类没有相关引用(即不可以写 SQLObject._set_lastName(…),因为SQLObject类并不知道你的类的列)。你需要自己重载_set_lastName 方法。
为了处理这种问题,SQLObjec类创建了两个方法作为getter和setter,例如:_set_lastName和_SO_set_lastName。所以可以截获所有对lastName的更改:
class Person(SQLObject): lastName=StringCol() firstName=StringCol() def _set_lastName(self,value): self.notifyLastNameChange(value) self._SO_set_lastName(value)
或者你可能想要包含电话号码的数字,需要限制长度,可以按照如下格式:
import re class PhoneNumber(SQLObject): phoneNumber=StringCol(length=30) _garbageCharactersRE=re.compile(r'[\-\.\(\) ]') _phoneNumberRE=re.compile(r'^[0-9]+$') def _set_phoneNumber(self,value): value=self._garbageCharactersRE.sub('',value) if not len(value)>=10: raise ValueError( 'Phone numbers must be at least 10 digits long') if not self._phoneNumberRE.match(value): raise ValueError,'Phone numbers can contain only digits' self._SO_set_phoneNumber(value) def _get_phoneNumber(self): value=self._SO_get_phoneNumber() number='(%s) %s-%s'%(value[0:3],value[3:6],value[6:10]) if len(value) > 10: number+=' ext.%s'%value[10:] return number
在修改从属性中获得的数据时必须小心。有些时候,人们希望设置与返回的值相同。这个例子中我们在存入数据库之前去除了一些字符,并在取出的时候重新格式化了。这个方法(反对存取属性)的优点之一是程序员往往希望将这些分开。
当然,还应该注意,这些转换在存入和取出时都会发生,但是在查询的时候却不会发生。所以如果你将值从Pythonic形式转换为SQLish形式 时,你的查询(当使用.select()或者.selectBy()方法)需要使用SQL/Database形式(因为这些命令是按照SQL来在数据库上 运行的)。
取消属性定义(Undefined attributes)
还有一个有用的特性,因为你有时需要返回奇怪的结果。SQLObject在你设置一个未定义的属性时不会跑出异常;这很好解释,并且不会改变数据库。他的工作方式有如其他Python类一样,但是在SQLObject类中却没有。
这在有些时候可能会出问题,如果你已经有了一个’name’属性,而你却写了’a.namme=”Victor”‘,这时不会跑出异常,但是却是错误的。
21 参考手册(Reference)
上面的信息可以让你快速进入工作,下面的信息让你定义更加完整。
22 Col类,定义列
列的列表是Col对象的列表。这些对象本身并没有功能,用于定义列。
- dbName 数据库的列名,如果不指定你指定的Python名称将会从大小写混用的形式转换到小写加下划线的形式。
- default 列的缺省值,在创建一个新行时使用。如果指定了一个可调用对象或函数,将会调用这个函数,并且使用其返回值。所以你可以使用 DateTimeCol.now作为当前时间的缺省值。或者你可以使用sqlbuilder.func.NOW()来设置数据库使用NOW()内部函数。 如果你不指定缺省值,则在调用这个记录的new时会抛出异常。
- alternateID 这是一个布尔型变量,缺省为False。指定列是否作为ID属性,例如用户名,尽管并不一定是主键。如果是这样,会添加一个类方法,例如 byUsername将会返回这个对象,使用laternateMethodName,当你希望使用by*类似的名称时,例如 alternateMethodName=”username”。这个列将会被声明为UNIQUE。
- unique 如果为True,当SQLObject创建一个表格时,将会指定这个列为UNIQUE。
- notNone 如果为True,则这个列不允许使用空值,用于创建表格。
- sqlType 这个列的SQL类型,例如INT、BOOLEAN等。你可以使用下面的类来定义,但是有时候使用sqlType更容易一些。仅在SQLObject创建表格时有效。
23 列类型
ForeignKey类可以替换Col来使用,当列是其他表的外键时。一般使用方法如ForeignKey(‘Role’),在这个列子中创建了一 个到表Role的引用。这基本等同于Col(foreignKey=’Role’,ssqlType=’INT’)。这会创建两个属性,role,会返回 Role的实例;roleID会返回与之关联的role的整数ID。
Col还有一些其他子类,用于SQLObject创建表格时指示列的类型。
-
BLOBCol 二进制数据列,目前只能在MySQL、PostgreSQL、SQLite中使用。
-
BoolCol 创建一个BOOLEAN列在Postgre,或者INT在其他数据库中。而且会将”t”/”f”或者0/1转换到数据库后端。
-
CurrencyCol 等同于DecimalCol(size=10,precision=2)。注意DecimalCol可能不会返回正确的值,这个列可能共享一些行为。注意阅读DecimalCol的注意事项。
-
DateTimeCol 日期时间,一般返回datetime或mxDateTime对象。
-
DateCol 一个日期对象,一般返回datetime或mxDateTime对象。
-
TimeCol 一个日期对象,一般返回datetime或mxDateTime对象。
-
DecimalCol 以10为基础的,正确数据,使用关键字参数size指定存储的数字位数,precision指定小数点位数。警告:偶尔会发生在DecimalCol值, 尽管正确的存入数据库,但是可能返回浮点数而不是decimals。你可以自己测试一下,也可以试着导入Decimal类型,在你的数据库适配器导入 SQLObject之前。
-
EnumCol 枚举类型,包含有限个数的字符串值。给出列表中可能的字符串,依靠enumValues关键字参数。MySQL有内置的本地ENUM类型,但是在其他数据库中也可以工作,只不过效率上并不占优势。
-
FloatCol 浮点数
-
ForeignKey 其他表/类的外键,例如user=ForeignKey(‘User’)
-
IntCol 整数
-
PickleCol 一种扩展的BLOBCol,这个列可以存储/取出任何Python对象;实际上是使用了Python的pickle来对对象串行化的压缩和解压缩的,而最终存取的是字符串。
-
StringCol 一个字符串列。String(character)列。扩展关键字如下:
length:如果给定了则字段类似于VARCHAR(length)。如果未指定则使用TEXT字段类型。
varchar:如果包含了length,则用于区别CHAR和VARCHAR,缺省为True,使用VARCHAR。
-
UnicodeCol StringCol的子类,接受dbEncoding关键字参数,缺省为”UTF-8″。其值在存取数据库的过程中被编码和解码。在使用UnicodeCol进行查询时有些限制:
只有简单的q-magic字段支持,不允许表达式;只支持”==”和”<>”操作符。
如下为示例代码:
MyTable.select(u'value'==MyTable.q.name) MyTable.select(MyTable.q.name<>u'value') MyTable.select(OR(MyTable.q.col1==u'value1',MyTable.q.col2<>u'value2')) MyTable.selectBy(name=u'value') MyTable.selectBy(col1=u'value1',col2=u'value2') MyTable.byCol1(u'value1') #假设col1是一个alternetID字段
如下为错误代码:
MyTable.select((MyTable.q.name+MyTable.q.surname)==u'value')
如下情况,必须先转换编码:
MyTable.select((MyTable.q.name+MyTable.q.surname)==u'value'.encode(dbEncoding))
24 两个类/表之间的关系
必须使用ForeignKey来处理表的外键,后台实际使用连接(join)。
25 多连接和SQL多连接:一对多
查看”One-to-Many关系”查看一对多连接的例子。
多连接(MultipleJoin)返回结果类表,而SQLMultipleJoin返回SelectResults对象。
少数关键字参数允许MultipleJoin构造器:
joinColumn:
列名