起步:编写简单的ORM对象
写一个类映射某个数据表,下面是写一个User类,对应数据库中的user表:
|
1
2
3
4
|
class
User(Model): id
= StringField(primary_key=True,ddl='varchar(50)') name
= StringField(ddl='varchar(50)') |
这个表中只有两个字段,id和name,为了简便,这两个字段都为StringField类型。其中StringField类型也为定义的类,对应数据库中的varchar类型。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
class
Field(object): _count
= 0 def
__init__(self,**kw): self.name
= kw.get('name',None) self._default
= kw.get('default',None) self.nullable
= kw.get('nullable',False) self.primary_key
= kw.get('primary_key',False) self._order
= Field._count Field._count
= Field._count
+ 1 print
'xxx' self.ddl
= kw.get('ddl','') @property def
default(self): d
= self._default return
d() if
callable(d) else
d def
__str__(self): s
= ['<%s:%s,%s,default(%s),'
% (self.__class__.__name__,self.name,self.ddl,self._default)] self.nullable
and s.append('N') s.append('>') return
''.join(s)class
StringField(Field): def
__init__(self,**kw): if
not 'default'
in kw: kw['default']
= '' if
not 'ddl'
in kw: kw['ddl']
= 'varchar(250)' super(StringField,self).__init__(**kw) |
其中Field为基类,可以将数据库中的类型扩充完。然后在写一个Model类:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class
Model(dict): __metaclass__
= ModelMetaclass def
__init__(self,**kw): super(Model,self).__init__(**kw) def
__getattr__(self,key): try: return
self[key] except
KeyError: raise
AttributeError(r"'Model' object has no attribute '%s'"
% key) def
__setattr__(self,key,value): self[key]
= value print
'%s: %s' %
self,value |
Model类父类为dict,其中__metaclass__为元类。这个是整个代码的基础。元类创建一个ModelMetaclass类的实例,注意__new__(cls,name,bases,attrs)中的四个参数表示的意思就很好理解了:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
class
ModelMetaclass(type): def
__new__(cls,name,bases,attrs): if
name ==
'Model': return
type.__new__(cls,name,bases,attrs) print
('Found model: %s'
% name) mappings
= dict() primary_key
= None li
= [] for
k,v in
attrs.iteritems(): if
isinstance(v,Field): if
not v.name: v.name
= k if
v.primary_key: if
primary_key: raise
TypeError('Cannot define more than one primary key in class: %s'
% name) if
v.nullable: v.nullable
= False primary_key
= v mappings[k]
= v if
not primary_key: raise
TypeError('Primary key not defined in class: %s'
% name) for
k in
mappings.iterkeys(): attrs.pop(k) attrs['__table__']
= name.lower() attrs['__mappings__']
= mappings attrs['__primary_key__']
= primary_key attrs['__sql__']
= _gen_sql(attrs['__table__'],mappings) print
str(attrs['__sql__']) tables.append(attrs['__sql__']) for
trigger in
_triggers: if
not trigger
in attrs: attrs[trigger]
= None return
type.__new__(cls,name,bases,attrs) |
最后是完整的代码,不过只实现了创建表的功能,这只是万里长征的第一步,慢慢来吧:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
#!/usr/bin/env python# -*- coding: utf-8 -*-# orm.pytables =
[]# Field类class
Field(object): _count
= 0 def
__init__(self,**kw): print
'aaa' self.name
= kw.get('name',None) self._default
= kw.get('default',None) self.nullable
= kw.get('nullable',False) self.primary_key
= kw.get('primary_key',False) self._order
= Field._count Field._count
= Field._count
+ 1 print
'xxx' self.ddl
= kw.get('ddl','') @property def
default(self): d
= self._default return
d() if
callable(d) else
d def
__str__(self): s
= ['<%s:%s,%s,default(%s),'
% (self.__class__.__name__,self.name,self.ddl,self._default)] self.nullable
and s.append('N') s.append('>') return
''.join(s)class
StringField(Field): def
__init__(self,**kw): if
not 'default'
in kw: kw['default']
= '' if
not 'ddl'
in kw: kw['ddl']
= 'varchar(250)' super(StringField,self).__init__(**kw)_triggers
= frozenset(['pre_insert','pre_update','pre_insert'])# 生成sql语句def
_gen_sql(table_name,mappings): pk
= None sql
= ['create table `%s` ('
% table_name] for
f in
sorted(mappings.values(),lambda
x,y:cmp(x._order, y._order)): if
not hasattr(f,'ddl'): raise
StandardError('No ddl in field `%s`'
% n) ddl
= f.ddl nullable
= f.nullable if
f.primary_key: pk
= f.name sql.append(nullable
and ' `%s` %s'
% (f.name,ddl)
or ' `%s` %s not null'
% (f.name,ddl)) if
pk: sql.append(' primary key,') pk
= None sql.append(');') return
'\n'.join(sql) class
ModelMetaclass(type): def
__new__(cls,name,bases,attrs): if
name ==
'Model': return
type.__new__(cls,name,bases,attrs) print
('Found model: %s'
% name) mappings
= dict() primary_key
= None li
= [] for
k,v in
attrs.iteritems(): if
isinstance(v,Field): if
not v.name: v.name
= k if
v.primary_key: if
primary_key: raise
TypeError('Cannot define more than one primary key in class: %s'
% name) if
v.nullable: v.nullable
= False primary_key
= v mappings[k]
= v if
not primary_key: raise
TypeError('Primary key not defined in class: %s'
% name) for
k in
mappings.iterkeys(): attrs.pop(k) attrs['__table__']
= name.lower() attrs['__mappings__']
= mappings attrs['__primary_key__']
= primary_key attrs['__sql__']
= _gen_sql(attrs['__table__'],mappings) print
str(attrs['__sql__']) tables.append(attrs['__sql__']) for
trigger in
_triggers: if
not trigger
in attrs: attrs[trigger]
= None return
type.__new__(cls,name,bases,attrs)class
Model(dict): __metaclass__
= ModelMetaclass def
__init__(self,**kw): super(Model,self).__init__(**kw) def
__getattr__(self,key): try: return
self[key] except
KeyError: raise
AttributeError(r"'Model' object has no attribute '%s'"
% key) def
__setattr__(self,key,value): self[key]
= value print
'%s: %s' %
self,value # 该方法可以注释掉 def
save(self): fields
= [] params
= [] args
= [] for
k,v in
self.__mappings__.iteritems(): fields.append(v.name) params.append('?') args.append(getattr(self,k,None)) sql
= 'insert into %s (%s) values(%s)'
% (self.__table__,','.join(fields),','.join(params)) print
sql print
('ARGS: %s'
% str(args))class
User(Model): id
= StringField(primary_key=True,ddl='varchar(50)') name
= StringField(ddl='varchar(50)')sql =
''.join(tables)sql =
sql.replace('`','')print
sqlimport
mysql.connectorconfig
= {'user':'root','password':'z5201314','host':'127.0.0.1','port':3306,'database':'test'}cxn =
mysql.connector.connect(**config)cursor
= cxn.cursor()cursor.execute(sql) |
运行结果:

查看数据库:

本文介绍了如何使用ORM(对象关系映射)技术编写简单的Python类来映射数据库中的表,以实现数据的增删改查操作。通过定义类、字段和元类,实现了基本的表创建和对象操作。

428

被折叠的 条评论
为什么被折叠?



