-
Notifications
You must be signed in to change notification settings - Fork 56
/
sqlalchemy详解.html
2511 lines (2107 loc) · 127 KB
/
sqlalchemy详解.html
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html>
<head>
<!-- 2016-02-25 四 16:28 -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>sqlalchemy详解</title>
<meta name="generator" content="Org-mode">
<meta name="author" content="万泽(德山书生)">
<meta name="description" content="制作者邮箱:[email protected]"
>
<style type="text/css">
body {
padding-right: 30px;
padding-left: 30px;
margin-right: auto;
margin-left: auto;
}
@media (min-width: 768px) {
body {
width: 732px;
}
}
@media (min-width: 992px) {
body {
width: 948px;
}
}
@media (min-width: 1200px) {
body {
width: 1140px;
}
}
.title {
display: block;
text-align: center;
padding: 10px;
}
.center-block {
display: block;
margin-left: auto;
margin-right: auto;
}
.underline{
text-decoration: underline;
}
#content {
display: block;
margin-left: 10%;
margin-right: 10%;
}
code {
padding: 2px 4px;
color: #c7254e;
background-color: #f9f2f4;
border-radius: 4px;
}
pre {
display: block;
padding: 9.5px;
margin: 0 0 10px;
font-size: 13px;
line-height: 1.42857143;
color: #333;
word-break: break-all;
/*word-wrap: break-word;*/
word-wrap: normal; /* horizontal scrolling */
background-color: #f5f5f5;
border: 1px solid #ccc;
border-radius: 4px;
}
blockquote {
padding: 10px 20px;
margin: 0 0 20px;
font-size: 17.5px;
border-left: 5px solid #eee;
}
p{
text-indent:2em;
line-height:150%;
}
li, dt{
margin-top: 0.5em;
margin-bottom: 0.5em;
}
video{
width: 95%;
margin-left: auto;
margin-right: auto;
}
figure p{
text-indent:0em;
}
img{
max-width: 95%;
}
figure{
text-align: center;
}
/* class */
.framed{
max-width:700px;
border:1px solid ;
padding: 1em;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.notecard{
width: 320px;
position:relative;
right: -215px;
padding: 1em;
margin:0 auto;
border: solid 1px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
/*
table
*/
table {
border-collapse: collapse;
border-spacing: 0;
margin: 16px 0;
empty-cells: show;
border: 1px solid #ccc;
width: 100%;
display: table;
}
table tr {
border-bottom: 1px solid #ddd;
}
table th,table td{
padding:8px;
}
table tr:nth-child(even) {
background-color: #f1f1f1;
}
.highlight .hll { background-color: #ffffcc }
.highlight { background: #f8f8f8; }
.highlight .c { color: #8f5902; font-style: italic } /* Comment */
.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */
.highlight .g { color: #000000 } /* Generic */
.highlight .k { color: #204a87; font-weight: bold } /* Keyword */
.highlight .l { color: #000000 } /* Literal */
.highlight .n { color: #000000 } /* Name */
.highlight .o { color: #ce5c00; font-weight: bold } /* Operator */
.highlight .x { color: #000000 } /* Other */
.highlight .p { color: #000000; font-weight: bold } /* Punctuation */
.highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */
.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #8f5902; font-style: italic } /* Comment.Preproc */
.highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */
.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */
.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */
.highlight .gd { color: #a40000 } /* Generic.Deleted */
.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */
.highlight .gr { color: #ef2929 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #000000; font-style: italic } /* Generic.Output */
.highlight .gp { color: #8f5902 } /* Generic.Prompt */
.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */
.highlight .kc { color: #204a87; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #204a87; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #204a87; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #204a87; font-weight: bold } /* Keyword.Pseudo */
.highlight .kr { color: #204a87; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #204a87; font-weight: bold } /* Keyword.Type */
.highlight .ld { color: #000000 } /* Literal.Date */
.highlight .m { color: #0000cf; font-weight: bold } /* Literal.Number */
.highlight .s { color: #4e9a06 } /* Literal.String */
.highlight .na { color: #c4a000 } /* Name.Attribute */
.highlight .nb { color: #204a87 } /* Name.Builtin */
.highlight .nc { color: #000000 } /* Name.Class */
.highlight .no { color: #000000 } /* Name.Constant */
.highlight .nd { color: #5c35cc; font-weight: bold } /* Name.Decorator */
.highlight .ni { color: #ce5c00 } /* Name.Entity */
.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #000000 } /* Name.Function */
.highlight .nl { color: #f57900 } /* Name.Label */
.highlight .nn { color: #000000 } /* Name.Namespace */
.highlight .nx { color: #000000 } /* Name.Other */
.highlight .py { color: #000000 } /* Name.Property */
.highlight .nt { color: #204a87; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #000000 } /* Name.Variable */
.highlight .ow { color: #204a87; font-weight: bold } /* Operator.Word */
.highlight .w { color: #f8f8f8; text-decoration: underline } /* Text.Whitespace */
.highlight .mb { color: #0000cf; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000cf; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000cf; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000cf; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000cf; font-weight: bold } /* Literal.Number.Oct */
.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */
.highlight .sc { color: #4e9a06 } /* Literal.String.Char */
.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */
.highlight .se { color: #4e9a06 } /* Literal.String.Escape */
.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */
.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */
.highlight .sx { color: #4e9a06 } /* Literal.String.Other */
.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */
.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */
.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */
.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #000000 } /* Name.Variable.Class */
.highlight .vg { color: #000000 } /* Name.Variable.Global */
.highlight .vi { color: #000000 } /* Name.Variable.Instance */
.highlight .il { color: #0000cf; font-weight: bold } /* Literal.Number.Integer.Long */
</style>
</head>
<body>
<div id="content">
<header>
<h1 class="title">sqlalchemy详解</h1>
</header><nav id="table-of-contents">
<h2>Table of Contents</h2>
<div id="text-table-of-contents">
<ul>
<li><a href="#orgheadline4">1. 前言</a>
<ul>
<li><a href="#orgheadline1">1.1. 安装</a></li>
<li><a href="#orgheadline2">1.2. 引用惯例</a></li>
<li><a href="#orgheadline3">1.3. 简介</a></li>
</ul>
</li>
<li><a href="#orgheadline34">2. 非ORM风格</a>
<ul>
<li><a href="#orgheadline10">2.1. 创建一个Engine</a>
<ul>
<li><a href="#orgheadline7">2.1.1. 连接sqlite3</a>
<ul>
<li><a href="#orgheadline5">2.1.1.1. 连接sqlite3 in-memory</a></li>
<li><a href="#orgheadline6">2.1.1.2. 连接sqlite3 on-disk</a></li>
</ul>
</li>
<li><a href="#orgheadline8">2.1.2. 连接mysql</a></li>
<li><a href="#orgheadline9">2.1.3. 连接postgresql</a></li>
</ul>
</li>
<li><a href="#orgheadline14">2.2. MetaData对象</a>
<ul>
<li><a href="#orgheadline11">2.2.1. 创建一个unbound MetaData对象</a></li>
<li><a href="#orgheadline12">2.2.2. bind一个Engine对象</a></li>
<li><a href="#orgheadline13">2.2.3. 测试数据库是否存在</a></li>
</ul>
</li>
<li><a href="#orgheadline23">2.3. 创建一个Table对象</a>
<ul>
<li><a href="#orgheadline15">2.3.1. 利用已存在的Table</a></li>
<li><a href="#orgheadline16">2.3.2. 实际在数据库中创建表格</a></li>
<li><a href="#orgheadline17">2.3.3. 列的属性设置</a></li>
<li><a href="#orgheadline19">2.3.4. 列的数据类型声明</a>
<ul>
<li><a href="#orgheadline18">2.3.4.1. mysql方言的额外类型</a></li>
</ul>
</li>
<li><a href="#orgheadline20">2.3.5. postgresql额外的类型</a></li>
<li><a href="#orgheadline21">2.3.6. Oracle额外的类型</a></li>
<li><a href="#orgheadline22">2.3.7. 更多的类型支持</a></li>
</ul>
</li>
<li><a href="#orgheadline24">2.4. insert语句</a></li>
<li><a href="#orgheadline25">2.5. delete语句</a></li>
<li><a href="#orgheadline26">2.6. update语句</a></li>
<li><a href="#orgheadline29">2.7. select语句</a>
<ul>
<li><a href="#orgheadline27">2.7.1. ResultProxy对象</a></li>
<li><a href="#orgheadline28">2.7.2. RowProxy对象</a></li>
</ul>
</li>
<li><a href="#orgheadline33">2.8. 多表连接</a>
<ul>
<li><a href="#orgheadline30">2.8.1. 交叉连接或笛卡尔积</a></li>
<li><a href="#orgheadline31">2.8.2. 内连接</a></li>
<li><a href="#orgheadline32">2.8.3. 外连接</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#orgheadline48">3. ORM风格</a>
<ul>
<li><a href="#orgheadline42">3.1. CRUD操作</a>
<ul>
<li><a href="#orgheadline35">3.1.1. 增加记录</a></li>
<li><a href="#orgheadline39">3.1.2. 查询记录</a>
<ul>
<li><a href="#orgheadline36">3.1.2.1. 过滤排序等操作</a></li>
<li><a href="#orgheadline37">3.1.2.2. 返回结果</a></li>
<li><a href="#orgheadline38">3.1.2.3. text函数</a></li>
</ul>
</li>
<li><a href="#orgheadline40">3.1.3. 更改记录</a></li>
<li><a href="#orgheadline41">3.1.4. 删除记录</a></li>
</ul>
</li>
<li><a href="#orgheadline47">3.2. ORM层的关系</a>
<ul>
<li><a href="#orgheadline43">3.2.1. one-to-many模型</a></li>
<li><a href="#orgheadline44">3.2.2. one-to-one模型</a></li>
<li><a href="#orgheadline45">3.2.3. many-to-one模型</a></li>
<li><a href="#orgheadline46">3.2.4. many-to-many模型</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#orgheadline53">4. 高级议题</a>
<ul>
<li><a href="#orgheadline49">4.1. cascade</a></li>
<li><a href="#orgheadline50">4.2. 自我引用表达树状结构</a></li>
<li><a href="#orgheadline51">4.3. 面向ORM的内省机制</a></li>
<li><a href="#orgheadline52">4.4. 面向ORM的数据继承机制</a></li>
</ul>
</li>
<li><a href="#orgheadline59">5. 附录</a>
<ul>
<li><a href="#orgheadline55">5.1. 其他</a>
<ul>
<li><a href="#orgheadline54">5.1.1. datetime数据类型</a></li>
</ul>
</li>
<li><a href="#orgheadline56">5.2. 如何测试</a></li>
<li><a href="#orgheadline57">5.3. flask-sqlalchemy模块</a></li>
<li><a href="#orgheadline58">5.4. 参考资料</a></li>
</ul>
</li>
</ul>
</div>
</nav>
<div class="outline-2">
<h2 id="orgheadline4">前言</h2>
<div class="outline-text-2" id="text-1">
<p>
老实说sqlalchemy这个模块特别难学,主要原因倒不是这个模块本身,阻碍我很好地学习这个模块的是这个心态,认为自己可以直接学习sqlalchemyORM封装就行了,不用学习SQL语句。这是错误的。要学好sqlalchemy必须先学习好SQL语句,要完全发挥出sqlalchemy的威力,也必须先学会SQL语句和对应的SQL实现。然后还有一个误区,我们在使用上也不一定要使用class这样的类声明风格。实际上sqlalchemy这个模块里面内容是很丰富的,是很灵活的。它是可以完全取代sqlite3模块和psycopg2模块等初级的DB API,然后还提供了高级的ORM封装。
</p>
</div>
<div class="outline-3">
<h3 id="orgheadline1">安装</h3>
<div class="outline-text-3" id="text-1-1">
<p>
sqlalchemy的安装简单用pip3命令安装之即可:
</p>
<pre>
sudo pip3 install sqlalchemy
</pre>
<p>
惯例python模块安装好之后进去输入版本号测试下安装情况:
</p>
<pre>
>>> import sqlalchemy
>>> sqlalchemy.__version__
'1.0.8'
</pre>
</div>
</div>
<div class="outline-3">
<h3 id="orgheadline2">引用惯例</h3>
<div class="outline-text-3" id="text-1-2">
<p>
在后面都默认有如下引用:
</p>
<pre>
from sqlalchemy import *
</pre>
<p>
后面将不会再提及,也就是凡是 <code>from sqlalchemy import what</code> 的所有语句也都归于如上一条引用。
</p>
</div>
</div>
<div class="outline-3">
<h3 id="orgheadline3">简介</h3>
<div class="outline-text-3" id="text-1-3">
<p>
通过sqlalchemy连接具体的某个数据库,前面有一些准备工作要做,参考 <a href="http://www.aosabook.org/en/sqlalchemy.html">sqlalchemy architecture</a> 一文的描述:
</p>
<figure>
<p><img src="images/layers.png" alt="layers.png">
</p>
<figcaption><span class="figure-number">Figure 1:</span> SQLAlchemy layer diagram</figcaption>
</figure>
<p>
和数据库直接相连的是我们熟悉的那些DBAPI接口模块,比如: sqlite3, pymysql, psycopg2等,然后中间的核心层有Engine,连接池,方言,SQL表达语言和类型系统。core层很重要,实际上有些模块是完全建构在core层之上的,不一定要用ORM方法。
</p>
</div>
</div>
</div>
<div class="outline-2">
<h2 id="orgheadline34">非ORM风格</h2>
<div class="outline-text-2" id="text-2">
</div><div class="outline-3">
<h3 id="orgheadline10">创建一个Engine</h3>
<div class="outline-text-3" id="text-2-1">
<p>
创建一个 <code>Engine</code> 对象实际上对应的就是和数据库的连接操作。具体是通过 <code>create_engine</code> 函数创建的Engine对象,其一开始并没有实际连接数据库,只有具体要求某个操作的时候才会去连接。
</p>
</div>
<div class="outline-4">
<h4 id="orgheadline7">连接sqlite3</h4>
<div class="outline-text-4" id="text-2-1-1">
</div><div class="outline-5">
<h5 id="orgheadline5">连接sqlite3 in-memory</h5>
<div class="outline-text-5" id="text-2-1-1-1">
<pre>
engine = create_engine('sqlite://')
</pre>
<p>
但是推荐采用如下写法:
</p>
<pre>
engine = create_engine('sqlite:///:memory:',echo=True)
</pre>
<p>
这样后面谈及的sqlalchmy_utils的 <code>database_exists</code> 函数也能正常工作。
</p>
</div>
</div>
<div class="outline-5">
<h5 id="orgheadline6">连接sqlite3 on-disk</h5>
<div class="outline-text-5" id="text-2-1-1-2">
<pre>
engine = create_engine('sqlite:///sqlite3_learning_example.db')
</pre>
<p>
上面的db文件是创建在命令行当前工作目录下的,也就是相对路径表达。此外还可以如下写上绝对路径表达:
</p>
<pre>
engine = create_engine('sqlite:////absolute/path/to/foo.db')
</pre>
<p>
在三个斜杠线的基础上还需要加上一个斜杠线。作为这种形式的通用表达,前面必定有两个斜杠线,然后第二个斜杠线和第三个斜杠线之间是登录信息的描述,因为sqlite3没有这些信息,所以空了,如下所示:
</p>
<pre>
dialect://username:password@host:port/database
</pre>
<p>
或者某个方言系统再加上某个驱动:
</p>
<pre>
dialect+driver://username:password@host:port/database
</pre>
<p>
这里的方言可以有:
</p>
<dl class="org-dl">
<dt>sqlite</dt><dd>默认的driver的官方的 <strong>sqlite3</strong> 模块,这个应该不需要改动。</dd>
<dt>mysql</dt><dd>默认的dirver是 <strong>mysql-python</strong> ,但推荐使用 <strong>pymysql</strong> ,你需要用pip安装之。</dd>
</dl>
<pre>
engine = create_engine('mysql+pymysql://root@localhost/test')
</pre>
<dl class="org-dl">
<dt>postgresql</dt><dd>默认的driver是 <strong>psycopg2</strong> ,这个还行。</dd>
<dt>oracle</dt><dd>默认的driver是 <strong>cx_oracle</strong> 。</dd>
<dt>mssql</dt><dd>默认的driver是 <strong>pyodbc</strong> 。</dd>
</dl>
</div>
</div>
</div>
<div class="outline-4">
<h4 id="orgheadline8">连接mysql</h4>
<div class="outline-text-4" id="text-2-1-2">
<pre>
engine = create_engine('mysql+pymysql://localhost/mysql_db')
</pre>
<p>
确保你安装了pymysql:
</p>
<pre>
sudo pip3 install pymysql
</pre>
</div>
</div>
<div class="outline-4">
<h4 id="orgheadline9">连接postgresql</h4>
<div class="outline-text-4" id="text-2-1-3">
<pre>
engine = create_engine('postgres://rick:foo@localhost:5432/pg_db')
</pre>
</div>
</div>
</div>
<div class="outline-3">
<h3 id="orgheadline14">MetaData对象</h3>
<div class="outline-text-3" id="text-2-2">
<p>
MetaData对象你可以看作比Table层更高一级的抽象,里面存放着Table对象的一些metadata描述信息。一个简单的理解是将一个MetaData对象看作sqlalchemy内部的database概念。
</p>
</div>
<div class="outline-4">
<h4 id="orgheadline11">创建一个unbound MetaData对象</h4>
<div class="outline-text-4" id="text-2-2-1">
<p>
通过 <code>MetaData()</code> 默认创建的就是一个unbound MetaData对象。
</p>
<pre>
metadata = MetaData()
</pre>
</div>
</div>
<div class="outline-4">
<h4 id="orgheadline12">bind一个Engine对象</h4>
<div class="outline-text-4" id="text-2-2-2">
<p>
你可以如下将一个unbound MetaData对象具体 <code>bind</code> 一个Engine对象。
</p>
<pre>
engine = create_engine('sqlite://')
metadata = MetaData()
metadata.bind = engine
</pre>
<p>
或者在上面创建的时候就指定:
</p>
<pre>
engine = create_engine('sqlite://')
metadata = MetaData(engine)
</pre>
<p>
或者你还可以直接engine的URL表达来后台自动创建一个engine,于是有:
</p>
<pre>
metadata = MetaData('sqlite://')
</pre>
<p>
对于初学者用的最多的还是 <code>BoundMetaData</code> ,通过上面谈及的方法创建了一个 <code>BoundMetaData</code> 对象之后,某个Table对象关联了该 <code>BoundMetaData</code> 对象,然后该Table对象就可以直接通过:
</p>
<pre>
table.create()
</pre>
<p>
来创建自身了。
</p>
</div>
</div>
<div class="outline-4">
<h4 id="orgheadline13">测试数据库是否存在</h4>
<div class="outline-text-4" id="text-2-2-3">
<p>
这里关于 <code>sqlalchemy_utils</code> 的想法来自 <a href="http://stackoverflow.com/questions/6506578/how-to-create-a-new-database-using-sqlalchemy">这个网页</a> 。
</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">sqlalchemy_utils</span> <span class="kn">import</span> <span class="n">database_exists</span><span class="p">,</span> <span class="n">create_database</span>
<span class="k">def</span> <span class="nf">init_sqlalchemy</span><span class="p">(</span><span class="n">dburl</span><span class="p">,</span><span class="n">echo</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="n">engine</span> <span class="o">=</span> <span class="n">create_engine</span><span class="p">(</span><span class="n">dburl</span><span class="p">,</span><span class="n">echo</span><span class="o">=</span><span class="n">echo</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">database_exists</span><span class="p">(</span><span class="n">engine</span><span class="o">.</span><span class="n">url</span><span class="p">):</span><span class="c1">###确保目标数据库是存在的。</span>
<span class="n">create_database</span><span class="p">(</span><span class="n">engine</span><span class="o">.</span><span class="n">url</span><span class="p">)</span>
<span class="n">metadata</span> <span class="o">=</span> <span class="n">MetaData</span><span class="p">(</span><span class="n">bind</span> <span class="o">=</span> <span class="n">engine</span><span class="p">)</span>
<span class="k">return</span> <span class="n">metadata</span>
<span class="n">metadata</span> <span class="o">=</span> <span class="n">init_sqlalchemy</span><span class="p">(</span><span class="s1">'sqlite:///test.db'</span><span class="p">)</span>
</pre></div>
<p>
这里的 <code>sqlalchemy_utils</code> 需要额外安装,在这里主要是利用其 <code>database_exists</code> 函数来检测某个数据库是否存在,然后如果不存在的话则用 <code>create_database</code> 函数创建之。
</p>
<p>
上面的 <code>init_sqlalchemy</code> 函数最重要的一个参数就是那个 <code>dburl</code> ,具体其细节前面已有所叙述,正是照它来创建的Engine,并基于这个Engine对象来创建的MetaData对象,一般将这个MetaData对象bind之前的那个engine,然后返回该metadata即可,后面主要需要使用这个metadata。
</p>
<p>
然后后面实际操作就以创建一个Table对象开始了,其他database的操作,建议如同上面处理的一样,都提到顶层用sqlalchemy_utils模块来处理之。类似的还有 <strong>drop_database</strong> : 删除database,参数如create_database也是某个Engine对象的url。
</p>
</div>
</div>
</div>
<div class="outline-3">
<h3 id="orgheadline23">创建一个Table对象</h3>
<div class="outline-text-3" id="text-2-3">
<p>
下面是一个完整的例子,最后创建了一个Table表格。这里的 <code>db</code> 也就是前面谈及的MetaData对象,我们看到在创建Table对象的时候第一个参数是具体创建的SQL表格的名字,第二个就是该表格bind的某个MetaData对象,也可以简单理解为该表格对象存入该MetaData对象代表的database中。然后后面调用 <code>db.create_all()</code> ,所有这些bind到该db上的表格都将创建。你还可以用 <code>users.create()</code> 来单独创建某个表格。
</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">sqlalchemy_utils</span> <span class="kn">import</span> <span class="n">database_exists</span><span class="p">,</span> <span class="n">create_database</span>
<span class="k">def</span> <span class="nf">init_sqlalchemy</span><span class="p">(</span><span class="n">dburl</span><span class="p">,</span><span class="n">echo</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="n">engine</span> <span class="o">=</span> <span class="n">create_engine</span><span class="p">(</span><span class="n">dburl</span><span class="p">,</span><span class="n">echo</span><span class="o">=</span><span class="n">echo</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">database_exists</span><span class="p">(</span><span class="n">engine</span><span class="o">.</span><span class="n">url</span><span class="p">):</span><span class="c1">###确保目标数据库是存在的。</span>
<span class="n">create_database</span><span class="p">(</span><span class="n">engine</span><span class="o">.</span><span class="n">url</span><span class="p">)</span>
<span class="n">metadata</span> <span class="o">=</span> <span class="n">MetaData</span><span class="p">(</span><span class="n">bind</span> <span class="o">=</span> <span class="n">engine</span><span class="p">)</span>
<span class="k">return</span> <span class="n">metadata</span>
<span class="n">db</span> <span class="o">=</span> <span class="n">init_sqlalchemy</span><span class="p">(</span><span class="s1">'sqlite:///test.db'</span><span class="p">)</span>
<span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span><span class="s1">'users'</span><span class="p">,</span> <span class="n">db</span><span class="p">,</span>
<span class="n">Column</span><span class="p">(</span><span class="s1">'user_id'</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="bp">True</span><span class="p">),</span>
<span class="n">Column</span><span class="p">(</span><span class="s1">'name'</span><span class="p">,</span> <span class="n">String</span><span class="p">(</span><span class="mi">40</span><span class="p">)),</span>
<span class="n">Column</span><span class="p">(</span><span class="s1">'age'</span><span class="p">,</span> <span class="n">Integer</span><span class="p">),</span>
<span class="n">Column</span><span class="p">(</span><span class="s1">'password'</span><span class="p">,</span> <span class="n">String</span><span class="p">),</span>
<span class="p">)</span>
<span class="n">db</span><span class="o">.</span><span class="n">create_all</span><span class="p">()</span>
</pre></div>
</div>
<div class="outline-4">
<h4 id="orgheadline15">利用已存在的Table</h4>
<div class="outline-text-4" id="text-2-3-1">
<p>
如果某个数据库的某个Table已经存在了,那么你就没有必要如上去创建一个Table对象了,只需要如下做就可以获得该Table对象了:
</p>
<pre>
users = Table('users',db,autoload=True)
</pre>
<p>
具体就是将 <code>autoload</code> 设置为True即可。这里的db就是所谓的metadata,然后这里必须是bind了的metadata对象,若还未bind,则还需要加上autoload_with参数。
</p>
</div>
</div>
<div class="outline-4">
<h4 id="orgheadline16">实际在数据库中创建表格</h4>
<div class="outline-text-4" id="text-2-3-2">
<p>
具体可以整个metadata对象,调用 <code>create_all</code> 方法来创建所有表格(其也有 <code>checkfirst</code> 参数。):
</p>
<pre>
db.create_all()
</pre>
<p>
或者该Table对象具体调用 <code>create</code> 方法来自我创建之。在应用推荐加上 <code>checkfirst=True</code> 设置,这样就算数据库中该表格已经存在也不会报错。如下所示:
</p>
<pre>
users.create(checkfirst=True)
</pre>
<p>
类似的还有如下用法用于安装删除某个表格,即使该表格不存在也不会报错:
</p>
<pre>
users.drop(checkfirst=True)
</pre>
<p>
这里代码改成了这个样子了:
</p>
<div class="highlight"><pre><span></span><span class="k">try</span><span class="p">:</span>
<span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span><span class="s1">'users'</span><span class="p">,</span><span class="n">db</span><span class="p">,</span><span class="n">autoload</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="k">except</span> <span class="n">sqlalchemy</span><span class="o">.</span><span class="n">exc</span><span class="o">.</span><span class="n">NoSuchTableError</span><span class="p">:</span>
<span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span><span class="s1">'users'</span><span class="p">,</span> <span class="n">db</span><span class="p">,</span>
<span class="n">Column</span><span class="p">(</span><span class="s1">'user_id'</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="bp">True</span><span class="p">),</span>
<span class="n">Column</span><span class="p">(</span><span class="s1">'name'</span><span class="p">,</span> <span class="n">String</span><span class="p">(</span><span class="mi">40</span><span class="p">)),</span>
<span class="n">Column</span><span class="p">(</span><span class="s1">'age'</span><span class="p">,</span> <span class="n">Integer</span><span class="p">),</span>
<span class="n">Column</span><span class="p">(</span><span class="s1">'password'</span><span class="p">,</span> <span class="n">String</span><span class="p">),</span>
<span class="p">)</span>
</pre></div>
<p>
注意这个 <code>NoSuchTableError</code> ,如果通过 <code>autoload=True</code> 来获取该Table对象而其在数据库中并不存在,则将抛出这个异常。
</p>
</div>
</div>
<div class="outline-4">
<h4 id="orgheadline17">列的属性设置</h4>
<div class="outline-text-4" id="text-2-3-3">
<p>
创建表格对象后面一系列的参数就是具体各个列Column对象,其第一个参数是具体列的名字,然后第二个参数该列所存储的值的类型,后面还可以跟其他一些可选项作为属性的进一步修饰。具体如下所示:
</p>
<dl class="org-dl">
<dt>primary_key</dt><dd>设置该列为主键列或者称之为主键约束</dd>
<dt>unique</dt><dd>该列加上唯一约束,即该列的值不可重复。主键约束是一种特殊的唯一约束。</dd>
<dt>nullable</dt><dd>该列可不可为空</dd>
<dt>default</dt><dd>该列的默认值设置</dd>
<dt>index</dt><dd>该列是否加入索引</dd>
<dt>auto_increment</dt><dd>Integer的列数值自动递增</dd>
<dt>ForeignKey('brand.id')</dt><dd>设置外键约束</dd>
<dt>CheckConstraint('amount > 0')</dt><dd>设置Check约束</dd>
<dt>onupdate</dt><dd>最常见的用法如下:</dd>
</dl>
<pre>
onupdate=datetime.utcnow
</pre>
<p>
应该意思是若update了则调用某个callable对象吧。
</p>
</div>
</div>
<div class="outline-4">
<h4 id="orgheadline19">列的数据类型声明</h4>
<div class="outline-text-4" id="text-2-3-4">
<p>
下面对各个列存储的值的可能类型描述详细介绍之,更多信息请参看文档查看之。
</p>
<table>
<colgroup>
<col class="org-left">
<col class="org-left">
<col class="org-left">
<col class="org-left">
</colgroup>
<thead>
<tr>
<th scope="col" class="org-left">Class name</th>
<th scope="col" class="org-left">Python Type</th>
<th scope="col" class="org-left">SQL Type (for SQLitedriver)</th>
<th scope="col" class="org-left">Arguments</th>
</tr>
</thead>
<tbody>
<tr>
<td class="org-left">String</td>
<td class="org-left">string</td>
<td class="org-left">TEXT or VARCHAR</td>
<td class="org-left">length</td>
</tr>
<tr>
<td class="org-left">Integer</td>
<td class="org-left">int</td>
<td class="org-left">INTEGER</td>
<td class="org-left">none</td>
</tr>
<tr>
<td class="org-left">SmallInteger</td>
<td class="org-left">int</td>
<td class="org-left">SMALLINT</td>
<td class="org-left">none</td>
</tr>
<tr>
<td class="org-left">Numeric</td>
<td class="org-left">float,Decimal</td>
<td class="org-left">NUMERIC</td>
<td class="org-left">precision=10, length=2</td>
</tr>
<tr>
<td class="org-left">Float</td>
<td class="org-left">float</td>
<td class="org-left">NUMERIC</td>
<td class="org-left">precision=10</td>
</tr>
<tr>
<td class="org-left">DateTime</td>
<td class="org-left">datetime.datetime</td>
<td class="org-left">TIMESTAMP</td>
<td class="org-left">none</td>
</tr>
<tr>
<td class="org-left">time</td>
<td class="org-left">datetime.time</td>
<td class="org-left">TIME</td>
<td class="org-left">none</td>
</tr>
<tr>
<td class="org-left">Date</td>
<td class="org-left">datetime.date</td>
<td class="org-left">DATE</td>
<td class="org-left">none</td>
</tr>
<tr>
<td class="org-left">Binary</td>
<td class="org-left">byte string</td>
<td class="org-left">BLOB</td>
<td class="org-left">length</td>
</tr>
<tr>
<td class="org-left">Boolean</td>
<td class="org-left">bool</td>
<td class="org-left">BOOLEAN</td>
<td class="org-left">none</td>
</tr>
<tr>
<td class="org-left">Unicode</td>
<td class="org-left">unicode</td>
<td class="org-left">TEXT or VARCHAR</td>
<td class="org-left">length</td>
</tr>
</tbody>
</table>
<p>
大致就这些,然后sqlalchemy还有一些类名大致和上面的某个等同,只是多了一个使用上的名字。
</p>
<dl class="org-dl">
<dt>FLOAT</dt><dd>等同于 Numeric</dd>
<dt>TEXT</dt><dd>等同于 String</dd>
<dt>DECIMAL</dt><dd>等同于 Numeric</dd>
<dt>INT</dt><dd>等同于 Integer</dd>
<dt>INTEGER</dt><dd>等同于 Integer</dd>
<dt>TIMESTAMP</dt><dd>等同于 DateTime</dd>
<dt>DATETIME</dt><dd>等同于 DateTime</dd>
<dt>CLOB</dt><dd>等同于 String</dd>
<dt>VARCHAR</dt><dd>等同于 String</dd>
<dt>CHAR</dt><dd>等同于 String</dd>
<dt>NCHAR</dt><dd>等同于 Unicode</dd>
<dt>BLOB</dt><dd>等同于 Binary</dd>
<dt>BOOLEAN</dt><dd>等同于 Boolean</dd>
</dl>
</div>
<div class="outline-5">
<h5 id="orgheadline18">mysql方言的额外类型</h5>
<div class="outline-text-5" id="text-2-3-4-1">
<table>
<colgroup>
<col class="org-left">
<col class="org-left">
<col class="org-left">
<col class="org-left">
</colgroup>
<thead>
<tr>
<th scope="col" class="org-left">Class name</th>
<th scope="col" class="org-left">Python type</th>
<th scope="col" class="org-left">SQL type</th>
<th scope="col" class="org-left">Arguments</th>
</tr>
</thead>
<tbody>
<tr>
<td class="org-left">MSEnum</td>
<td class="org-left">string</td>
<td class="org-left">ENUM</td>
<td class="org-left">values</td>
</tr>
<tr>
<td class="org-left">MSTinyInteger</td>
<td class="org-left">int</td>
<td class="org-left">TINYINT</td>
<td class="org-left">length</td>
</tr>
<tr>
<td class="org-left">MSBigInteger</td>
<td class="org-left">int</td>
<td class="org-left">BIGINT</td>
<td class="org-left">length</td>
</tr>
<tr>
<td class="org-left">MSDouble</td>
<td class="org-left">float</td>
<td class="org-left">DOUBLE</td>
<td class="org-left">length=10,precision=2</td>
</tr>
<tr>
<td class="org-left">MSTinyText</td>
<td class="org-left">string</td>
<td class="org-left">TINYTEXT</td>
<td class="org-left">none</td>
</tr>
<tr>
<td class="org-left">MSMediumText</td>
<td class="org-left">string</td>
<td class="org-left">MEDIUMTEXT</td>
<td class="org-left">none</td>
</tr>
<tr>
<td class="org-left">MSLongText</td>
<td class="org-left">string</td>
<td class="org-left">LONGTEXT</td>
<td class="org-left">none</td>
</tr>
<tr>
<td class="org-left">MSNVarChar</td>
<td class="org-left">unicode</td>
<td class="org-left">NATIONAL VARCHAR</td>
<td class="org-left">length</td>
</tr>
<tr>
<td class="org-left">MSTinyBlob</td>
<td class="org-left">byte string</td>
<td class="org-left">TINYBLOB</td>
<td class="org-left">none</td>
</tr>
<tr>
<td class="org-left">MSMediumBlob</td>
<td class="org-left">byte string</td>
<td class="org-left">MEDIUMBLOB</td>
<td class="org-left">none</td>
</tr>
<tr>
<td class="org-left">MSLongBlob</td>
<td class="org-left">byte string</td>
<td class="org-left">LONGBLOB</td>
<td class="org-left">none</td>
</tr>
<tr>
<td class="org-left">MSBinary</td>
<td class="org-left">byte string</td>
<td class="org-left">BINARY</td>
<td class="org-left">length</td>
</tr>
<tr>
<td class="org-left">MSVarBinary</td>
<td class="org-left">byte string</td>
<td class="org-left">VARBINARY</td>
<td class="org-left">length</td>
</tr>
<tr>
<td class="org-left">MSSet</td>
<td class="org-left">set</td>
<td class="org-left">SET</td>
<td class="org-left">set values</td>
</tr>
<tr>