-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtutorial.html
More file actions
493 lines (447 loc) · 58.8 KB
/
tutorial.html
File metadata and controls
493 lines (447 loc) · 58.8 KB
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="../_static/favicon.ico">
<title>GINO 基础教程 - GINO 1.1.0rc1 文档</title>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async
src="https://www.googletagmanager.com/gtag/js?id=UA-3759436-10"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag () {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'UA-3759436-10');
</script>
<link rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Raleway:400,500,600,700&display=swap">
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css">
<link type="text/css" rel="stylesheet"
href="../_static/css/materialize.min.css"
media="screen,projection"/>
<link rel="stylesheet" href="../_static/pygments.css"
type="text/css"/>
<link type="text/css" rel="stylesheet"
href="../_static/css/gino.css"/>
</head>
<body>
<header>
<div class="navbar-fixed">
<nav>
<div class="nav-wrapper">
<a href="#" data-target="sidenav" class="sidenav-trigger"><hr><hr><hr></a>
<a href="../index.html" class="brand-logo">
<div class="img"
style="background-image: url(../_static/logo.svg); width: 103px; height: 40px;"></div>
</a>
<div class="breadcrumbs">
<a class="breadcrumb" style="display: none"></a>
<a href="../tutorials.html"
class="breadcrumb">上手教程</a>
<a class="breadcrumb" style="color: #FFFFFF">GINO 基础教程</a>
</div>
<div class="spacer"></div>
<div id="search-container" class="search">
<input type="text" id="search" placeholder="搜索">
<i class="mdi mdi-magnify"></i>
<div id="search-results" style="display: none"></div>
</div>
<a class="btn-flat theme-dark" href="/">
首页
</a>
<a class="btn-flat theme-dark" href="/authors.html">
鸣谢
</a>
<a href="https://github.com/python-gino/gino" target="_blank"
class="github-stars">
<div class="left"><img
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNDNweCIgaGVpZ2h0PSI0MnB4IiB2aWV3Qm94PSIwIDAgNDMgNDIiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDYxLjIgKDg5NjUzKSAtIGh0dHBzOi8vc2tldGNoLmNvbSAtLT4KICAgIDx0aXRsZT5GaWxsIDQ5PC90aXRsZT4KICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPgogICAgPGcgaWQ9IlYzLeacgOaWsOeov+S7tiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9IkhPTUUtdjMiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xNTA3LjAwMDAwMCwgLTQ5LjAwMDAwMCkiIGZpbGw9IiNGRkZGRkUiPgogICAgICAgICAgICA8ZyBpZD0iYmFubmVyLWJnIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMzc5LjAwMDAwMCwgLTE4Ny4wMDAwMDApIj4KICAgICAgICAgICAgICAgIDxnIGlkPSJoZWFkZXIiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDU5Ny4wMDAwMDAsIDIxOC4wMDAwMDApIj4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTMxMC40OTgwMiwxOCBDMTI5OC42MjcxMiwxOCAxMjg5LDI3LjYzOTg4MzEgMTI4OSwzOS41MzIxMTIzIEMxMjg5LDQ5LjA0NTEwMjYgMTI5NS4xNTk4Myw1Ny4xMTQ2ODggMTMwMy43MDMzNCw1OS45NjE4NDM5IEMxMzA0Ljc3OTAzLDYwLjE2MDExMzggMTMwNS4xNzEwMyw1OS40OTUyNDg3IDEzMDUuMTcxMDMsNTguOTI0MjMxMyBDMTMwNS4xNzEwMyw1OC40MTI2OTUgMTMwNS4xNTI1NSw1Ny4wNTkxNzI0IDEzMDUuMTQxOTksNTUuMjYyODQ3IEMxMjk5LjE2MTY3LDU2LjU2MzQ5NzYgMTI5Ny44OTk4Nyw1Mi4zNzYwMzcxIDEyOTcuODk5ODcsNTIuMzc2MDM3MSBDMTI5Ni45MjE4NSw0OS44ODg0MTA2IDEyOTUuNTEyMjMsNDkuMjI2MTg5MSAxMjk1LjUxMjIzLDQ5LjIyNjE4OTEgQzEyOTMuNTYwMTUsNDcuODkxMTcxNyAxMjk1LjY2MDA2LDQ3LjkxNzYwNzcgMTI5NS42NjAwNiw0Ny45MTc2MDc3IEMxMjk3LjgxODA0LDQ4LjA2OTYxNDYgMTI5OC45NTMxMyw1MC4xMzY5MDg5IDEyOTguOTUzMTMsNTAuMTM2OTA4OSBDMTMwMC44NzA5LDUzLjQyNjg2NzYgMTMwMy45ODU3OSw1Mi40NzY0OTM4IDEzMDUuMjEwNjMsNTEuOTI1MzAzNSBDMTMwNS40MDU5Nyw1MC41MzQ3NzA1IDEzMDUuOTYxNjMsNDkuNTg1NzE4NiAxMzA2LjU3NTM3LDQ5LjA0Nzc0NjIgQzEzMDEuODAxNDEsNDguNTA0NDg2NiAxMjk2Ljc4MTk1LDQ2LjY1NjYxMTEgMTI5Ni43ODE5NSwzOC40MDU5MzkyIEMxMjk2Ljc4MTk1LDM2LjA1NTc3OTkgMTI5Ny42MjAwNiwzNC4xMzI1NjE3IDEyOTguOTk1MzcsMzIuNjI4MzU0IEMxMjk4Ljc3MzYzLDMyLjA4Mzc3MjYgMTI5OC4wMzU4MiwyOS44OTM1NTEgMTI5OS4yMDY1NCwyNi45MzAwNzY4IEMxMjk5LjIwNjU0LDI2LjkzMDA3NjggMTMwMS4wMTA4LDI2LjM1MTEyODYgMTMwNS4xMTgyNCwyOS4xMzc0ODE4IEMxMzA2LjgzMjc1LDI4LjY1ODk5MDQgMTMwOC42NzI2NCwyOC40MjEwNjY1IDEzMTAuNTAwNjYsMjguNDExODEzOSBDMTMxMi4zMjczNiwyOC40MjEwNjY1IDEzMTQuMTY1OTQsMjguNjU4OTkwNCAxMzE1Ljg4MzA4LDI5LjEzNzQ4MTggQzEzMTkuOTg3ODgsMjYuMzUxMTI4NiAxMzIxLjc4OTUsMjYuOTMwMDc2OCAxMzIxLjc4OTUsMjYuOTMwMDc2OCBDMTMyMi45NjI4NiwyOS44OTM1NTEgMTMyMi4yMjUwNSwzMi4wODM3NzI2IDEzMjIuMDA0NjMsMzIuNjI4MzU0IEMxMzIzLjM4MjU4LDM0LjEzMjU2MTcgMTMyNC4yMTQwOSwzNi4wNTU3Nzk5IDEzMjQuMjE0MDksMzguNDA1OTM5MiBDMTMyNC4yMTQwOSw0Ni42Nzc3NTk5IDEzMTkuMTg2NzIsNDguNDk3ODc3NiAxMzE0LjM5ODIzLDQ5LjAzMDU2MjggQzEzMTUuMTY5MDQsNDkuNjk1NDI3OSAxMzE1Ljg1NjY5LDUxLjAwOTI5NjUgMTMxNS44NTY2OSw1My4wMTcxMDk4IEMxMzE1Ljg1NjY5LDU1Ljg5NTk4ODkgMTMxNS44MzAyOSw1OC4yMTgzOTA1IDEzMTUuODMwMjksNTguOTI0MjMxMyBDMTMxNS44MzAyOSw1OS41MDA1MzU5IDEzMTYuMjE4MzMsNjAuMTcwNjg4MiAxMzE3LjMwODU0LDU5Ljk2MDUyMjEgQzEzMjUuODQ1NDUsNTcuMTA2NzU3MiAxMzMyLDQ5LjA0MjQ1OSAxMzMyLDM5LjUzMjExMjMgQzEzMzIsMjcuNjM5ODgzMSAxMzIyLjM3Mjg4LDE4IDEzMTAuNDk4MDIsMTgiIGlkPSJGaWxsLTQ5Ij48L3BhdGg+CiAgICAgICAgICAgICAgICA8L2c+CiAgICAgICAgICAgIDwvZz4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg=="
class="github-logo">
GitHub
</div>
<div class="right"><img
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjFweCIgaGVpZ2h0PSIxOXB4IiB2aWV3Qm94PSIwIDAgMjEgMTkiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDYxLjIgKDg5NjUzKSAtIGh0dHBzOi8vc2tldGNoLmNvbSAtLT4KICAgIDx0aXRsZT5QYXRoPC90aXRsZT4KICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPgogICAgPGcgaWQ9IlYzLeacgOaWsOeov+S7tiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9IkhPTUUtdjMiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xNTYxLjAwMDAwMCwgLTYwLjAwMDAwMCkiIGZpbGw9IiNGOEQyMzAiPgogICAgICAgICAgICA8ZyBpZD0iYmFubmVyLWJnIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMzc5LjAwMDAwMCwgLTE4Ny4wMDAwMDApIj4KICAgICAgICAgICAgICAgIDxnIGlkPSJoZWFkZXIiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDU5Ny4wMDAwMDAsIDIxOC4wMDAwMDApIj4KICAgICAgICAgICAgICAgICAgICA8ZyBpZD0ibGFiZWwtY29weS0xMiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTI4OS4wMDAwMDAsIDE4LjAwMDAwMCkiPgogICAgICAgICAgICAgICAgICAgICAgICA8cG9seWdvbiBpZD0iUGF0aCIgcG9pbnRzPSI2MS4wNTQzNTQzIDE3Ljc1NzM4MzYgNTQuMjE1MjQ2NiAxOC4zMTMzOTI5IDU5Ljg4OTM1MTcgMjIuOTczNzM4NyA1Ny43ODQ1MjI4IDI5Ljg0MDExODQgNjQuNDQyNTI3MSAyNi41NDM0MTg4IDcwLjU3NzcyMzkgMjkuODQwMTE4NCA2OS4yMzA0MzI1IDIyLjk3MzczODcgNzQuNzMyNTY5NiAxOC4zMTMzOTI5IDY3Ljg5MzQ2MiAxNy43NTczODM2IDY0LjQ0MjUyNzEgMTEuMzc1Ij48L3BvbHlnb24+CiAgICAgICAgICAgICAgICAgICAgPC9nPgogICAgICAgICAgICAgICAgPC9nPgogICAgICAgICAgICA8L2c+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4=">
<span id="github-star-num"></span>
</div>
</a>
</div>
</nav>
</div>
<div id="sidenav" class="sidenav sidenav-fixed">
<p class="caption" role="heading"><span class="caption-text">上手教程</span></p>
<ul class="current">
<li class="toctree-l1 current"><a class="reference internal" href="../tutorials.html">上手教程</a><ul class="current">
<li class="toctree-l2"><a class="reference internal" href="announcement.html">官宣:Python 异步编程再添一利器</a></li>
<li class="toctree-l2 current"><a class="current reference internal" href="#">GINO 基础教程</a></li>
<li class="toctree-l2"><a class="reference internal" href="fastapi.html">搭建一个 FastAPI 服务器</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="announcement.html">官宣:Python 异步编程再添一利器</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">GINO 基础教程</a></li>
<li class="toctree-l1"><a class="reference internal" href="fastapi.html">搭建一个 FastAPI 服务器</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">进阶用法</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../how-to.html">进阶用法</a></li>
<li class="toctree-l1"><a class="reference internal" href="../how-to/alembic.html">使用 Alembic</a></li>
<li class="toctree-l1"><a class="reference internal" href="../how-to/bakery.html">预制查询</a></li>
<li class="toctree-l1"><a class="reference internal" href="../how-to/contributing.html">贡献</a></li>
<li class="toctree-l1"><a class="reference internal" href="../how-to/crud.html">增删改查</a></li>
<li class="toctree-l1"><a class="reference internal" href="../how-to/faq.html">常见问题</a></li>
<li class="toctree-l1"><a class="reference internal" href="../how-to/json-props.html">JSON 扩展属性</a></li>
<li class="toctree-l1"><a class="reference internal" href="../how-to/loaders.html">加载器与关系</a></li>
<li class="toctree-l1"><a class="reference internal" href="../how-to/pool.html">连接池</a></li>
<li class="toctree-l1"><a class="reference internal" href="../how-to/schema.html">表结构定义</a></li>
<li class="toctree-l1"><a class="reference internal" href="../how-to/transaction.html">数据库事务</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">原理说明</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../explanation.html">原理说明</a></li>
<li class="toctree-l1"><a class="reference internal" href="../explanation/async.html">异步编程基础</a></li>
<li class="toctree-l1"><a class="reference internal" href="../explanation/engine.html">引擎与连接</a></li>
<li class="toctree-l1"><a class="reference internal" href="../explanation/sa20.html">SQLAlchemy 2.0</a></li>
<li class="toctree-l1"><a class="reference internal" href="../explanation/why.html">为什么要用异步 ORM?</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">参考手册</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../reference.html">参考手册</a></li>
<li class="toctree-l1"><a class="reference internal" href="../reference/api.html">API 参考</a></li>
<li class="toctree-l1"><a class="reference internal" href="../reference/extensions.html">扩展</a></li>
<li class="toctree-l1"><a class="reference internal" href="../reference/history.html">版本历史</a></li>
</ul>
</div>
</header>
<main>
<div class="row">
<div class="col s12 m9 body">
<div id="main-content" role="main">
<section id="gino-basics">
<h1>GINO 基础教程<a class="headerlink" href="#gino-basics" title="永久链接至标题">¶</a></h1>
<p>这是一篇写给刚入坑同学的指南,将介绍 GINO 的基本部分。阅读之前,请先了解以下知识点:</p>
<ul class="simple">
<li><p>关系型数据库,尤其是 <a class="reference external" href="https://www.postgresql.org/">PostgreSQL</a></p></li>
<li><p><a class="reference external" href="https://realpython.com/async-io-python/">Python 异步编程</a></p></li>
</ul>
<p>您不需要对 <a class="reference external" href="https://www.sqlalchemy.org/">SQLAlchemy</a> 有所了解。</p>
<section id="introduction">
<h2>介绍<a class="headerlink" href="#introduction" title="永久链接至标题">¶</a></h2>
<p>简单来说,GINO 可以在您的异步应用中帮助您完成 SQL 语句的生成及执行,您只需要通过友好的对象化 API 来操作您的数据即可,无需亲自编写 SQL 与数据库交互。</p>
<p>因为异步编程并不会使您的程序变快——如果说不拖累的话——而且还会增加复杂度和风险,所以也许您并不需要 GINO 或者说是异步数据库连接。跳坑之前请先阅读<a class="reference internal" href="../explanation/why.html"><span class="doc">为什么要用异步 ORM?</span></a>。</p>
</section>
<section id="installation">
<h2>安装<a class="headerlink" href="#installation" title="永久链接至标题">¶</a></h2>
<p>请在终端中执行以下命令以安装 GINO:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>pip install gino
</pre></div>
</div>
<p>以上就是安装 GINO 的推荐方式,因为这种方式始终会去安装最新的稳定版。</p>
<p>如果您还没有安装过 <a class="reference external" href="https://pip.pypa.io">pip</a>,您可以参阅 <a class="reference external" href="http://docs.python-guide.org/en/latest/starting/installation/">Python 安装指南</a>。</p>
<p>另外如果您在使用 <a class="reference external" href="https://python-poetry.org">Poetry</a> 进行项目依赖关系管理,那需要执行的则是:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>poetry add gino
</pre></div>
</div>
</section>
<section id="declare-models">
<h2>声明模型<a class="headerlink" href="#declare-models" title="永久链接至标题">¶</a></h2>
<p>开始之前,我们需要先创建一个 <a class="reference internal" href="../reference/api/gino.api.html#gino.api.Gino" title="gino.api.Gino"><code class="xref py py-class docutils literal notranslate"><span class="pre">Gino</span></code></a> 的全局实例,通常叫做 <code class="docutils literal notranslate"><span class="pre">db</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">gino</span> <span class="kn">import</span> <span class="n">Gino</span>
<span class="n">db</span> <span class="o">=</span> <span class="n">Gino</span><span class="p">()</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">db</span></code> 可以被当做是数据库的一个代表,后续大部分的数据库交互都将通过它来完成。</p>
<p>“Model” 是 GINO 中的一个基本概念,它表示继承自 <a class="reference internal" href="../reference/api/gino.api.html#gino.api.Gino.Model" title="gino.api.Gino.Model"><code class="xref py py-attr docutils literal notranslate"><span class="pre">db.Model</span></code></a> 的用户定义类。每个 <a class="reference internal" href="../reference/api/gino.declarative.html#gino.declarative.Model" title="gino.declarative.Model"><code class="xref py py-class docutils literal notranslate"><span class="pre">Model</span></code></a> 的子类代表了数据库中的一张表,而这些类的对象则代表了对应表中的一行数据。如果您曾经使用过其它 ORM 产品,对这种映射关系应该不感到陌生。现在我们尝试定义一个 model:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">User</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'users'</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Integer</span><span class="p">(),</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">nickname</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Unicode</span><span class="p">(),</span> <span class="n">default</span><span class="o">=</span><span class="s1">'noname'</span><span class="p">)</span>
</pre></div>
</div>
<p>这里的 <code class="docutils literal notranslate"><span class="pre">User</span></code> 类其实就是在定义一张叫做 <code class="docutils literal notranslate"><span class="pre">users</span></code> 的数据库表,包含了 <code class="docutils literal notranslate"><span class="pre">id</span></code> 和 <code class="docutils literal notranslate"><span class="pre">nickname</span></code> 两个字段。请注意,<code class="xref py py-attr docutils literal notranslate"><span class="pre">__tablename__</span></code> 是一个必要的固定属性。GINO 建议使用单数名词来为 model 命名,同时使用复数名词去命名表。每个 <a class="reference external" href="https://docs.sqlalchemy.org/en/14/core/metadata.html#sqlalchemy.schema.Column" title="(在 SQLAlchemy v1.4)"><code class="xref py py-class docutils literal notranslate"><span class="pre">db.Column</span></code></a> 属性都定义了一个数据库字段,其中第一个参数是字段类型,其余参数则用来定义字段其他属性或约束。您可以参考 <a class="reference external" href="http://docs.sqlalchemy.org/en/latest/core/type_basics.html">SQLAlchemy</a> 的文档来了解不同 <code class="docutils literal notranslate"><span class="pre">db</span></code> 类型到数据库类型的对应关系。</p>
<div class="admonition note">
<p class="admonition-title">注解</p>
<p><a class="reference external" href="https://www.sqlalchemy.org/">SQLAlchemy</a> 是 Python 中一个强大的非异步 ORM 库,而 GINO 就是基于其构建的。通过不同的 SQL 方言实现,SQLAlchemy 支持包括 PostgreSQL 和 MySQL 在内的许多流行的 RDBMS,以至于有时相同的 Python 代码可以不经修改地运行在不同的数据库上。GINO 自然也承袭了这一特性,但目前暂仅支持 PostgreSQL(通过 <a class="reference external" href="https://github.com/MagicStack/asyncpg">asyncpg</a>)。</p>
</div>
<p>如果需要定义涵盖多个列的数据库约束或索引,您仍然可以通过 model 类属性的方式来定义,属性名称虽未被用到,但不能重复。例如:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Booking</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'bookings'</span>
<span class="n">day</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Date</span><span class="p">)</span>
<span class="n">booker</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">String</span><span class="p">)</span>
<span class="n">room</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">String</span><span class="p">)</span>
<span class="n">_pk</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">PrimaryKeyConstraint</span><span class="p">(</span><span class="s1">'day'</span><span class="p">,</span> <span class="s1">'booker'</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">'bookings_pkey'</span><span class="p">)</span>
<span class="n">_idx1</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Index</span><span class="p">(</span><span class="s1">'bookings_idx_day_room'</span><span class="p">,</span> <span class="s1">'day'</span><span class="p">,</span> <span class="s1">'room'</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">_idx2</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Index</span><span class="p">(</span><span class="s1">'bookings_idx_booker_room'</span><span class="p">,</span> <span class="s1">'booker'</span><span class="p">,</span> <span class="s1">'room'</span><span class="p">)</span>
</pre></div>
</div>
<p>另外如果有倾向性,您也可以在 model 类之外定义约束和索引,请参考 <a class="reference external" href="http://docs.sqlalchemy.org/en/latest/core/constraints.html">SQLAlchemy 文档</a>来了解更多细节。</p>
<p>由于一些限制,目前不允许在父类中直接使用类属性的方式来单独定义数据库约束和索引,<code class="xref py py-attr docutils literal notranslate"><span class="pre">__table_args__</span></code> 也是一样的。GINO 提供了 <a class="reference internal" href="../reference/api/gino.declarative.html#gino.declarative.declared_attr" title="gino.declarative.declared_attr"><code class="xref py py-func docutils literal notranslate"><span class="pre">declared_attr()</span></code></a> 来实现比如 mixin 类这样的功能,更多信息请参阅其 API 文档。</p>
</section>
<section id="get-connected">
<h2>建立连接<a class="headerlink" href="#get-connected" title="永久链接至标题">¶</a></h2>
<p>前面的声明只是定义了映射关系,并非实际在数据库中创建了这些表结构。为了使用 GINO 来创建表,我们需要先与数据库建立连接。这里我们先为本指南创建一个 PostgreSQL 的数据库实例:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>createdb gino
</pre></div>
</div>
<p>然后,告诉我们的 <code class="docutils literal notranslate"><span class="pre">db</span></code> 对象去连接这个数据库:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">asyncio</span>
<span class="k">async</span> <span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="k">await</span> <span class="n">db</span><span class="o">.</span><span class="n">set_bind</span><span class="p">(</span><span class="s1">'postgresql://localhost/gino'</span><span class="p">)</span>
<span class="n">asyncio</span><span class="o">.</span><span class="n">get_event_loop</span><span class="p">()</span><span class="o">.</span><span class="n">run_until_complete</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
</pre></div>
</div>
<p>如果执行成功了,那就意味着您连上了新创建的数据库。此处的 <code class="docutils literal notranslate"><span class="pre">postgresql</span></code> 代表了要用的数据库方言(默认的驱动是 <code class="docutils literal notranslate"><span class="pre">asyncpg</span></code>,您也可以显式地指定使用它:<code class="docutils literal notranslate"><span class="pre">postgresql+asyncpg://</span></code> 或者就只写 <code class="docutils literal notranslate"><span class="pre">asyncpg://</span></code>),<code class="docutils literal notranslate"><span class="pre">localhost</span></code> 是数据库服务器所在的地址,<code class="docutils literal notranslate"><span class="pre">gino</span></code> 是数据库实例的名字。<a class="reference external" href="https://docs.sqlalchemy.org/en/latest/core/engines.html">这里</a>可以读到更多关于如何构造一个数据库 URL 的信息。</p>
<div class="admonition note">
<p class="admonition-title">注解</p>
<p>在底层,<a class="reference internal" href="../reference/api/gino.api.html#gino.api.Gino.set_bind" title="gino.api.Gino.set_bind"><code class="xref py py-meth docutils literal notranslate"><span class="pre">set_bind()</span></code></a> 调用了 <a class="reference internal" href="../reference/api/gino.html#gino.create_engine" title="gino.create_engine"><code class="xref py py-func docutils literal notranslate"><span class="pre">create_engine()</span></code></a> 来创建 engine,并将其绑定到 <code class="docutils literal notranslate"><span class="pre">db</span></code> 对象上。GINO engine 与 SQLAlchemy engine 类似,但 GINO engine 是异步的,而后者是阻塞式的。关于如何使用 engine,请参考 GINO 的 API 文档。</p>
</div>
<p>建立连接之后,我们就可以用 GINO 在数据库中创建我们的表了(在同一个 <code class="docutils literal notranslate"><span class="pre">main()</span></code> 函数里):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">await</span> <span class="n">db</span><span class="o">.</span><span class="n">gino</span><span class="o">.</span><span class="n">create_all</span><span class="p">()</span>
</pre></div>
</div>
<div class="admonition warning">
<p class="admonition-title">警告</p>
<p>这里是 <a class="reference internal" href="../reference/api/gino.schema.html#gino.schema.GinoSchemaVisitor.create_all" title="gino.schema.GinoSchemaVisitor.create_all"><code class="xref py py-meth docutils literal notranslate"><span class="pre">db.gino.create_all</span></code></a>,而不是 <a class="reference external" href="https://docs.sqlalchemy.org/en/14/core/metadata.html#sqlalchemy.schema.MetaData.create_all" title="(在 SQLAlchemy v1.4)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">db.create_all</span></code></a>,因为 <code class="docutils literal notranslate"><span class="pre">db</span></code> 继承自 SQLAlchemy 的 <a class="reference external" href="https://docs.sqlalchemy.org/en/14/core/metadata.html#sqlalchemy.schema.MetaData" title="(在 SQLAlchemy v1.4)"><code class="xref py py-class docutils literal notranslate"><span class="pre">MetaData</span></code></a>,而 <a class="reference external" href="https://docs.sqlalchemy.org/en/14/core/metadata.html#sqlalchemy.schema.MetaData.create_all" title="(在 SQLAlchemy v1.4)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">db.create_all</span></code></a> 是 SQLAlchemy 的阻塞式方法,无法适用于绑定的 GINO engine。</p>
<p>实践中 <a class="reference internal" href="../reference/api/gino.schema.html#gino.schema.GinoSchemaVisitor.create_all" title="gino.schema.GinoSchemaVisitor.create_all"><code class="xref py py-meth docutils literal notranslate"><span class="pre">create_all()</span></code></a> 通常并不是一个理想的解决方案。为了管理数据库表结构,我们通常推荐使用诸如 <a class="reference external" href="https://bitbucket.org/zzzeek/alembic">Alembic</a> 这样的工具,请参阅如何 <a class="reference internal" href="../how-to/alembic.html"><span class="doc">使用 Alembic</span></a>。</p>
</div>
<p>如果您想显式地断开与数据库的连接,您可以这么做:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">await</span> <span class="n">db</span><span class="o">.</span><span class="n">pop_bind</span><span class="p">()</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</pre></div>
</div>
<p>继续之前,让我们重新看一下前面所有的代码:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">asyncio</span>
<span class="kn">from</span> <span class="nn">gino</span> <span class="kn">import</span> <span class="n">Gino</span>
<span class="n">db</span> <span class="o">=</span> <span class="n">Gino</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">User</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'users'</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Integer</span><span class="p">(),</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">nickname</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Unicode</span><span class="p">(),</span> <span class="n">default</span><span class="o">=</span><span class="s1">'noname'</span><span class="p">)</span>
<span class="k">async</span> <span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="k">await</span> <span class="n">db</span><span class="o">.</span><span class="n">set_bind</span><span class="p">(</span><span class="s1">'postgresql://localhost/gino'</span><span class="p">)</span>
<span class="k">await</span> <span class="n">db</span><span class="o">.</span><span class="n">gino</span><span class="o">.</span><span class="n">create_all</span><span class="p">()</span>
<span class="c1"># further code goes here</span>
<span class="k">await</span> <span class="n">db</span><span class="o">.</span><span class="n">pop_bind</span><span class="p">()</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">asyncio</span><span class="o">.</span><span class="n">get_event_loop</span><span class="p">()</span><span class="o">.</span><span class="n">run_until_complete</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
</pre></div>
</div>
</section>
<section id="crud-operations">
<h2>增删改查<a class="headerlink" href="#crud-operations" title="永久链接至标题">¶</a></h2>
<p>为了操作数据库中的数据,GINO 提供了基本的基于对象的增删改查功能。</p>
<section id="create">
<h3>增<a class="headerlink" href="#create" title="永久链接至标题">¶</a></h3>
<p>让我们从创建一个 <code class="docutils literal notranslate"><span class="pre">User</span></code> 对象开始:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">user</span> <span class="o">=</span> <span class="k">await</span> <span class="n">User</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">nickname</span><span class="o">=</span><span class="s1">'fantix'</span><span class="p">)</span>
<span class="c1"># This will cause GINO to execute this SQL with parameter 'fantix':</span>
<span class="c1"># INSERT INTO users (nickname) VALUES ($1) RETURNING users.id, users.nickname</span>
</pre></div>
</div>
<p>正如之前所说,<code class="docutils literal notranslate"><span class="pre">user</span></code> 对象代表了数据库中新插入的这一行数据。您可以通过 <code class="docutils literal notranslate"><span class="pre">user</span></code> 对象上的之前定义的列属性来访问每一列的值:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s1">'ID: </span><span class="si">{</span><span class="n">user</span><span class="o">.</span><span class="n">id</span><span class="si">}</span><span class="s1">'</span><span class="p">)</span> <span class="c1"># 1</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s1">'Nickname: </span><span class="si">{</span><span class="n">user</span><span class="o">.</span><span class="n">nickname</span><span class="si">}</span><span class="s1">'</span><span class="p">)</span> <span class="c1"># fantix</span>
</pre></div>
</div>
<p>另外,您也可以先在内存中创建一个 <code class="docutils literal notranslate"><span class="pre">user</span></code> 对象,然后再将其插入到数据库中:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="p">(</span><span class="n">nickname</span><span class="o">=</span><span class="s1">'fantix'</span><span class="p">)</span>
<span class="n">user</span><span class="o">.</span><span class="n">nickname</span> <span class="o">+=</span> <span class="s1">' (founder)'</span>
<span class="k">await</span> <span class="n">user</span><span class="o">.</span><span class="n">create</span><span class="p">()</span>
</pre></div>
</div>
</section>
<section id="retrieve">
<h3>查<a class="headerlink" href="#retrieve" title="永久链接至标题">¶</a></h3>
<p>想要通过主键来获取一个 model 对象,您可以使用 model 的类方法 <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.CRUDModel.get" title="gino.crud.CRUDModel.get"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get()</span></code></a>。比如,重新获取刚才插入的同一行数据:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">user</span> <span class="o">=</span> <span class="k">await</span> <span class="n">User</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="c1"># SQL (parameter: 1):</span>
<span class="c1"># SELECT users.id, users.nickname FROM users WHERE users.id = $1</span>
</pre></div>
</div>
<p>常规的 SQL 查询则是通过类属性 <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.CRUDModel.query" title="gino.crud.CRUDModel.query"><code class="xref py py-attr docutils literal notranslate"><span class="pre">query</span></code></a> 来完成。比如,获取数据库中所有的 <code class="docutils literal notranslate"><span class="pre">User</span></code> 对象的列表:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">all_users</span> <span class="o">=</span> <span class="k">await</span> <span class="n">db</span><span class="o">.</span><span class="n">all</span><span class="p">(</span><span class="n">User</span><span class="o">.</span><span class="n">query</span><span class="p">)</span>
<span class="c1"># SQL:</span>
<span class="c1"># SELECT users.id, users.nickname FROM users</span>
</pre></div>
</div>
<p>或者,您也可以使用 <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.CRUDModel.query" title="gino.crud.CRUDModel.query"><code class="xref py py-attr docutils literal notranslate"><span class="pre">query</span></code></a> 的 <code class="docutils literal notranslate"><span class="pre">gino</span></code> 扩展。比如,下面的代码可以实现一样的效果:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">all_users</span> <span class="o">=</span> <span class="k">await</span> <span class="n">User</span><span class="o">.</span><span class="n">query</span><span class="o">.</span><span class="n">gino</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="c1"># SQL:</span>
<span class="c1"># SELECT users.id, users.nickname FROM users</span>
</pre></div>
</div>
<div class="admonition note">
<p class="admonition-title">注解</p>
<p>实际上,<code class="docutils literal notranslate"><span class="pre">User.query</span></code> 是一个普通的 SQLAlchemy 查询对象,SQLAlchemy 的阻塞式执行方法依然存在其上,因此 GINO 向所有 SQLAlchemy 的“Executable”对象注入了一个 <code class="docutils literal notranslate"><span class="pre">gino</span></code> 扩展,以便在不影响 SQLAlchemy 原有 API 的基础上,让直接异步地执行这些查询对象更容易,而不用每次都通过 engine 或 <code class="docutils literal notranslate"><span class="pre">db</span></code> 对象来执行。</p>
</div>
<p>现在让我们尝试增加一些过滤器。比如,查找出所有 ID 小于 10 的用户:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">founding_users</span> <span class="o">=</span> <span class="k">await</span> <span class="n">User</span><span class="o">.</span><span class="n">query</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="n">User</span><span class="o">.</span><span class="n">id</span> <span class="o"><</span> <span class="mi">10</span><span class="p">)</span><span class="o">.</span><span class="n">gino</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="c1"># SQL (parameter: 10):</span>
<span class="c1"># SELECT users.id, users.nickname FROM users WHERE users.id < $1</span>
</pre></div>
</div>
<p>因为查询对象就是出自于 SQLAlchemy core,所以请参阅<a class="reference external" href="https://docs.sqlalchemy.org/en/latest/core/expression_api.html">如何编写查询</a>。</p>
<div class="admonition warning">
<p class="admonition-title">警告</p>
<p>当您拿到一个 model 对象时,这个对象就已经彻底与数据库分离了,完全成为内存中的一个普通对象。这就意味着,即使数据库中对应的行发生了变化,对象的值仍然不会受到丝毫影响。类似地,如果您修改了该对象的值,数据库也不会受到任何影响。</p>
<p>并且,GINO 也不会追踪 model 对象,因此重复查询同一行数据将会得到两个独立的、拥有相同值的对象,修改其中一个的值不会幽灵般地影响到另一个的值。</p>
<p>不同于传统 ORM 的 model 对象通常是有状态的,GINO 的 model 对象则更像是用对象封装的 SQL 查询结果,这是 GINO 为了适应异步编程而特意设计的简易性,也是“GINO 不是 ORM”名字的来源。</p>
</div>
<p>有时我们仅需要获取一个对象,比如验证登录时,使用用户名来查找一个用户。这时,可以使用这种便捷的写法:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">user</span> <span class="o">=</span> <span class="k">await</span> <span class="n">User</span><span class="o">.</span><span class="n">query</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="n">User</span><span class="o">.</span><span class="n">nickname</span> <span class="o">==</span> <span class="s1">'fantix'</span><span class="p">)</span><span class="o">.</span><span class="n">gino</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
<span class="c1"># SQL (parameter: 'fantix'):</span>
<span class="c1"># SELECT users.id, users.nickname FROM users WHERE users.nickname = $1</span>
</pre></div>
</div>
<p>如果数据库中没有叫“fantix”的用户,则 <code class="docutils literal notranslate"><span class="pre">user</span></code> 会被置为 <code class="docutils literal notranslate"><span class="pre">None</span></code>。</p>
<p>又有时,我们会需要获取一个单独的值,比如 ID 为 1 的用户的名字。此时可以使用 model 的类方法 <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.CRUDModel.select" title="gino.crud.CRUDModel.select"><code class="xref py py-meth docutils literal notranslate"><span class="pre">select()</span></code></a>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">name</span> <span class="o">=</span> <span class="k">await</span> <span class="n">User</span><span class="o">.</span><span class="n">select</span><span class="p">(</span><span class="s1">'nickname'</span><span class="p">)</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="n">User</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">gino</span><span class="o">.</span><span class="n">scalar</span><span class="p">()</span>
<span class="c1"># SQL (parameter: 1):</span>
<span class="c1"># SELECT users.nickname FROM users WHERE users.id = $1</span>
<span class="nb">print</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="c1"># fantix</span>
</pre></div>
</div>
<p>又比如,查询用户数量:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">population</span> <span class="o">=</span> <span class="k">await</span> <span class="n">db</span><span class="o">.</span><span class="n">func</span><span class="o">.</span><span class="n">count</span><span class="p">(</span><span class="n">User</span><span class="o">.</span><span class="n">id</span><span class="p">)</span><span class="o">.</span><span class="n">gino</span><span class="o">.</span><span class="n">scalar</span><span class="p">()</span>
<span class="c1"># SQL:</span>
<span class="c1"># SELECT count(users.id) AS count_1 FROM users</span>
<span class="nb">print</span><span class="p">(</span><span class="n">population</span><span class="p">)</span> <span class="c1"># 17 for example</span>
</pre></div>
</div>
</section>
<section id="update">
<h3>改<a class="headerlink" href="#update" title="永久链接至标题">¶</a></h3>
<p>接下来,让我们尝试对数据做一些修改,下面的例子会穿插一些前面用过的查询操作。</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># create a new user</span>
<span class="n">user</span> <span class="o">=</span> <span class="k">await</span> <span class="n">User</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">nickname</span><span class="o">=</span><span class="s1">'fantix'</span><span class="p">)</span>
<span class="c1"># get its name</span>
<span class="n">name</span> <span class="o">=</span> <span class="k">await</span> <span class="n">User</span><span class="o">.</span><span class="n">select</span><span class="p">(</span><span class="s1">'nickname'</span><span class="p">)</span><span class="o">.</span><span class="n">where</span><span class="p">(</span>
<span class="n">User</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="n">user</span><span class="o">.</span><span class="n">id</span><span class="p">)</span><span class="o">.</span><span class="n">gino</span><span class="o">.</span><span class="n">scalar</span><span class="p">()</span>
<span class="k">assert</span> <span class="n">name</span> <span class="o">==</span> <span class="n">user</span><span class="o">.</span><span class="n">nickname</span> <span class="c1"># they are both 'fantix' before the update</span>
<span class="c1"># modification here</span>
<span class="k">await</span> <span class="n">user</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">nickname</span><span class="o">=</span><span class="s1">'daisy'</span><span class="p">)</span><span class="o">.</span><span class="n">apply</span><span class="p">()</span>
<span class="c1"># SQL (parameters: 'daisy', 1):</span>
<span class="c1"># UPDATE users SET nickname=$1 WHERE users.id = $2 RETURNING users.nickname</span>
<span class="nb">print</span><span class="p">(</span><span class="n">user</span><span class="o">.</span><span class="n">nickname</span><span class="p">)</span> <span class="c1"># daisy</span>
<span class="c1"># get its name again</span>
<span class="n">name</span> <span class="o">=</span> <span class="k">await</span> <span class="n">User</span><span class="o">.</span><span class="n">select</span><span class="p">(</span><span class="s1">'nickname'</span><span class="p">)</span><span class="o">.</span><span class="n">where</span><span class="p">(</span>
<span class="n">User</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="n">user</span><span class="o">.</span><span class="n">id</span><span class="p">)</span><span class="o">.</span><span class="n">gino</span><span class="o">.</span><span class="n">scalar</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="c1"># daisy</span>
<span class="k">assert</span> <span class="n">name</span> <span class="o">==</span> <span class="n">user</span><span class="o">.</span><span class="n">nickname</span> <span class="c1"># they are both 'daisy' after the update</span>
</pre></div>
</div>
<p>这里的 <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.CRUDModel.update" title="gino.crud.CRUDModel.update"><code class="xref py py-meth docutils literal notranslate"><span class="pre">update()</span></code></a> 是我们碰到的第一个 model 实例上的 GINO 方法,它接受多个自定义命名参数,参数名对应着 model 的字段名,而参数值则为期望修改成的新的值。连着写的 <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.UpdateRequest.apply" title="gino.crud.UpdateRequest.apply"><code class="xref py py-meth docutils literal notranslate"><span class="pre">apply()</span></code></a> 则会将这一修改同步到数据库中。</p>
<div class="admonition note">
<p class="admonition-title">注解</p>
<p>GINO 显式地将“修改内存中对象的值”与“修改数据库中的行”拆分成了两个方法: <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.CRUDModel.update" title="gino.crud.CRUDModel.update"><code class="xref py py-meth docutils literal notranslate"><span class="pre">update()</span></code></a> 与 <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.UpdateRequest.apply" title="gino.crud.UpdateRequest.apply"><code class="xref py py-meth docutils literal notranslate"><span class="pre">apply()</span></code></a>。<a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.CRUDModel.update" title="gino.crud.CRUDModel.update"><code class="xref py py-meth docutils literal notranslate"><span class="pre">update()</span></code></a> 负责修改内存中的值,并且将改动记录在返回的 <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.UpdateRequest" title="gino.crud.UpdateRequest"><code class="xref py py-class docutils literal notranslate"><span class="pre">UpdateRequest</span></code></a> 对象中;紧接着调用的 <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.UpdateRequest" title="gino.crud.UpdateRequest"><code class="xref py py-class docutils literal notranslate"><span class="pre">UpdateRequest</span></code></a> 对象的 <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.UpdateRequest.apply" title="gino.crud.UpdateRequest.apply"><code class="xref py py-meth docutils literal notranslate"><span class="pre">apply()</span></code></a> 方法则会将这些记录下的改动通过 SQL 更新到数据库中。</p>
</div>
<div class="admonition tip">
<p class="admonition-title">小技巧</p>
<p><a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.UpdateRequest" title="gino.crud.UpdateRequest"><code class="xref py py-class docutils literal notranslate"><span class="pre">UpdateRequest</span></code></a> 对象还有一个方法也叫 <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.UpdateRequest.update" title="gino.crud.UpdateRequest.update"><code class="xref py py-meth docutils literal notranslate"><span class="pre">update()</span></code></a>,它与 model 对象上的 <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.CRUDModel.update" title="gino.crud.CRUDModel.update"><code class="xref py py-attr docutils literal notranslate"><span class="pre">update()</span></code></a> 方法的功能是一样的,只不过前者还会将新的改动记录与当前 <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.UpdateRequest" title="gino.crud.UpdateRequest"><code class="xref py py-class docutils literal notranslate"><span class="pre">UpdateRequest</span></code></a> 已记录的改动合并在一起,并且返回同一个 <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.UpdateRequest" title="gino.crud.UpdateRequest"><code class="xref py py-class docutils literal notranslate"><span class="pre">UpdateRequest</span></code></a> 对象。这意味着,您可以连着写多个 <code class="docutils literal notranslate"><span class="pre">update()</span></code> 调用,最后用一个 <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.UpdateRequest.apply" title="gino.crud.UpdateRequest.apply"><code class="xref py py-meth docutils literal notranslate"><span class="pre">apply()</span></code></a> 结尾,或者仅仅是通过 <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.UpdateRequest" title="gino.crud.UpdateRequest"><code class="xref py py-class docutils literal notranslate"><span class="pre">UpdateRequest</span></code></a> 对象来完成内存对象的多次改动。</p>
</div>
<p>Model 对象上的 <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.CRUDModel.update" title="gino.crud.CRUDModel.update"><code class="xref py py-meth docutils literal notranslate"><span class="pre">update()</span></code></a> 方法只能操作该对象对应的数据库中的一行数据,而如果您想要批量更新多行数据的话,您可以使用 model 类上的 <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.CRUDModel.update" title="gino.crud.CRUDModel.update"><code class="xref py py-meth docutils literal notranslate"><span class="pre">update()</span></code></a> 类方法。用法略有不同:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">await</span> <span class="n">User</span><span class="o">.</span><span class="n">update</span><span class="o">.</span><span class="n">values</span><span class="p">(</span><span class="n">nickname</span><span class="o">=</span><span class="s1">'Founding Member '</span> <span class="o">+</span> <span class="n">User</span><span class="o">.</span><span class="n">nickname</span><span class="p">)</span><span class="o">.</span><span class="n">where</span><span class="p">(</span>
<span class="n">User</span><span class="o">.</span><span class="n">id</span> <span class="o"><</span> <span class="mi">10</span><span class="p">)</span><span class="o">.</span><span class="n">gino</span><span class="o">.</span><span class="n">status</span><span class="p">()</span>
<span class="c1"># SQL (parameter: 'Founding Member ', 10):</span>
<span class="c1"># UPDATE users SET nickname=($1 || users.nickname) WHERE users.id < $2</span>
<span class="n">name</span> <span class="o">=</span> <span class="k">await</span> <span class="n">User</span><span class="o">.</span><span class="n">select</span><span class="p">(</span><span class="s1">'nickname'</span><span class="p">)</span><span class="o">.</span><span class="n">where</span><span class="p">(</span>
<span class="n">User</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">gino</span><span class="o">.</span><span class="n">scalar</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="c1"># Founding Member fantix</span>
</pre></div>
</div>
<p>这里不再有 <a class="reference internal" href="../reference/api/gino.crud.html#gino.crud.UpdateRequest" title="gino.crud.UpdateRequest"><code class="xref py py-class docutils literal notranslate"><span class="pre">UpdateRequest</span></code></a> 了,所有的操作又回到了普通的 SQLAlchemy 用法,更多细节可以参考 <a class="reference external" href="https://docs.sqlalchemy.org/en/latest/core/dml.html">SQLAlchemy 的文档</a>。</p>
</section>
<section id="delete">
<h3>删<a class="headerlink" href="#delete" title="永久链接至标题">¶</a></h3>
<p>最后,删除一行数据与更新一行数据有些类似,但要简单很多:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">user</span> <span class="o">=</span> <span class="k">await</span> <span class="n">User</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">nickname</span><span class="o">=</span><span class="s1">'fantix'</span><span class="p">)</span>
<span class="k">await</span> <span class="n">user</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
<span class="c1"># SQL (parameter: 1):</span>
<span class="c1"># DELETE FROM users WHERE users.id = $1</span>
<span class="nb">print</span><span class="p">(</span><span class="k">await</span> <span class="n">User</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">user</span><span class="o">.</span><span class="n">id</span><span class="p">))</span> <span class="c1"># None</span>
</pre></div>
</div>
<div class="admonition hint">
<p class="admonition-title">提示</p>
<p>还记得内存对象的事情吗?在最后一行的 <a class="reference external" href="https://docs.python.org/3/library/functions.html#print" title="(在 Python v3.10)"><code class="xref py py-func docutils literal notranslate"><span class="pre">print()</span></code></a> 中,尽管数据库中已经没有这一行数据了,但是 <code class="docutils literal notranslate"><span class="pre">user</span></code> 对象依然在内存中,它的值也都没有变化,所以这里仍然可以用 <code class="docutils literal notranslate"><span class="pre">user.id</span></code>。</p>
</div>
<p>或者批量删除(千万不要忘记写 <code class="docutils literal notranslate"><span class="pre">where</span></code>!是不是整个表都不想要了?):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">await</span> <span class="n">User</span><span class="o">.</span><span class="n">delete</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="n">User</span><span class="o">.</span><span class="n">id</span> <span class="o">></span> <span class="mi">10</span><span class="p">)</span><span class="o">.</span><span class="n">gino</span><span class="o">.</span><span class="n">status</span><span class="p">()</span>
<span class="c1"># SQL (parameter: 10):</span>
<span class="c1"># DELETE FROM users WHERE users.id > $1</span>
</pre></div>
</div>
<p>有了基本的 <a class="reference internal" href="../how-to/crud.html"><span class="doc">增删改查</span></a>,您应该已经可以用 GINO 做出一些不可思议的东西来了。这篇上手指南到此结束,要了解更多请继续阅读文档的剩余部分。祝编程愉快!</p>
</section>
</section>
</section>
</div>
<p style="text-align: center; font-size: 12px;">
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">
<img
alt="知识共享许可协议"
style="border-width:0"
src="https://i.creativecommons.org/l/by-sa/4.0/80x15.png"
/>
</a>
<br/>
本作品采用<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">知识共享署名-相同方式共享 4.0 国际许可协议</a>进行许可。
</p>
</div>
<div class="col hide-on-small-only m3 right-nav">
<div class="table-of-contents fixed">
<ul>
<li><a class="reference internal" href="#">GINO 基础教程</a><ul>
<li><a class="reference internal" href="#introduction">介绍</a></li>
<li><a class="reference internal" href="#installation">安装</a></li>
<li><a class="reference internal" href="#declare-models">声明模型</a></li>
<li><a class="reference internal" href="#get-connected">建立连接</a></li>
<li><a class="reference internal" href="#crud-operations">增删改查</a><ul>
<li><a class="reference internal" href="#create">增</a></li>
<li><a class="reference internal" href="#retrieve">查</a></li>
<li><a class="reference internal" href="#update">改</a></li>
<li><a class="reference internal" href="#delete">删</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<div id="version-selector">
<hr>
<div class="version-warning">
您正在浏览 master 分支,该文档可能涉及尚未发布的功能。
</div>
</div>
<div class="add-your-lang">
<a href="https://www.transifex.com/decentfox-studio/gino_1_0/"
target="_blank">Add your language here.</a>
</div>
</div>
</div>
</div>
<div class="fixed-action-btn click-to-toggle">
<a class="btn-floating btn-large white">
<img src="../_static/images/language.svg">
<div>
ZH
</div>
</a>
<ul id="lang-selector">
</ul>
</div>
</main>
<script type="text/javascript" src="../_static/js/materialize.min.js"></script>
<script type="text/javascript" src="../_static/js/language_data.js"></script>
<script id="documentation_options" data-url_root="../" src="../_static/js/documentation_options.js"></script>
<script type="text/javascript" src="../_static/js/underscore.js"></script>
<script type="text/javascript" src="../_static/js/jquery.js"></script>
<script type="text/javascript">
var sver = 'master';
var language = 'zh';
var pagename = 'tutorials/tutorial';
</script>
<script type="text/javascript" src="../_static/js/gino.js"></script>
<script type="text/javascript" src="../searchindex.js"></script>
</body>
</html>