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
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>pattern-db</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link type="text/css" rel="stylesheet" href="../clips.css" />
<style>
/* Small fixes because we omit the online layout.css. */
h3 { line-height: 1.3em; }
#page { margin-left: auto; margin-right: auto; }
#header, #header-inner { height: 175px; }
#header { border-bottom: 1px solid #C6D4DD; }
table { border-collapse: collapse; }
#checksum { display: none; }
</style>
<link href="../js/shCore.css" rel="stylesheet" type="text/css" />
<link href="../js/shThemeDefault.css" rel="stylesheet" type="text/css" />
<script language="javascript" src="../js/shCore.js"></script>
<script language="javascript" src="../js/shBrushXml.js"></script>
<script language="javascript" src="../js/shBrushJScript.js"></script>
<script language="javascript" src="../js/shBrushPython.js"></script>
</head>
<body class="node-type-page one-sidebar sidebar-right section-pages">
<div id="page">
<div id="page-inner">
<div id="header"><div id="header-inner"></div></div>
<div id="content">
<div id="content-inner">
<div class="node node-type-page"
<div class="node-inner">
<div class="breadcrumb">View online at: <a href="http://www.clips.ua.ac.be/pages/pattern-db" class="noexternal" target="_blank">http://www.clips.ua.ac.be/pages/pattern-db</a></div>
<h1>pattern.db</h1>
<!-- Parsed from the online documentation. -->
<div id="node-1432" class="node node-type-page"><div class="node-inner">
<div class="content">
<p class="big">The pattern.db module contains wrappers for databases (SQLite, MySQL), Unicode CSV files and Python's datetime. It offers a convenient way to work with tabular data, for example retrieved with the pattern.web module.</p>
<p>It can be used by itself or with other <a href="pattern.html">pattern</a> modules: <a href="pattern-web.html">web</a> | db | <a href="pattern-en.html">en</a> | <a href="pattern-search.html">search</a> <span class="blue"></span> | <a href="pattern-vector.html">vector</a> | <a href="pattern-graph.html">graph</a>.</p>
<p><img src="../g/pattern_schema.gif" alt="" width="620" height="180" /></p>
<hr />
<h2>Documentation</h2>
<ul style="margin-top: 0;">
<li><a href="#database">Database</a> <span class="smallcaps link-maintenance">(sqlite + mysql)</span></li>
<li><a href="#table">Table</a></li>
<li><a href="#query">Query</a></li>
<li><a href="#datasheet">Datasheet</a> <span class="smallcaps link-maintenance">(<a href="#csv">csv</a>)</span></li>
<li><a href="#date">Date</a></li>
</ul>
<p> </p>
<hr />
<h2><a name="database"></a>Database</h2>
<p>A database is a collection of tables. A table has rows of data with a specific data type (e.g., string, float) for each field or column. A database engine provides an interface to the database, using <a href="https://en.wikipedia.org/wiki/SQL" target="_blank">SQL</a> statements (Structured Query Language). Python 2.5+ comes bundled with the SQLite engine. The <a href="http://www.mysql.com/" target="_blank">MySQL</a> engine requires the <a href="http://sourceforge.net/projects/mysql-python/" target="_blank">MySQL-Python</a> bindings. Note that a 32-bit Python requires a 32-bit MySQL.</p>
<p>The <span class="inline_code">Database()</span> constructor creates (if necessary) and returns an <span class="inline_code">SQLITE</span> or <span class="inline_code">MYSQL</span> database. With <span class="inline_code">SQLITE</span>, it will create a file with the given name in the current folder.</p>
<pre class="brush:python; gutter:false; light:true;">db = Database(
name,
host = 'localhost',
port = 3306,
username = 'root',
password = '',
type = SQLITE
)
</pre><pre class="brush:python; gutter:false; light:true;">db.type # SQLITE | MYSQL
db.name # Database name.
db.host # Database host (MySQL).
db.port # Database port (MySQL).
db.username # Database username (MySQL).
db.password # Database password (MySQL).
db.tables # Dictionary of (name, Table)-items.
db.relations # List of relations, see Database.link().
db.query # Last executed SQL query.
db.connected # True after Database.connect(). </pre><pre class="brush:python; gutter:false; light:true;">db.connect() # Happens automatically.
db.disconnect()</pre><pre class="brush:python; gutter:false; light:true;">db.create(table, fields=[])
db.remove(table)
db.link(table1, field1, table2, field2, join=LEFT) </pre><pre class="brush:python; gutter:false; light:true;">db.execute(SQL, commit=False)
db.commit()
db.escape(value) # "a cat's tail" => "'a cat\'s tail'"</pre><ul>
<li><span class="inline_code">Database.execute()</span> returns an iterator of rows for the given SQL query.</li>
<li><span class="inline_code">Database.commit()</span> commits the changes of pending <span class="inline_code">INSERT</span>, <span class="inline_code">UPDATE</span>, <span class="inline_code">DELETE</span> queries.</li>
<li><span class="inline_code">Database.escape()</span> safely quotes and escapes field values.</li>
</ul>
<h3>Create table</h3>
<p><span class="inline_code">Database.create()</span> creates a new table in the database, It takes a table name and a list of row fields, where each field is defined with the <span class="inline_code">field()</span> function. Each field has a <span class="inline_code">name</span> (a-z + underscores) and a <span class="inline_code">type</span>, with an optional <span class="inline_code">default</span> value for new rows. The <span class="inline_code">pk()</span> function can be used for primary keys.</p>
<pre class="brush:python; gutter:false; light:true;">field(name, type=STRING, default=None, index=False, optional=True)</pre><pre class="brush: python;gutter: false; light: true; fontsize: 100; first-line: 1; ">pk(name='id') # field('id', INTEGER, index=PRIMARY, optional=False) </pre><table class="border">
<tbody>
<tr>
<td><span class="smallcaps">Type</span></td>
<td><span class="smallcaps">Value</span></td>
<td><span class="smallcaps">Example</span></td>
</tr>
<tr>
<td><span class="inline_code">STRING</span></td>
<td><span class="inline_code">str</span>, <span class="inline_code">unicode</span> (1-255 characters)</td>
<td><span class="inline_code">u'Schrödinger'</span></td>
</tr>
<tr>
<td><span class="inline_code">INTEGER</span></td>
<td><span class="inline_code">int</span></td>
<td><span class="inline_code">42</span></td>
</tr>
<tr>
<td><span class="inline_code">FLOAT</span></td>
<td><span class="inline_code">float</span></td>
<td><span class="inline_code">3.14159</span></td>
</tr>
<tr>
<td><span class="inline_code">TEXT</span></td>
<td><span class="inline_code">str</span>, <span class="inline_code">unicode</span></td>
<td><span class="inline_code">open('file.txt').read() </span></td>
</tr>
<tr>
<td><span class="inline_code">BLOB</span></td>
<td><span class="inline_code">str</span> (binary, e.g., PDF, PNG)</td>
<td><span class="inline_code">db.binary(open('img.jpg',</span> <span class="inline_code">'rb').read())</span></td>
</tr>
<tr>
<td><span class="inline_code">BOOLEAN</span></td>
<td><span class="inline_code">bool</span></td>
<td><span class="inline_code">True</span>, <span class="inline_code">False</span></td>
</tr>
<tr>
<td><span class="inline_code">DATE</span></td>
<td><span class="inline_code">Date</span></td>
<td><span class="inline_code">date('1999-12-31 23:59:59')</span></td>
</tr>
</tbody>
</table>
<p>A <span class="inline_code">STRING</span> field can contain up to a 100 characters. The length (1-255) can be changed by calling <span class="inline_code">STRING</span> as a function, e.g., <span class="inline_code">type=STRING(255)</span>. For longer strings, use <span class="inline_code">TEXT</span>. The default value for a <span class="inline_code">DATE</span> field is <span class="inline_code">NOW</span>.</p>
<p>With <span class="inline_code">index=True</span>, the field is indexed for faster search. The index can also be set to <span class="inline_code">UNIQUE</span> (no duplicates) or <span class="inline_code">PRIMARY</span>. A table must have a primary key field that uniquely identifies each row (i.e., an id). Integer primary keys are auto-numbered, there is no need to set the value manually in new rows.</p>
<p>With <span class="inline_code">optional=True</span>, the field is allowed to contain <span class="inline_code">None</span>.</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> from pattern.db import Database, field, pk, STRING, BOOLEAN, DATE, NOW
>>>
>>> db = Database('my_stuff')
>>> db.create('pets', fields=(
>>> pk(),
>>> field('name', STRING(80), index=True),
>>> field('type', STRING(20)),
>>> field('tail', BOOLEAN),
>>> field('date_birth', DATE, default=None),
>>> field('date_created', DATE, default=NOW)
>>> ))</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> db.pets.append(name=u'Schrödinger', type='cat', tail=True)
>>> print db.pets.rows()[0]
(1, u'Schrödinger', u'cat', True, None, Date('2013-12-11 10:09:08'))</pre></div>
<h3>Create table from XML</h3>
<p><span class="inline_code">Database.create()</span> can also take a <span class="inline_code">Table.xml</span> or <span class="inline_code">Query.xml</span>. It creates a new table and copies the row data in the given XML string. An optional <span class="inline_code">name</span> parameter can be used to rename the new table. In <span class="inline_code">Query.xml</span>, a field name may contain a period. It will be replaced with an underscore (e.g., pets.name → pets_name). Alternatively, an alias can be defined in the <span class="inline_code">Query.aliases</span> dictionary.</p>
<p> </p>
<hr />
<h2><a name="table"></a>Table</h2>
<p>A <span class="inline_code">Table</span> is a list of rows, with one or more fields (i.e., table columns) of a certain type (i.e., string or number). A new table can be created with <span class="inline_code">Database.create()</span>. A <span class="inline_code">TableError</span> is raised if a table with the given name exists. An existing table can be retrieved with <span class="inline_code">Database.tables[name]</span>, <span class="inline_code">Database[name]</span> or <span class="inline_code">Database.<name></span>.</p>
<pre class="brush:python; gutter:false; light:true;">table = Database.tables[name]</pre><pre class="brush:python; gutter:false; light:true;">table.db # Parent Database.
table.name # Table name (a-z + underscores).
table.fields # List of field names (i.e., columns).
table.schema # Dictionary of (field, Schema)-items.
table.default # Dictionary of (field, value)-items for new rows.
table.pk # Primary key field name.</pre><pre class="brush:python; gutter:false; light:true;">table.count() # Total number of rows (len(table) also works).
table.rows() # List of rows, each a tuple of fields.
</pre><pre class="brush:python; gutter:false; light:true;">table.record(row) # Dictionary of (field, value)-items for given row.</pre><pre class="brush:python; gutter:false; light:true;">table.append(fields={}, commit=True)
table.update(id, fields={}, commit=True)
table.remove(id, commit=True)
</pre><pre class="brush:python; gutter:false; light:true;">table.filter(*args, **kwargs)
table.search(*args, **kwargs) </pre><pre class="brush:python; gutter:false; light:true;">table.xml # XML string with the table schema and rows.
table.datasheet # Datasheet object (see below).</pre><ul>
<li><span class="inline_code">Table.rows()</span> returns a list of all rows. To iterate rows memory-efficiently, use <span class="inline_code">iter(</span><span class="inline_code">Table)</span>.</li>
<li><span class="inline_code">Table.append()</span>, <span class="inline_code">update()</span> and <span class="inline_code">remove()</span> modify the table contents.<br />With <span class="inline_code">commit=False</span>, changes are only committed after <span class="inline_code">Database.commit()</span> (= faster in batch).</li>
<li><span class="inline_code">Table.filter()</span> returns a subset of rows with a subset of fields.<br />For example: <span class="inline_code">table.filter('name',</span> <span class="inline_code">type='cat')</span>.</li>
</ul>
<h3>Table schema</h3>
<p>The <span class="inline_code">Table.schema</span> dictionary contains field name → <span class="inline_code">Schema</span> items.</p>
<pre class="brush:python; gutter:false; light:true;">schema = Table.schema[fieldname]</pre><pre class="brush:python; gutter:false; light:true;">schema.name # Field name.
schema.type # STRING, INTEGER, FLOAT, TEXT, BLOB, BOOLEAN, DATE
schema.length # STRING field length.
schema.default # Default value.
schema.index # PRIMARY | UNIQUE | True | False
schema.optional # True or False. </pre><div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> from pattern.db import Database
>>>
>>> db = Database('my_stuff')
>>>
>>> print db.pets.fields
>>> print db.pets.schema['name'].type
>>> print db.pets.schema['name'].length
['id', 'name', 'tail', 'date_birth', 'date_created']
STRING
80 </pre></div>
<h3>Append row</h3>
<p><span class="inline_code">Table.append()</span> adds a new row with the given field values. It returns the row id, if the table has a primary key generated with <span class="inline_code">pk()</span>. Field values can be given as optional parameters, a dictionary or a tuple. Field values for a <span class="inline_code">BLOB</span> field must be wrapped in <span class="inline_code">Database.binary()</span>.<span style="color: #333333; font-family: Inconsolata, 'Courier New', Courier, monospace; font-size: small;"></span></p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> db.pets.append(name=u'Schrödinger', date_birth=date('2009-08-12'))</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> db.pets.append({'name': u'Schrödinger', 'date_birth': date('2009-08-12')}) </pre></div>
<div class="example">
<pre class="brush: python;gutter: false; light: true; fontsize: 100; first-line: 1; ">>>> db.pets.append((u'Schrödinger', 'cat', True, date('2009-08-12')) # in-order</pre></div>
<h3>Update row</h3>
<p><span class="inline_code">Table.update()</span> updates values in the row with the given primary key. A batch of rows can be updated using a <a class="link-maintenance" href="#filter">filter</a>, or a chain of filters with <span class="inline_code">any()</span> or <span class="inline_code">all()</span>. In the last example, all rows with <span class="inline_code">type='cat'</span> will have their <span class="inline_code">tail</span> field set to <span class="inline_code">True</span>.</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> db.pets.update(1, type='cat') # set type='cat' in row with id=1.</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> db.pets.update(1, {'type': 'cat'})</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> db.pets.update(eq('type', 'cat'), tail=True) </pre></div>
<h3>Remove row</h3>
<p><span class="inline_code">Table.remove()</span> removes the row with the given primary key:</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> db.pets.remove(1)</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> db.pets.remove(ALL)</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> db.pets.remove(all(eq('type', 'cat'), lt(year('date_birth'), 1990, '<')))</pre></div>
<p>The last example removes all rows that have <span class="inline_code">type='cat'</span> AND year of birth before 1990.</p>
<h3><span>Filter rows</span></h3>
<p><span class="inline_code">Table.filter()</span> returns a list of rows filtered by field value(s), where each row is a tuple of fields. The first parameter defines which fields to return. It can be a single field name, a list of field names or <span class="inline_code">ALL</span>. The following parameters are optional and define field constraints. They can also be given as a dictionary:</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> db.pets.filter('name') # all rows, name</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> db.pets.filter(('id', 'name')) # all rows, name + id</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> db.pets.filter(ALL, type='cat') # type='cat', all fields</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> db.pets.filter(ALL, type=('cat', 'dog')) # type='cat' OR type='dog' </pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> db.pets.filter(ALL, type='*at') # type='cat' OR 'hat' OR 'brat', ...</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> db.pets.filter(ALL, type='cat', tail=True) # type='cat' AND tail=True </pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> db.pets.filter('id', {'type': 'cat', 'tail': True})
</pre></div>
<p>More complex queries can be constructed with a <span class="inline_code">Query</span>.</p>
<p> </p>
<hr />
<h2><a name="query"></a>Query</h2>
<p><span class="inline_code">Table.search()</span> returns a new <span class="inline_code">Query</span> with options for filtering, sorting and ordering rows by field value(s). It can include fields from other, related tables.</p>
<pre class="brush:python; gutter:false; light:true;">query = Table.search(
fields = ALL,
filters = [],
relations = [],
sort = None,
order = ASCENDING,
group = None,
function = FIRST,
range = None
)</pre><pre class="brush:python; gutter:false; light:true;">query.table # Parent Table.
query.fields # Field name, list of field names, or ALL.
query.aliases # Dictionary of (field name, alias)-items.
query.filters # List of filter() objects.
query.relations # List of rel() objects.
query.sort # Field name or list of field names.
query.order # ASCENDING | DESCENDING
query.group # Field name or list of field names.
query.function # FIRST, LAST, COUNT, MIN, MAX, SUM, AVG, CONCATENATE
query.range # (start, stop)-tuple, e.g. rows 11-20.</pre><pre class="brush:python; gutter:false; light:true;">query.sql() # SQL string, can be used with Database.execute().</pre><pre class="brush:python; gutter:false; light:true;">query.rows() # List of rows, each a tuple of fields.</pre><pre class="brush:python; gutter:false; light:true;">query.record(row) # Dictionary of (field, value)-items for given row.</pre><pre class="brush:python; gutter:false; light:true;">query.xml # XML string with the query schema and rows.</pre><p>To iterate rows memory-efficiently, use <span class="inline_code">iter(Query)</span> instead of <span class="inline_code">Query.rows()</span>.</p>
<h3><a name="filter"></a>Query filter</h3>
<p>The <span class="inline_code">filter()</span> function creates a field-value constraint that matches certain rows in a table. A list of filters can be passed to the <span class="inline_code">filters</span> parameter of a <span class="inline_code">Query</span>.</p>
<pre class="brush:python; gutter:false; light:true;">filter(field, value, comparison='=')</pre><table class="border">
<tbody>
<tr>
<td style="text-align: center;"><span class="smallcaps">Comparison</span></td>
<td><span class="smallcaps">Description</span></td>
<td><span class="smallcaps">Example</span></td>
<td style="text-align: center;"><span class="smallcaps">Alias</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="inline_code">=</span></td>
<td>equal to</td>
<td><span class="inline_code">filter('type',</span> <span class="inline_code">('cat',</span> <span class="inline_code">'dog'),</span> <span class="inline_code">'=') </span></td>
<td style="text-align: left;"><span class="inline_code"> eq()</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="inline_code">i=</span></td>
<td>equal to (case-insensitive)</td>
<td><span class="inline_code">filter('name',</span> <span class="inline_code">'tig*',</span> <span class="inline_code">'i=') </span></td>
<td style="text-align: left;"><span class="inline_code"> eqi()</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="inline_code">!=</span></td>
<td>not equal to</td>
<td><span class="inline_code">filter('name',</span> <span class="inline_code">'*y',</span> <span class="inline_code">'!=')</span></td>
<td style="text-align: left;"><span class="inline_code"> ne()</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="inline_code">></span></td>
<td>greater than</td>
<td><span class="inline_code">filter('weight',</span> <span class="inline_code">10,</span> <span class="inline_code">'>') </span></td>
<td style="text-align: left;"><span class="inline_code"> gt()</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="inline_code"><</span></td>
<td>less than</td>
<td><span class="inline_code">filter('weight',</span> <span class="inline_code">10,</span> <span class="inline_code">'<') </span></td>
<td style="text-align: left;"><span class="inline_code"> lt()</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="inline_code">>=</span></td>
<td>greater than or equal to</td>
<td><span class="inline_code">filter(year('date'),</span> <span class="inline_code">1999,</span> <span class="inline_code">'>=') </span></td>
<td style="text-align: left;"><span class="inline_code"> gte()</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="inline_code"><=</span></td>
<td>less than or equal to</td>
<td><span class="inline_code">filter(year('date'),</span> <span class="inline_code">2002,</span> <span class="inline_code">'<=')</span></td>
<td style="text-align: left;"><span class="inline_code"> lte()</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="inline_code">:</span></td>
<td>between (inclusive)</td>
<td><span class="inline_code">filter(year('date'),</span> <span class="inline_code">(1999,</span> <span class="inline_code">2002),</span> <span class="inline_code">':')</span></td>
<td style="text-align: left;"><span class="inline_code"> rng()</span></td>
</tr>
</tbody>
</table>
<p>The field name of a <span class="inline_code">DATE</span> field can be passed to the <span class="inline_code">year()</span>, <span class="inline_code">month()</span>, <span class="inline_code">day()</span>, <span class="inline_code">hour()</span>, <span class="inline_code">minute()</span> or <span class="inline_code">second()</span> function.The short aliases of <span class="inline_code">filter()</span> have a preset comparison operator.</p>
<h3>Query filter chain</h3>
<p>Filters can be chained together. The <span class="inline_code">all()</span> function returns a list with AND logic. The <span class="inline_code">any()</span> function returns a list with OR logic. In the example below, the first query matches <span style="text-decoration: underline;">all</span> cats named Taxi. The second and third query match <span style="text-decoration: underline;">any</span> pet that is cat OR that is named Taxi.</p>
<pre class="brush:python; gutter:false; light:true;">all(filter1, filter2, ...) # Rows must match ALL of the filters.</pre><pre class="brush:python; gutter:false; light:true;">any(filter1, filter2, ...) # Rows must match ANY of the filters.</pre><div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> from pattern.db import Database, eq, all, any
>>>
>>> db = Database('my_stuff')
>>>
>>> db.pets.search(filters=all(eq('name', 'Taxi'), eq('type', 'cat')))
>>> db.pets.search(filters=any(eq('name', 'Taxi'), eq('type', 'cat')))
>>> db.pets.search(filters=any(name='Taxi', type='cat')) </pre></div>
<p>Lists created with <span class="inline_code">all()</span> and <span class="inline_code">any()</span> can be nested to define complex search criteria. The example below matches all pets that are cats, and whose name starts with Fluff- OR ends with a -y:</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> f = any(eq('name', 'Fluff*'), eq('name', '*y')) # OR
>>> f = all(eq('type', 'cat'), f) # AND
>>>
>>> for row in db.pets.search(filters=f):
>>> print row</pre></div>
<p>The syntax can even be more concise:</p>
<div class="example">
<pre class="brush: python;gutter: false; light: true; fontsize: 100; first-line: 1; ">>>> for row in db.pets.search(filters=all(name=('Fluff*', '*y'), type='cat')):
>>> print row </pre></div>
<h3>Query relation</h3>
<p>The <span class="inline_code">rel()</span> function defines a relation between two fields in different tables (usually id's).</p>
<pre class="brush: python;gutter: false; light: true; fontsize: 100; first-line: 1; ">rel(field1, field2, table, join=LEFT) # LEFT | INNER</pre><p>The optional <span class="inline_code">join</span> parameter defines how rows are matched. <span class="inline_code">LEFT</span> takes all rows from the base table, with additional fields from the related table. For a row with no match between <span class="inline_code">field1</span> and <span class="inline_code">field2</span>, these fields have value <span class="inline_code">None</span>. <span class="inline_code">INNER</span> takes the subset of rows that have a match between <span class="inline_code">field1</span> and <span class="inline_code">field2</span>.</p>
<p>A well-known example is a database app that processes invoices. Say we have a products table and an orders table. Each order has a product id – instead of all product details. Each product id can occur in multiple orders. This approach is called database normalization. It avoids duplicate data. To generate an invoice, we can combine product details and order details using a query relation.</p>
<p>The following example demonstrates a simple products + customers + orders database app:</p>
<table class="border=">
<tbody>
<tr>
<td>
<table class="border" style="margin: 0;">
<tbody>
<tr>
<td style="text-align: center;" colspan="3"><span class="smallcaps">products</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="smallcaps">id</span></td>
<td style="text-align: left;"><span class="smallcaps">name</span></td>
<td style="text-align: center;"><span class="smallcaps">price</span></td>
</tr>
<tr>
<td style="text-align: center;">1</td>
<td style="text-align: left;">pizza</td>
<td style="text-align: center;">15</td>
</tr>
<tr>
<td style="text-align: center;">2</td>
<td style="text-align: left;">garlic bread</td>
<td style="text-align: center;">3</td>
</tr>
</tbody>
</table>
</td>
<td>
<table class="border" style="margin: 0;">
<tbody>
<tr>
<td style="text-align: center;" colspan="3"><span class="smallcaps">customers</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="smallcaps">id</span></td>
<td style="text-align: left;"><span class="smallcaps">name</span></td>
</tr>
<tr>
<td style="text-align: center;">1</td>
<td style="text-align: left;">Schrödinger</td>
</tr>
<tr>
<td style="text-align: center;">2</td>
<td style="text-align: left;">Hofstadter</td>
</tr>
</tbody>
</table>
</td>
<td>
<table class="border" style="margin: 0;">
<tbody>
<tr>
<td style="text-align: center;" colspan="3"><span class="smallcaps">orders</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="smallcaps">id</span></td>
<td style="text-align: center;"><span class="smallcaps">product</span></td>
<td style="text-align: center;"><span class="smallcaps">customer</span></td>
</tr>
<tr>
<td style="text-align: center;">1</td>
<td style="text-align: center;">1</td>
<td style="text-align: center;">2</td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> from pattern.db import Database, field, pk, INTEGER as I
>>>
>>> db = Database('pizza_delivery')
>>>
>>> db.create( 'products', (pk(), field('name'), field('price', I)))
>>> db.create('customers', (pk(), field('name')))
>>> db.create( 'orders', (pk(), field('product', I), field('customer', I)))</pre></div>
<div class="example">Add products and customers. Pizza delivery is open for business!</div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> db.products.append(name='pizza', price=15)
>>> db.products.append(name='garlic bread', price=3)</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> db.customers.append(name=u'Schrödinger')
>>> db.customers.append(name=u'Hofstadter')</pre></div>
<p>Hofstadter orders a pizza.</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> db.orders.append(product=1, customer=2)</pre></div>
<div class="example">An orders query with relations to products and customers generates a human-readable invoice:</div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> from pattern.db import Database, rel
>>>
>>> db = Database('pizza_delivery')
>>>
>>> f = ('orders.id', 'customers.name', 'products.name', 'products.price')
>>> q = db.orders.search(f, relations=(
>>> rel('orders.customer', 'customers.id', 'customers'),
>>> rel('orders.product', 'products.id', 'products'))
>>> )
>>> for row in q:
>>> print q.record(row)
{ 'orders.id' : 1,
'customers.name' : u'Hofstadter',
'products.name' : u'pizza',
'products.price' : 15 }</pre></div>
<div class="example">If a relation is used repeatedly, define it once with <span class="inline_code">Database.link()</span>. It will be available in every <span class="inline_code">Query</span>.</div>
<h3>Grouping rows</h3>
<p>A <span class="inline_code">Query</span> has an optional parameter <span class="inline_code">group</span> that can be used to merge rows on duplicate field values. The given <span class="inline_code">function</span> is applied to the other fields. It can also be a list with a function for each field.</p>
<table class="border">
<tbody>
<tr>
<td><span class="smallcaps">Function</span></td>
<td style="text-align: center;"><span class="smallcaps">Field type</span></td>
<td><span class="smallcaps">Description</span></td>
</tr>
<tr>
<td><span class="inline_code">FIRST</span></td>
<td style="text-align: center;">any</td>
<td>The first row field in the group.</td>
</tr>
<tr>
<td><span class="inline_code">LAST</span></td>
<td style="text-align: center;">any</td>
<td>The last row field in the group.</td>
</tr>
<tr>
<td><span class="inline_code">COUNT</span></td>
<td style="text-align: center;">any</td>
<td>The number of rows in the group.</td>
</tr>
<tr>
<td><span class="inline_code">MIN</span></td>
<td style="text-align: center;"><span class="inline_code">INTEGER</span> + <span class="inline_code">FLOAT</span></td>
<td>The lowest field value in the group.</td>
</tr>
<tr>
<td><span class="inline_code">MAX</span></td>
<td style="text-align: center;"><span class="inline_code">INTEGER</span> + <span class="inline_code">FLOAT</span></td>
<td>The highest field value in the group.</td>
</tr>
<tr>
<td><span class="inline_code">SUM</span></td>
<td style="text-align: center;"><span class="inline_code">INTEGER</span> + <span class="inline_code">FLOAT</span></td>
<td>The sum of all field values in the group.</td>
</tr>
<tr>
<td><span class="inline_code">AVG</span></td>
<td style="text-align: center;"><span class="inline_code">INTEGER</span> + <span class="inline_code">FLOAT</span></td>
<td>The average of all field values in the group.</td>
</tr>
<tr>
<td><span class="inline_code">STDEV</span></td>
<td style="text-align: center;"><span class="inline_code">INTEGER</span> + <span class="inline_code">FLOAT</span></td>
<td>The standard deviation (= variation from average).</td>
</tr>
<tr>
<td><span class="inline_code">CONCATENATE</span></td>
<td style="text-align: center;"><span class="inline_code">STRING</span></td>
<td>Joins all field values with a comma.</td>
</tr>
</tbody>
</table>
<p>For example, to get the total revenue per ordered product:</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> print db.orders.search(
>>> fields = ('products.name', 'products.price'),
>>> relations = rel('product', 'products.id', 'products'),
>>> group = 'products.name', # Merge orders with same product name.
>>> function = SUM # Sum of product prices.
>>> ).rows()</pre></div>
<p> </p>
<hr />
<h2><a name="datasheet"></a>Datasheet</h2>
<p>A <span class="inline_code">Datasheet</span> is a matrix of rows and columns, where each row and column can be retrieved as a list. The data can be imported or exported as a CSV-file. Optionally, the given <span class="inline_code">fields</span> is a list of <span class="inline_code">(name,</span> <span class="inline_code">type)</span> headers, where <span class="inline_code">type</span> can be <span class="inline_code">STRING</span>, <span class="inline_code">TEXT</span>, <span class="inline_code">INTEGER</span>, <span class="inline_code">FLOAT</span>, <span class="inline_code">BOOLEAN</span>, <span class="inline_code">BLOB</span> or <span class="inline_code">DATE</span>.</p>
<pre class="brush:python; gutter:false; light:true;">datasheet = Datasheet(rows=[], fields=None)</pre><pre class="brush:python; gutter:false; light:true;">datasheet = Datasheet.load(path, separator=',', decoder=lambda v: v, headers=False)
</pre><pre class="brush:python; gutter:false; light:true;">datasheet.rows # List of rows (each row = list of values).
datasheet.columns # List of columns (each column = list of values).
datasheet.fields # List of (name, type) column headers.
datasheet.<field> # List of column values. </pre><pre class="brush:python; gutter:false; light:true;">datasheet[i] # Row at index i.
datasheet[i, j] # Value in row i at column j.
datasheet[i1:i2, j] # Slice of column j from rows i1-i2.
datasheet[i, j1:j2] # Slice of columns j1-j2 from row i.
datasheet[i1:i2, j1:j2] # Datasheet with columns j1-j2 from rows i1-i2.
datasheet[:] # Datasheet copy. </pre><pre class="brush:python; gutter:false; light:true;">datasheet.insert(i, row, default=None)
datasheet.append(row, default=None)
datasheet.extend(rows, default=None)
datasheet.copy(rows=ALL, columns=ALL)</pre><pre class="brush:python; gutter:false; light:true;">datasheet.group(j, function=FIRST, key=lambda v: v)</pre><pre class="brush:python; gutter:false; light:true;">datasheet.save(path, separator=',', encoder=lambda v: v, headers=False)</pre><pre class="brush:python; gutter:false; light:true;">datasheet.json # JSON-formatted string.</pre><ul>
<li><span class="inline_code">Datasheet.insert()</span> and <span class="inline_code">append()</span> fill missing columns with the <span class="inline_code">default</span> value.</li>
<li><span class="inline_code">Datasheet.columns.insert()</span> and <span class="inline_code">append()</span> fill missing rows with the <span class="inline_code">default</span> value.<br />An optional <span class="inline_code">field</span> parameter can be used to supply a (<span class="inline_code">name</span>, <span class="inline_code">type</span>) column header.</li>
<li><span class="inline_code">Datasheet.copy()</span> returns a new <span class="inline_code">Datasheet</span> from a selective list of row and/or column indices.</li>
<li>To rotate a datasheet 90 degrees, use <span class="inline_code">datasheet</span> <span class="inline_code">=</span> <span class="inline_code">flip(datasheet)</span>.</li>
</ul>
<p>For example:</p>
<div class="example">
<pre class="brush: python;gutter: false; light: true; fontsize: 100; first-line: 1; ">>>> from pattern.db import Datasheet
>>>
>>> ds = Datasheet()
>>> ds.append((u'Schrödinger', 'cat'))
>>> ds.append((u'Hofstadter', 'cat'))
>>> ds.save('pets.csv')
>>>
>>> ds = Datasheet.load('pets.csv')
>>> print ds
[[u'Schrödinger', 'cat'],
[ u'Hofstadter', 'cat']]</pre></div>
<h3>Grouping rows</h3>
<p><span class="inline_code">Datasheet.group(j)</span> returns a new <span class="inline_code">Datasheet</span> with unique values in column <span class="inline_code">j</span>. It merges rows using a given <span class="inline_code">function</span> that takes a list of column values and returns a single value. Predefined functions are <span class="inline_code">FIRST</span>, <span class="inline_code">LAST</span>, <span class="inline_code">COUNT</span>, <span class="inline_code">MIN</span>, <span class="inline_code">MAX</span>, <span class="inline_code">SUM</span>, <span class="inline_code">AVG</span>, <span class="inline_code">STDEV</span> and <span class="inline_code">CONCATENATE</span>. It can also be a list of functions.</p>
<p>The optional <span class="inline_code">key</span> can be used to compare the values in column <span class="inline_code">j</span>. For example, <span class="inline_code">lambda</span> <span class="inline_code">date:</span> <span class="inline_code">date.year</span> groups a column of <span class="inline_code">Date</span> objects by year.</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> from pattern.db import Datasheet, pprint
>>>
>>> ds = Datasheet(rows=[
>>> (1, u'Schrödinger', 'cat'),
>>> (2, u'Hofstadter', 'cat'),
>>> (3, u'Taxi', 'dog')
>>> ])
>>>
>>> g = ds.copy(columns=[2, 0]) # A copy with type & id.
>>> g = g.group(0, COUNT) # Group type, count rows per type.
>>> pprint(g, fill='')
cat 2
dog 1 </pre></div>
<h3>Sorting rows & columns</h3>
<p><span class="inline_code">Datasheet.columns[j].sort()</span> sorts the rows according to the values in column <span class="inline_code">j</span>. <br /><span class="inline_code">Datasheet.columns.sort()</span> can be used to change the column order:</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> ds.columns.sort(order=[0, 2, 1])
>>> pprint(ds, fill='')
1 cat Schrödinger
2 cat Hofstadter
3 dog Taxi</pre></div>
<p><span class="inline_code">Datasheet.columns.swap(j1,j2)</span> swaps two individual columns with given indices.</p>
<h3><a name="csv"></a>CSV import & export</h3>
<p><span class="inline_code">Datasheet.save()</span> exports the matrix as a CSV file. <span class="inline_code">Datasheet.load()</span> returns a <span class="inline_code">Datasheet</span> from a given CSV file. CSV (comma-separated values) is a simple text format for tabular data, where each line is a row and each value is separated by a comma.</p>
<pre class="brush:python; gutter:false; light:true;">datasheet = Datasheet.load(path, separator=',', decoder=lambda v: v, headers=False)</pre><pre class="brush:python; gutter:false; light:true;">datasheet.save(path, separator=',', encoder=lambda v: v, headers=False)</pre><p>On export, all <span class="inline_code">str</span>, <span class="inline_code">int</span>, <span class="inline_code">float</span>, <span class="inline_code">bool</span> and <span class="inline_code">Date</span> values are converted to Unicode. An <span class="inline_code">encoder</span> can be given for other data types. On import, all values in the datasheet will be Unicode unless a <span class="inline_code">decoder</span> is given.</p>
<p>With <span class="inline_code">headers=True</span>, the <span class="inline_code">Datasheet.fields</span> headers are exported and imported (first line in CSV). In this case, the data type for each column (<span class="inline_code">STRING</span>, <span class="inline_code">INTEGER</span>, <span class="inline_code">FLOAT</span>, <span class="inline_code">BOOLEAN</span> or <span class="inline_code">DATE</span>) is explicitly known and no <span class="inline_code">encoder</span> or <span class="inline_code">decoder</span> is needed.</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> from pattern.db import Datasheet, STRING, DATE, date
>>>
>>> ds = Datasheet(fields=(('name', STRING), ('date', DATE)))
>>> ds.append((u'Schrödinger', date('1887-08-12')))
>>> ds.append((u'Hofstadter', date('1945-02-15')))
>>>
>>> ds.save('pets.csv', headers=True)
>>>
>>> ds = Datasheet.load('pets.csv', headers=True)
>>> print ds[0]
[u'Schrödinger', Date('1887-08-12 00:00:00')]
</pre></div>
<p>The <span class="inline_code">csv()</span> function can also be used instead of <span class="inline_code">Datasheet.load()</span>:</p>
<div class="example">
<pre class="brush: python;gutter: false; light: true; fontsize: 100; first-line: 1; ">>>> from pattern.db import csv
>>>
>>> for name, date in csv('pets.csv', separator=',', headers=True):
>>> print name, date</pre></div>
<p> </p>
<hr />
<h2><a name="date"></a>Date</h2>
<p>The <span class="inline_code">date()</span> function returns a new <span class="inline_code">Date</span>, a convenient subclass of Python's <span class="inline_code">datetime.datetime</span>. It takes an integer (Unix timestamp), a string or <span class="inline_code">NOW</span>. An optional string input format and output format can be given (e.g., <span class="inline_code">"%d/%m/%y"</span>). The default output format is <span class="inline_code">"YYYY-MM-DD hh:mm:ss"</span>.</p>
<pre class="brush:python; gutter:false; light:true;">d = date(int)</pre><pre class="brush:python; gutter:false; light:true;">d = date(NOW, format=DEFAULT)
</pre><pre class="brush:python; gutter:false; light:true;">d = date(string)</pre><pre class="brush:python; gutter:false; light:true;">d = date(string, format=DEFAULT)</pre><pre class="brush:python; gutter:false; light:true;">d = date(string, inputformat, format=DEFAULT)</pre><pre class="brush:python; gutter:false; light:true;">d = date(year, month, day, format=DEFAULT)</pre><pre class="brush:python; gutter:false; light:true;">d = date(year, month, day, hours, minutes, seconds, format=DEFAULT)</pre><pre class="brush: python;gutter: false; light: true; fontsize: 100; first-line: 1; ">d.year
d.month # 1-12
d.week # 1-52
d.weekday # 1-7
d.day # 1-31
d.minute # 1-60
d.second # 1-60
d.timestamp # Seconds elapsed since 1/1/1970.</pre><p>If no string input format is given, a number of common formats will be tried:</p>
<table class="border">
<tbody>
<tr>
<td><span class="smallcaps">Format</span></td>
<td><span class="smallcaps">Example</span></td>
</tr>
<tr>
<td><span class="inline_code">%Y-%m-%d %H:%M:%S</span></td>
<td>2010-09-21 09:27:01</td>
</tr>
<tr>
<td><span class="inline_code">%a, %d %b %Y %H:%M:%S %z</span></td>
<td>Tue, 9 Sep 2010 17:58:28 +0000</td>
</tr>
<tr>
<td><span class="inline_code">%Y-%m-%dT%H:%M:%SZ</span></td>
<td>2010-09-20T09:27:01Z</td>
</tr>
<tr>
<td><span class="inline_code">%Y-%m-%dT%H:%M:%S+0000</span></td>
<td>2010-09-20T09:27:01+0000</td>
</tr>
<tr>
<td><span class="inline_code">%Y-%m-%d %H:%M</span></td>
<td>2010-09-20 09:27</td>
</tr>
<tr>
<td><span class="inline_code">%Y-%m-%d</span></td>
<td>2010-09-20</td>
</tr>
<tr>
<td><span class="inline_code">%d/%m/%Y</span></td>
<td>20/09/2010</td>
</tr>
<tr>
<td><span class="inline_code">%d %B %Y</span></td>
<td>9 september 2010</td>
</tr>
<tr>
<td><span class="inline_code">%B %d %Y</span></td>
<td>September 9 2010</td>
</tr>
<tr>
<td><span class="inline_code">%B %d, %Y</span></td>
<td>September 09, 2010</td>
</tr>
</tbody>
</table>
<p>All date formats used in <a class="link-maintenance" href="pattern-web.html">pattern.web</a> (e.g., Twitter search result) are automatically detected.<br />For an overview of date format syntax, see: <a href="http://docs.python.org/library/time.html#time.strftime" target="_blank">http://docs.python.org/library/time.html#time.strftime</a>.<br /> </p>
<p><span class="smallcaps">Date calculations</span></p>
<p>The <span class="inline_code">time()</span> function can be used to add or subtract time to a <span class="inline_code">Date</span>:</p>
<pre class="brush:python; gutter:false; light:true;">time(days=0, seconds=0, minutes=0, hours=0)</pre><div class="example">
<pre class="brush:python; gutter:false; light:true;">>>> from pattern.db import date, time
>>>
>>> d = date('23 august 2011')
>>> d += time(days=2, hours=5)
>>> print type(d)
>>> print d
>>> print d.year, d.month, d.day
<class 'pattern.db.Date'>
2011-08-25 05:00:00
2011, 8, 25 </pre></div>
<p> </p>
<hr />
<h2>See also</h2>
<ul>
<li><a href="http://www.cherrypy.org/" target="_blank">CherryPy</a> (BSD): o<span>bject-oriented HTTP framework for Python.</span></li>
<li><span><a href="https://www.djangoproject.com/" target="_blank">Django</a> (BSD): m</span><span>odel-view-controller framework for Python.</span></li>
</ul>
</div>
</div></div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
SyntaxHighlighter.all();
</script>
</body>
</html>
|