Sqlalchemy Cheatsheet PDF
Sqlalchemy Cheatsheet PDF
A Python-database interface
John W. Shipman
2013-04-11 12:57
Abstract
Summary of common functions in the SQLAlchemy object-relational database system.
1 2
This publication is available in Web form and also as a PDF document . Please forward any
comments to [email protected].
Table of Contents
1. Introduction ............................................................................................................................ 2
2. Overall structure of SQLAlchemy ............................................................................................. 3
3. Connecting to database engines ................................................................................................ 3
3.1. DSN: The Data Source Name .......................................................................................... 4
4. Metadata: Describing the database schema ................................................................................ 4
4.1. Reflection: finding out the structure of an existing SQL database ...................................... 5
4.2. Building your own schema ............................................................................................ 5
4.3. Interface to class MetaData ....................................................................................... 6
4.4. class Table: Metadata for one table ........................................................................... 6
4.5. class ForeignKeyConstraint: Specifying a relation to another table ........................ 8
4.6. class PrimaryKeyConstraint: Describing a table's primary key ............................... 9
4.7. class UniqueConstraint: Describing a uniqueness constraint on a table .................... 9
4.8. class Index: Specifying an index on a table ............................................................... 10
4.9. class Column: Metadata for one table column ............................................................ 10
4.10. Column types ............................................................................................................ 12
4.11. class ForeignKey: Specifying a column's foreign key relation ................................. 14
4.12. class Sequence: Specifying an auto-incrementing column ....................................... 15
5. The object-relational mapper ................................................................................................... 15
5.1. Defining a class to be mapped ...................................................................................... 16
5.2. Using orm.mapper() ................................................................................................. 16
5.3. Properties of a mapping ............................................................................................... 17
6. Session operations .................................................................................................................. 19
6.1. Operations on a session ................................................................................................ 20
7. Queries .................................................................................................................................. 20
7.1. Slicing a Query ........................................................................................................... 21
7.2. Query.all() ............................................................................................................. 21
7.3. Query.count() ......................................................................................................... 21
7.4. Query.delete() ....................................................................................................... 22
7.5. Query.filter() ....................................................................................................... 22
1
2
http://www.nmt.edu/tcc/help/pubs/db/sqlalchemy/
http://www.nmt.edu/tcc/help/pubs/db/sqlalchemy/sqlalchemy.pdf
1. Introduction
This document summarizes some of the more commonly used features of the SQLAlchemy system. The
purpose of the SQLAlchemy system is to provide a connection between your Python3 program and any
of several classic database systems built on top of SQL (Structured Query Language ) such as MySQL,
Postgres, or Oracle.
Warning
You should have general knowledge of relational databases, and the additional problems of object-rela-
tional mappers, or the current document will not make much sense to you.
Assuming you understand how a classical SQL database works, SQLAlchemy can make life much
easier for these applications and many more:
You can use SQLAlchemy to connect to applications in other languages, using classical SQL database
engines to interchange data.
You can use SQLAlchemy to provide a persistence layer, so that some of the objects within your Python
application can be stored in external databases for later retrieval and translation back into live objects.
This document is not a complete reference. It is intended for daily reference to functions necessary to
put up fairly simple applications. SQLAlchemy is a full-featured and highly tuneable system, and we
will not cover here many of its useful features
4
for improved performance and simplified programming.
Please refer to the SQLAlchemy home page for tutorials and detailed reference information.
Section 9, reflector: Script to show an existing database's structure (p. 26) is a script that uses
reflection to determine the structure of an existing database.
5
For a sizeable working example, see pycbc: A Python interface to the Christmas Bird Count database .
3
4
http://en.wikipedia.org/wiki/SQL
5
http://www.sqlalchemy.org/
http://www.nmt.edu/~shipman/z/cbc/pycbc/
Once you have imported this function, use this calling sequence to create an engine instance:
dsn
A string that defines what database you are using. For allowable values, see Section 3.1, DSN: The
Data Source Name (p. 4).
convert_unicode=False
If True, any Unicode values that you send to the database will automatically be stored as raw byte
values, and automatically converted back to Unicode on retrieval.
echo=False
Use echo=True for debugging purposes, before your application is in production status. All gen-
erated SQL is written to the standard output stream. The default behavior is for messages to be sent
to a log.
If you would like result sets to be written as well, use echo='debug'.
pool_recycle=timeout
By default, connections will never be recycled (closed). The value, if given, specifies how often (in
seconds) SQLAlchemy should reconnect to the database. The default value is -1, meaning wait
forever.
However, MySQL will disconnect a connection after a time. If you are using MySQL, it is a good
idea to use pool_recycle=3600 so that SQLAlchemy will reconnect after an hour of idle time.
"protocol://username:password@host:port/dbname"
protocol
The type of database system. Supported values include:
mysql MySQL
postgresql Postgres
oracle Oracle
username
The user name.
password
The user's database password.
host
The host name. For the TCC's educational server, this will be dbhost.nmt.edu.
port
The :port part is optional, if you need to specify a TCP/IP port for the database server.
dbname
Name of the database.
Here's an example. Suppose your username is murgatroyd, your password is shazam, and you are
using a database named blortbase on the TCC's MySQL server. The DSN would look like this:
mysql://murgatroyd:[email protected]/blortbase
Then, use a constructor with this general form to create the MetaData instance:
schema.MetaData(bind=E, reflect=True)
where E is the Engine instance returned by the create_engine function described in Section 3,
Connecting to database engines (p. 3).
For operations on the resulting instance, see Section 4.3, Interface to class MetaData (p. 6).
schema.MetaData(bind=None, reflect=False)
bind
If you have an Engine instance E, pass it to this argument and your metadata will be connected to
that engine.
You don't have to bind your metadata to an existing engine. You can always connect later with a
statement of this form:
M.bind = E
name
The SQL name of the table. If the name has any uppercase characters, that name will be treated as
case-sensitive. Names with only lowercase characters will be case-insensitive.
M
The MetaData instance.
coli
The remaining positional arguments specify the columns, and constraints if any, of the table.
Each column is specified as a Column instance; see Section 4.9, class Column: Metadata for
one table column (p. 10).
To specify a primary key, especially when it comprises multiple columns, see Section 4.6, class
PrimaryKeyConstraint: Describing a table's primary key (p. 9).
To specify a foreign key constraint, see Section 4.5, class ForeignKeyConstraint: Specifying
a relation to another table (p. 8).
To specify a constraint that certain field values are unique within the table, see Section 4.7, class
UniqueConstraint: Describing a uniqueness constraint on a table (p. 9).
autoload=False
If you specify autoload=True, the metadata for this table will be reflected, that is, the current
definition of the table at the SQL level will be used.
include_columns=None
Normally, all the columns of the table will be visible at the SQLAlchemy level. If you would like to
make only some columns visible, pass a sequence of column names to this keyword argument.
For example, suppose a table has columns named first, last, and ssn, but you don't want to
make the ssn column visible. To accomplish this, use the argument in-
clude_columns=['first', 'last'].
The Table() constructor is located in the sqlalchemy.schema module, so you will need to import
it in one of these two ways:
from sqlalchemy.schema import Table
some_table = Table(...)
some_table = schema.Table(...)
You could also retrieve the Column instance for the first column with this expression:
colors.columns.red
Because retrieving columns in this way is quite common, the synonym .c makes this operation
shorter, like this:
colors.c.red
schema.ForeignKeyConstraint(localColumns, foreignColumns
[, name=localName])
localColumns
A sequence of the names of columns in the current table that are related to the foreign table.
foreignColumns
A sequence of the columns in the foreign table to which the columns in localColumns are related.
Each element of this sequence may be either: a name of the form "table.col_name"; or the actual
Column instance in the foreign table.
localName
The name of this constraint, unique within the database.
For example, suppose the concatenation of three columns named city, state, and nation in the
current table is a foreign key reference to columns named city_code, region, and country in a
If geo_table is the Table instance for the foreign table, you could instead use its .c attribute and
describe the relation by including this expression in the Table() argument list:
schema.PrimaryKeyConstraint(column, ...)
schema.PrimaryKeyConstraint('major_id', 'minor_id')
indexName
A name for this particular index. The name must be unique among all the indices in the same
database.
column
Provide one or more Column instances in order to index on the concatenation of the column values
in each row. Typically, each will be an expression of the form table.c.colName, where table
is the Table instance for which the index is to be created, and colName is the name of the column.
unique=False
By default, there is no requirement that each value in the index be unique. If you specify
unique=True, only one occurrence of each value will be permitted in the table.
For example, suppose town_table is a Table instance with two rows named state and city. To
add an index to this table whose values are unique, you would call the Index() constructor with these
values:
name
The name of the column.
type
The column type. You may pass either a class or an instance of a class, so long as the class is a subtype
of AbstractType. For some of the common column types, see Section 4.10, Column types (p. 12).
arg
Following the column type, you may optionally include these items:
Section 4.11, class ForeignKey: Specifying a column's foreign key relation (p. 14).
Section 4.12, class Sequence: Specifying an auto-incrementing column (p. 15).
default=value
Use value as the default value of this column when a new row is added, if no explicit value is
provided.
index=True
Specify an index on the table. If this column is to be indexed, specify index=True.
To specify an index on multiple columns, see Section 4.8, class Index: Specifying an index on
a table (p. 10).
key=columnKey
Normally, the name of a column at the SQLAlchemy level is the same as its name in the SQL table.
To use a different name throughout SQLAlchemy, supply that name as the value of this keywoard
argument.
nullable=True
By default, a column may contain null values. To prohibit this, use nullable=False.
primary_key=True
If you provide this option, the column will be part of the primary key for the table. If only one
column specifies this option, it will be the sole primary key column. To define a primary key com-
posed of multiple columns, use this option on each of the columns in the key.
unique=True
By default, a column may contain multiple rows with the same value. To prohibit this, use
unique=True.
Attributes of a Column instance include:
.name
The column's name.
.nullable
A bool value, True if this column may contain null values.
.primary_key
A bool value, True if this column is a primary key column.
.type
The column's type as an instance of one of the classes described in Section 4.10, Column
types (p. 12).
.unique
A bool value, True if the values in this column must be unique within the table.
When you call the Column() constructor, the second argument specifies the column type (see Section 4.9,
class Column: Metadata for one table column (p. 10)).
This section enumerates some of the more commonly used SQLAlchemy classes that are used to specify
column types. When you create a Column, you can pass either a class name or an instance as the type
argument.
For a number of generic, simple data types like Integer or Date, you'll generally specify the type
as just a class name.
For column types that need additional information, such as the size of a text field, you'll pass that
additional information to the constructor, and use the resulting instance as the type argument to the
Column() constructor. For example, if you want to store a text string up to 8 characters, you'll use
Text(8) as the argument.
Here's an example. Suppose your database has a table named horses that describes horses. The first
column is the horse's name, the primary key, up to 40 characters; and the second column is its birthdate.
This code would add that table's description to a MetaData instance named meta; note that the type
of the first column is an instance of the Text class, while the type of the second column is the name of
a class (Date).
SQLAlchemy's types have two faces: on the SQLAlchemy side, you will see a Python type, and on the
SQL side is the actual type that appears in the SQL statements sent to the database engine. For example,
in your Python code, an instance of SQLAlchemy's Date class looks like a date instance from Python's
datetime library, but in the SQL world the representation will use SQL's DATE type.
Here are some of the more common data types. Types whose names contain lowercase letters, such as
DateTime, are generic types; SQLAlchemy will pick an appropriate SQL type for you. Types whose
names are all caps, such as INTEGER,
6
are guaranteed to use the SQL type of the same name. Refer to
the vendor's documentation for the full set.
6
http://www.sqlalchemy.org/docs/core/types.html
types.Float(B)
The value of B is the number of bits of precision in the mantissa. In practical terms, any value of B from
1 to 24 will give you a single-precision float, while values 2553 will give you a double-precision column.
types.Numeric(precision=None, scale=None)
The precision argument specifies the maximum number of decimal digits, and the scale argument
specifies the scale factor. For example, a value of type Numeric(5,2) will hold numbers of up to five
digits, but with an implied decimal point before the last two digits, that is, numbers up to 999.99. The
default scale value is zero, and the default precision value depends on the underlying database
engine.
types.String(length)
schema.ForeignKey(foreignColumn[, name="keyName"])
foreignColumn
A reference to the column in the foreign table. This may be either a string of the form
"table.column", or a Column instance in the foreign table.
keyName
A unique name for this key. If omitted, it defaults to a string of the form "ix_columnName". This
name must be unique within the database.
Here's an example. Suppose you are defining an integer column named part_no, and values in this
column are related to a column named part_no in a table named part. Here is one way to define the
column:
You may also provide as an argument the actual Column instance from the foreign table. Here is another
way to define this column, assuming that part_table is the foreign table as a Table instance:
schema.Column("part_no", types.Integer,
schema.ForeignKey(part_table.c.part_no))
name
A name for this sequence column. This name must be unique within the database.
start
The value to be used for the first row added. Default is 1.
increment
The value to be added to the previous value every time a new row is added. Default is 1.
optional
If you are using Postgresql, use optional=True so that the engine's built-in auto-increment feature
will be used.
Suppose you are defining an auto-increment column named ticket_id. You might use a definition
like this:
class Bead(object):
def __init__(self, id, material, count):
self.id = id
self.material = material
self.count = count
def __repr__(self):
return("<Bead(%s (%.1f),
orm.mapper(Reptiles, reptile_table,
order_by=(Reptiles.section, Reptiles.id_number))
properties
A dictionary whose keys are the names of properties of the mapping. See Section 5.3, Properties
of a mapping (p. 17).
This will create a one-to-many relation between the mapped class and some class Other. Once you
have done this:
A reference to the childcol attribute on the mapped class will produce a list of the related children.
In each child instance, the backname attribute will point at the parent instance.
Here is an example. Suppose that the Part class is mapped to a table parts_table that relates part
numbers (column name partNo) to descriptions (column name desc). Further suppose that there is
an Inventory class that specifies how many (column partsCount) of a given part (whose part
number is in that class's .partNo attribute) are on hand. Here is the call to orm.mapper() for this
relation:
orm.mapper(Part, parts_table,
properties={'inventories': orm.relation(Inventory, backref='part')})
For any instance P of class Part, attribute P.inventories will be a list of Inventory instances that
have the same part number.
Also, for any instance I of class Inventory, attribute I.part will be the Part instance that has the
same part number.
othercol: orm.relation(OtherTable,
secondary=secondaryTable,
backref=backname)
otherCol is the name of an attribute that will be added to the primary table being mapped.
OtherTable is the other primary table as a class name.
secondaryTable is the Table instance for the secondary table.
backname is the name of an attribute that will be added to the other primary table.
Once you have done this:
Any instance of the first primary table will have an attribute that iterates over the related rows of the
other primary table. This instance name was specified by otherCol.
Any instance of the second primary table will have an attribute that iterates over the related rows of
the first primary table. This instance name was specified by backname.
To continue our example, suppose the Article class, whose primary key is its article_id column,
has a many-to-many relation with the Tag class, whose primary key is its tag_id column. The secondary
table metadata will look like this:
orm.mapper(Article, articles_table,
properties={ 'tags': orm.relation(Tag, secondary=article_tag_table,
backref='articles') })
Once this mapping is in place, every instance of the Article class will have a .tags attribute that it-
erates over all the related Tag instances. Conversely, every instance of the Tag class will have an
.articles attribute that will iterate over the articles with that tag.
bind
The engine returned by create_engine() (see Section 3, Connecting to database engines (p. 3)).
autoflush
If this argument is True, every transaction commit will flush the changes from the session into the
database before performing the commit.
autocommit
This option affects whether flushing the session also causes a commit. Generally it is good practice
to use the default value, autocommit=False, and commit explicitly. If this option is True, however,
whenever the session is flushed, SQLAlchemy also performs a commit.
expire_on_commit
By default, this option is True, which means that after every commit, objects in the session expire,
so the next transaction will fetch the latest values from the database. This option is strongly recom-
mended for multi-threaded applications.
Here's an example of session creation. Let's suppose that module model.py contains a variable named
metadata that defines the schema. First we create the Session class:
engine = create_engine("mysql://alice:[email protected]/alicedb")
model.metadata.bind = engine
Session = orm.sessionmaker(bind=engine)
session = Session()
7. Queries
You can initiate a query against a particular mapped class in the database by using the query()
method on a Session instance (see Section 6, Session operations (p. 19)).
Here is the general form of the expression that creates a Query instance, given a Session instance S:
7.2. Query.all()
To return a list of all the objects from a query, use this method. (If this list is very large, you may wish
to avoid this method, since it makes all the objects present in memory at once.)
For example, suppose you have a session instance named session, and a mapped class named mod-
el.Kennel. This query would display all the rows in the related table.
q = session.query(model.Kennel)
for row in q.all():
print row
7.3. Query.count()
This method returns, as an integer, the number of items that are retrieved by a query.
For example, this would return the number of rows in the mapped class model.Kennel:
print session.query(model.Kennel).count()
Warning
This method can delete entire tables! Use it with great caution. Back up your data outside the database
if you are concerned about losses.
Also, if you delete rows that are the subject of a foreign-key relation in another table, the operation may
fail. It is best to delete first the records that depend on other rows.
q.delete()
7.5. Query.filter()
This method returns a Query instance that is modified to include only certain rows.
The argument of this method may take any of the following forms, where column is a Column within
the table being queried.
column == value
Return only those rows for which column equals the given value.
column != value
Return only those rows for which column does not equal the given value.
Relational operators
The usual relational operators are allowed in expressions passed to .filter(). For example, this
would return a Query instance that produces all the rows from the People table whose age column
is greater than or equal to 18:
column.like(wildcard)
The wildcard argument is a string with one or more % characters match any string. For example,
this query would return all the rows from the Tree table whose kind column contains the string
"elm" anywhere in the column:
elmList = session.query(Tree).filter(Tree.c.kind.like("%elm%")).all()
column.in_(rowList)
Returns a modified Query that includes only those rows found in rowList.
The rowList argument may be either a regular Python list containing column values, or a Query
instance whose rows contain the given column. For example, this query displays rows of the Things
table whose category column is either "animal" or "vegetable".
~column.in_(rowList)
To produce a modified Query containing rows whose column values are not found in a given se-
quence or query, use the ~ operator before the call to the .in_() method. For example, here is
a query that excludes rows of the Bull table whose state column is Texas or Oklahoma.
column == None
Returns a new Query that includes only rows where the specified column has a null value.
column != None
Returns a new Query that includes only rows where the specified column does not have a null
value.
and_(C1, C2)
Return only rows that satisfy both condition C1 and condition C2. Each condition is described using
any of the expressions that can be passed to .filter(). You will need to import it like this:
For example, this query would return rows from the Date table whose marital column is
'single' and whose sex column is 'F'.
q = session.query(Date).filter(and_(
Date.c.marital=='single',
Date.c.sex=='F'))
or_(C1, C2)
Similar to the and_() method, but returns rows for which either condition C1 or condition C2 is
true. You will need to import it like this:
7.6. Query.filter_by()
This method produces a modified Query instance that includes only rows with certain column values.
Here is the general form, given a Query instance q:
Each colname is the name of a column in the queried table. The returned query selects only rows for
which each of the named columns has the given value.
For example, here is an example query from Section 7.5, Query.filter() (p. 22) redone using
.filter_by():
q = session.query(Date).filter_by(marital='single', sex='F')
7.7. Query.first()
This method takes no arguments, and attempts to produce the first result from the query.
If the query produces one or more results, this method returns the first result.
If the query produces no results, this method returns None.
eprise = session.query(Gliders).get("NCC-1701")
Suppose you have a table named Reptiles with a composite primary key containing the columns
genus and species. To query this table for a row whose genus is Crocodylus and its species porosus:
7.9. Query.join()
If you want to qualify your query according to the values of columns in a related table, use a method
call of this general form:
.join(table1, table2, )
q =(session.query(Inventory)
.join(Inventory.part)
.filter(Inventory.on_hand > 0)
.filter_by(obsolete=1))
The query will return Inventory instances because that was the argument you passed to the .query()
method. The .join() method call effectively adds the columns from the Part table to each row of the
query, so that you can refer to the obsolete column from the Part table in the .filter_by()
method call.
7.10. Query.one()
Use this method when you expect a query to return exactly one record, and you want to be notified
otherwise. It takes no arguments.
If the query returns exactly one row, it returns that instance.
If the query returns no rows, this method raises exception orm.exc.NoResultFound.
7.11. Query.order_by()
To specify the ordering of rows returned by a query, apply this method to it; the method returns a
modified Query instance.
.order_by(column, ...)
For example, suppose you have a mapped class named Addresses with columns named country,
state, and town. Here is a query that uses country as the major key, state as a secondary key, and
town as a tertiary key:
q = session.query(Addresses).order_by(Addresses.country,
Addresses.state, Addresses.town)
For a tuple t produced by iterating over q, you can access the value of the name column as t.name.
You can access the entire Island instance as t.Island.
8. Exceptions
Here is a list of exceptions that may be thrown by SQLAlchemy. They are defined in module sqlal-
chemy.exc.
ArgumentError
CircularDependencyError
CompileError
ConcurrentModificationError
DBAPIError
DataError
DatabaseError
DisconnectionError
FlushError
protocol
Database protocol, one of: postgresql, mysql, or oracle.
username
Your database user name.
passfile
The path name of a file that contains your database password by itself on the first line. We require
that you do things this way so that your database password will not be visible on the command
line.
host[:port]
The database server's hostname, optionally followed by a colon and a port number.
dbname
The name of your database.
7
8
http://www.nmt.edu/~shipman/soft/litprog/
http://www.nmt.edu/~shipman/soft/clean/
#!/usr/bin/env python
#================================================================
# reflector: Report on an existing database schema.
# For documentation, see:
# http://www.nmt.edu/tcc/help/pubs/db/sqlalchemy/
#----------------------------------------------------------------
# Command line options:
# reflector PROTOCOL USERNAME PWDFILE HOST[:PORT] DBNAME
# where:
# PROTOCOL {postgresql|mysql|...}
# USERNAME Database username
# PWDFILE Name of a file containing the password
# HOST[:PORT] Host name with optional port
# DBNAME Database name
#----------------------------------------------------------------
Next come module imports. We need sys to access the standard I/O streams.
reflector
#================================================================
# Imports
#----------------------------------------------------------------
import sys
From sqlalchemy, we will need the engine module to connect to the database engine, and the schema
module for the MetaData class to reflect the database's schema. The exc module defines SQLAlchemy's
exceptions.
reflector
The constant URL_FORMAT is used to assemble the various command line arguments and the password
into a URL suitable for connecting to the database engine.
reflector
#================================================================
# Manifest constants
#----------------------------------------------------------------
URL_FORMAT = "%s://%s:%s@%s/%s"
# ^ ^ ^ ^ ^
# | | | | +-- Database name
# | | | +-- Host name
# | | +-- Password
# | +-- User name
# +-- Protocol
# - - - - - m a i n
def main():
'''Report on the schema of an existing database.
#-- 1 --
# [ if the command line arguments are valid ->
# engineURL := an URL that will open the database
# with those arguments
# else ->
# sys.stderr +:= usage and error messages
# stop execution ]
engineURL = checkArguments()
#-- 2 --
# [ if engineURL specifies a useable database connection ->
# engine := an sqlalchemy.engine instance representing
# that connection
# metadata := an sqlalchemy.schema.MetaData instance
# reflecting the schema of that database
# else ->
# sys.stderr +:= error message
# stop execution ]
try:
db = engine.create_engine(engineURL)
metadata = schema.MetaData(bind=db, reflect=True)
except exc.SQLAlchemyError, detail:
fatal("Could not connect: %s" % detail)
The metadata attribute .tables is a dictionary whose keys are the table names, and each related value
is the corresponding Table instance. We will present the table reports in ascending order by table name.
reflector
#-- 3 --
# [ sys.stdout +:= report showing the tables in metadata in
# ascending order by table name ]
for tableName in sorted(metadata.tables.keys()):
# - - - c h e c k A r g u m e n t s
def checkArguments():
'''Process the command line arguments.
There must be exactly five arguments. The third argument is the name of the password file, so we must
try to go and read the password from that file. Errors are reported by Section 9.4, usage(): Usage
message (p. 30) and Section 9.5, fatal(): Fatal error message (p. 30).
reflector
#-- 1 --
# [ if there are exactly five command line arguments ->
# protocol, username, passFileName, host, dbName :=
# those arguments
# else ->
# sys.stderr +:= usage and error messages
# stop execution ]
argList = sys.argv[1:]
if len(argList) != 5:
usage("Incorrect number of arguments.")
protocol, username, passFileName, host, dbName = argList
#-- 2 --
# [ if passFileName names a readable, nonempty file ->
# password := first line from that file, with trailing
# whitespace removed
# else ->
# sys.stderr +:= (usage and error messages)
# stop execution ]
try:
passFile = file(passFileName)
password = passFile.readline().rstrip()
passFile.close()
except IOError, detail:
fatal("Could not open password file '%s': %s" %
(passFileName, detail))
Finally, assemble the pieces into a URL using the format string defined in Section 9.1, Prologue (p. 27).
#-- 3 --
return(URL_FORMAT %
(protocol, username, password, host, dbName))
# - - - u s a g e
def usage(*L):
'''Write a usage message and terminate.
# - - - f a t a l
def fatal(*L):
'''Write a message and stop execution.
# - - - s h o w T a b l e
#-- 1 --
print "\n\n================ %s ================" % table.name
The .primary_key attribute of a table is a sequence of Column objects; we display only the column
names.
reflector
#-- 2 --
# [ if table has at least one primary key ->
# sys.stdout +:= primary key report
# else -> I ]
if len(table.primary_key):
print "Primary keys:",
for k in table.primary_key:
print k.name,
print
Similarly, the .foreign_keys attribute is a sequence of ForeignKey instances, each of which has
the local column as a .parent attribute, and the foreign column as a .column attribute.
reflector
#-- 3 --
# [ if table has any foreign keys ->
# sys.stdout +:= report on those keys
# else -> I ]
if len(table.foreign_keys):
print "Foreign keys:"
for fkey in table.foreign_keys:
print " (%s -> %s)" % (fkey.parent.name, fkey.column)
If the table has any indices, the .indexes attribute is a sequence of Index instances, each with its name
as the .name attribute and its .columns attribute a sequence of Column instances.
reflector
#-- 4 --
# [ if table has an indices ->
# sys.stdout +:= report on those indices
# else -> I ]
if len(table.indexes):
print "Indices:"
for index in table.indexes:
Column display is handled by Section 9.7, showColumn(): Report on one column (p. 32).
reflector
#-- 5 --
# [ sys.stdout +:= report on table's columns ]
print "Columns [P=primary key; N=nullable; U=unique]:"
for column in table.c:
showColumn(column)
# - - - s h o w C o l u m n
def showColumn(column):
'''Display one column's definition.
To save space in the report, we represent the primary key, nullable, and unique properties as single-
letter codes dispayed in brackets after the column name.
reflector
#-- 1 --
# [ if column is a primary key, nullable, or unique ->
# notes := codes for those properties in brackets
# else ->
# noset := '' ]
L=[]
if column.primary_key:
L.append("P")
if column.nullable:
L.append("N")
if column.unique:
L.append("U")
notes =("[%s]" % ''.join(L)
if L
else "")
#-- 2 --
# [ sys.stdout +:= column.name + notes + column.type ]
print(" %s%s: %s" %
(column.name, notes, column.type))
9.8. Epilogue
These lines invoke the main program, provided it is run as a script.
#================================================================
# Epilogue
#----------------------------------------------------------------
if __name__ == '__main__':
main()