[SQL-CVS] SQLObject/docs SQLObject.txt,1.7,1.8
SQLObject is a Python ORM.
Brought to you by:
ianbicking,
phd
From: <ian...@us...> - 2003-04-08 03:08:11
|
Update of /cvsroot/sqlobject/SQLObject/docs In directory sc8-pr-cvs1:/tmp/cvs-serv12016/docs Modified Files: SQLObject.txt Log Message: Updated docs (almost ready for release!) Index: SQLObject.txt =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/docs/SQLObject.txt,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** SQLObject.txt 3 Apr 2003 19:36:59 -0000 1.7 --- SQLObject.txt 8 Apr 2003 03:08:02 -0000 1.8 *************** *** 1,4 **** ``````````````` ! SQLObject 0.2.1 ``````````````` --- 1,4 ---- ``````````````` ! SQLObject 0.3 ``````````````` *************** *** 9,13 **** SQLObject is by Ian Bicking, <ia...@co...>. The website ! is http://colorstudy.com/software/SQLObject The code is licensed under the `Lesser General Public License`_ --- 9,13 ---- SQLObject is by Ian Bicking, <ia...@co...>. The website ! is http://sqlobject.org The code is licensed under the `Lesser General Public License`_ *************** *** 29,51 **** In using SQLObject, you will create a class definition that will ! describe how the object connects to the database (in addition to any ! other methods you may wish to add to the class). SQLObject will ! produce the code to access the database, and update the database with ! your changes. The interface to the database is meant to be ! indistinguishable from other interfaces you may add to the object. ! SQLObject also includes a novel feature to generate WHERE clauses ! using Python syntax and objects (intead of generating SQL using string ! substitution, as is traditional). Requirements ============ ! Currently SQLObject supports MySQL, PostgreSQL (via ``psycopg``) and ! SQLite. The SQLite support is the youngest. ! Python 2.2 or higher is strictly required. SQLObject uses metaclasses ! to create the objects and properties throughout, and those features ! are only available in 2.2+. Compared To Other Database Wrappers --- 29,53 ---- In using SQLObject, you will create a class definition that will ! describe how the object translates to the database table. SQLObject ! will produce the code to access the database, and update the database ! with your changes. The generated interface looks similar to any other ! interface, and callers need not be aware of the database backend. ! SQLObject also includes a novel feature to avoid generating most SQL. ! Queries are constructed using Python syntax, which is turned into SQL. ! This also allows non-SQL databases to be used with the same query ! syntax. Requirements ============ ! Currently SQLObject supports MySQL, PostgreSQL (via ``psycopg``), ! SQLite, and a DBM-based store. The DBM backend is the youngest, ! and somewhat experimental. ! Python 2.2 or higher is strictly required. No backward compatible ! version is planned -- SQLObject uses many 2.2 features, and in many ! ways is my own learning tool for the dramatically different ! programming style that new-style classes allow. Compared To Other Database Wrappers *************** *** 53,64 **** There are several object-relational mappers (ORM) for Python. I ! honestly can't comment on the quality of those packages, but I'll try ! to place SQLObject in perspective. SQLObject uses new-style classes extensively. The resultant objects ! have that feel as well -- setting attributes has side effects (it ! changes the database), and defining classes has side effects (through ! the use of metaclasses). For me this is something of an experiment in ! new-style classes. I believe it has been successful. SQLObject creates objects that feel similar to normal Python objects --- 55,66 ---- There are several object-relational mappers (ORM) for Python. I ! honestly can't comment deeply on the quality of those packages, but ! I'll try to place SQLObject in perspective. SQLObject uses new-style classes extensively. The resultant objects ! have a new-style feel as a result -- setting attributes has side ! effects (it changes the database), and defining classes has side ! effects (through the use of metaclasses). Attributes are exposed ! without fear, knowing that they can be made dynamic later. SQLObject creates objects that feel similar to normal Python objects *************** *** 71,81 **** This is in contrast to some ORMs that provide a dictionary-like ! interface to the database (for example, PyDo_). The dictionary interface distinguishes the row from a normal Python object. I also don't care for the use of strings where an attribute seems more natural -- columns are limited in number and predefined, just like ! attributes. ! .. _PyDo: http://skunkweb.sourceforge.net/pydo.html SQLObject is, to my knowledge, unique in using metaclasses to --- 73,84 ---- This is in contrast to some ORMs that provide a dictionary-like ! interface to the database (for example, PyDO_). The dictionary interface distinguishes the row from a normal Python object. I also don't care for the use of strings where an attribute seems more natural -- columns are limited in number and predefined, just like ! attributes. (Note: newer version of PyDO apparently allow attribute ! access as well) ! .. _PyDO: http://skunkweb.sourceforge.net/pydo.html SQLObject is, to my knowledge, unique in using metaclasses to *************** *** 84,88 **** XML file (for example, MiddleKit, part of Webware_). By using metaclasses you are able to comfortably define your schema in the ! Python source code. No code generation, no weird tools. .. _Webware: http://webware.sourceforge.net --- 87,92 ---- XML file (for example, MiddleKit, part of Webware_). By using metaclasses you are able to comfortably define your schema in the ! Python source code. No code generation, no weird tools, no ! compilation step. .. _Webware: http://webware.sourceforge.net *************** *** 93,114 **** Here are some things I plan: ! * More databases supported. * Better transaction support -- right now you can use transactions for the database, but the object isn't transaction-aware, so non-database persistence won't be able to be rolled back. ! * Pre-fetching of values for a SQLObject. In particular, when you ! do a `select` that fetches a hundred objects, you ought to fetch ! all those objects in one ``SELECT`` statement, instead of just ! fetching the IDs and issuing one ``SELECT`` for each object. ! * `select` gives an iterator, so all objects don't have to be in ! memory at the same time. ! * Slicing of results, creating ``LIMIT`` and ``OFFSET`` in the SQL. ! * Cache management -- purging old objects, keeping size down, or ! not caching any objects. ! * Maybe even profile some of this, so that I know what really is ! the performance problem (though it also depends greatly on the ! structure of the database). ! * Allow different naming schemes, both for ``id`` and for ! mixedCase/mixed_case. Using SQLObject --- 97,111 ---- Here are some things I plan: ! * More databases supported. SQL databases (like Oracle or Firebird) ! should be easy, non-SQL databases like Metakit should be possible. * Better transaction support -- right now you can use transactions for the database, but the object isn't transaction-aware, so non-database persistence won't be able to be rolled back. ! * Profile SQLObject of this, so that I can identify bottlenecks. ! * Allow different naming schemes. ! * Makes hooks with a validation and form generation package, so ! SQLObject classes (read: schemas) can be published for editing ! more directly and easily. ! * Automatic joins in select queries. Using SQLObject *************** *** 133,142 **** CREATE TABLE person ( ! id INT PRIMARY KEY, first_name VARCHAR(100) NOT NULL, middle_initial CHAR(1), last_name VARCHAR(150) NOT NULL ); - CREATE SEQUENCE person_seq; The Python class will look like this:: --- 130,138 ---- CREATE TABLE person ( ! id SERIAL, first_name VARCHAR(100) NOT NULL, middle_initial CHAR(1), last_name VARCHAR(150) NOT NULL ); The Python class will look like this:: *************** *** 145,150 **** __connection__ = MySQLConnection( ! host='localhost', db='sqlobject_test', ! user='sqlobject_test', passwd='sqltest') class Person(SQLObject): --- 141,145 ---- __connection__ = MySQLConnection( ! host='localhost', db='test', user='test', passwd='') class Person(SQLObject): *************** *** 154,159 **** Col('lastName')] ! The special variable `__connection__` gives the access method for any ! classes in the module. You can also use the class variable `_connection` in the same way. The MySQL connection is shown, for Postgres use ``DBConnection.PostgresConnection(dsnString)``. --- 149,154 ---- Col('lastName')] ! The special variable `__connection__` gives the database connection ! for any classes in the module. You can also use the class variable `_connection` in the same way. The MySQL connection is shown, for Postgres use ``DBConnection.PostgresConnection(dsnString)``. *************** *** 171,197 **** use the keyword `dbName` analogously. If the primary key for the row isn't ``id``, you can use a _idName class attribute (like ! ``_idName='PersonID'``). ! You'll note that each column is a ``Col`` instance. This way you can give extra information about the column -- the first argument is always the name of the column, but you can give default values (for when new instances are created) and indicate it is a foreign key to ! another class/table. More options may be added later (perhaps type ! checking, for instance). ! SQLObject differs from most other systems in that it currently doesn't ! do any type checking. It is assumed that the database does this -- ! the database also usually does type coercion, so that the string ! ``"10"`` will be converted to the integer ``10`` if necessary. This ! should not present any security problem, as all values are properly ! quoted; but perhaps you'll find that bugs aren't caught that could ! be. You can still add extra constraints, if you wish (see ! `Overriding Column Attributes`_). You'll note that the ``id`` column is not given in the class ! definition. The ``id`` column must always exist (and be declared as ! ``INT PRIMARY KEY AUTO_INCREMENT`` in MySQL or ``INT PRIMARY KEY`` in ! Postgres with the accompanying sequence), and so there's no need to ! declare it. Using the Class --- 166,200 ---- use the keyword `dbName` analogously. If the primary key for the row isn't ``id``, you can use a _idName class attribute (like ! ``_idName='PersonID'``). An example using all of these:: ! class Person(SQLObject): ! ! _table = 'people' ! _id = 'peopleID' ! _columns = [Col('firstName', dbName='fname'), ! Col('middleInitial', dbName='MI'), ! Col('lastName', dbName='lname)] ! ! Each column is described with a ``Col`` instance. This way you can give extra information about the column -- the first argument is always the name of the column, but you can give default values (for when new instances are created) and indicate it is a foreign key to ! another class/table. To indicate the type of the column subclasses ! are provided. See `Automatic Schema Generation`_ for more (type ! information is not required, though). ! SQLObject doesn't require any type checking, and though some type ! information can be provided, it's not extensively used. It is assumed ! that the database does the type checking -- the database also usually ! does type coercion, so that the string ``"10"`` will be converted to ! the integer ``10`` if necessary. This should not present any security ! problem, as all values are properly quoted; but perhaps you'll find ! that bugs aren't caught that could be. You can still add extra ! constraints, if you wish (see `Overriding Column Attributes`_). You'll note that the ``id`` column is not given in the class ! definition, it is implied. For MySQL databases it should be defined ! as ``INT PRIMARY KEY AUTO_INCREMENT``, in Postgres ``SERIAL``, and in ! SQLite as ``INTEGER PRIMARY KEY``. Using the Class *************** *** 210,214 **** you would have gotten an error, as no default was given for these columns (``middleInitial`` has a default, so it will be set to ! ``NULL``, the equivalent of ``None``). When you create an object, it is immediately inserted into the --- 213,217 ---- you would have gotten an error, as no default was given for these columns (``middleInitial`` has a default, so it will be set to ! ``NULL``, the SQL equivalent of ``None``). When you create an object, it is immediately inserted into the *************** *** 237,244 **** unique -- there is only one ``Person`` instance of a particular id in memory at any one time (unless you are using transactions_). If you ! ask for more than one, you'll get back the same instance. This way ! you can be sure of a certain amount of consistency if you have ! multiple threads accessing the same data (though of course across ! processes there can be no sharing of an instance). To get an idea of what's happening behind the surface, I'll give the --- 240,248 ---- unique -- there is only one ``Person`` instance of a particular id in memory at any one time (unless you are using transactions_). If you ! ask for more than one person by a particular ID, you'll get back the ! same instance. This way you can be sure of a certain amount of ! consistency if you have multiple threads accessing the same data ! (though of course across processes there can be no sharing of an ! instance). To get an idea of what's happening behind the surface, I'll give the *************** *** 266,270 **** UPDATE person SET middle_initial='Q' WHERE id = 1; >>> p.middleInitial ! -- In this case, we've actually saved the info. 'Q' >>> p2 = Person(1) --- 270,275 ---- UPDATE person SET middle_initial='Q' WHERE id = 1; >>> p.middleInitial ! -- In this case, we've actually saved the info, so ! -- no query is made. 'Q' >>> p2 = Person(1) *************** *** 277,292 **** Hopefully you see that the SQL that gets sent is pretty clear and ! predictable. There are slight inefficiencies in inserting rows, but ! this is relatively less common than retrieval anyway. To view the SQL ! being sent, pass the keyword argument ``debug=1`` to MySQLConnection ! or PostgresConnection -- all SQL will be printed to the console. This ! can be reassuring. ! ! If you find yourself retrieving large numbers of these objects the ! performance penalty should not be too great because of the caching. ! However, if you iterate through them each and access them in sequence, ! then many SQL statements will be sent instead of a single statement ! that fetches all the rows. Maybe later that will be changed, but it's ! a performance problem for the time being. As a small optimization, instead of assigning each attribute --- 282,290 ---- Hopefully you see that the SQL that gets sent is pretty clear and ! predictable. There are some inefficiences; these should be worked out ! in time. To view the SQL being sent, pass the keyword argument ! ``debug=1`` to your connection object -- all SQL will be printed to ! the console. This can be reassuring, and I would encourage you to try ! it. As a small optimization, instead of assigning each attribute *************** *** 311,316 **** The list of columns is a list of `Col` objects. These objects don't ! have functionality, but give you a way to specify the column. In the ! future more manners of specification will probably be available. If you find yourself writing ``Col(colName)`` a lot, you might be --- 309,313 ---- The list of columns is a list of `Col` objects. These objects don't ! have functionality, but give you a way to specify the column. If you find yourself writing ``Col(colName)`` a lot, you might be *************** *** 319,324 **** be turned into a `Col` object for you. ! The first argument is always `name` -- the (Pythonic) name of the ! column. The other keyword arguments: `dbName`: --- 316,321 ---- be turned into a `Col` object for you. ! The first argument to `Col` is always `name` -- the (Pythonic) name of ! the column. The other keyword arguments: `dbName`: *************** *** 328,343 **** `default`: The default value for this column. Used when creating a new ! row. If you give a callable object or function, then the result ! of that call will be used. So you can give ``DateTime.now`` to ! make the default value be the current time. Or you can use ! ``func.NOW()`` to have the database use the ! ``NOW()`` function. If you don't give a default there will be an exception if this column isn't specified in the call to `new`. `foreignKey`: ! You can give a class name for `foreignKey`, which means that the ! column references another class (which is another row in another ! table). The column name should end with ``ID``, and the database ! column is expected to end with ``_id``. This will create another ! method in your class. For instance, if the ``personID`` column points to the ``Person`` --- 325,341 ---- `default`: The default value for this column. Used when creating a new ! row. If you give a callable object or function, then on object ! creation the function will be called, and the return value will ! be used. So you can give ``DateTime.now`` to make the default ! value be the current time. Or you can use ! ``SQLBuilder.func.NOW()`` to have the database use the ``NOW()`` ! function internally. If you don't give a default there will be an exception if this column isn't specified in the call to `new`. `foreignKey`: ! You can give a class name (as a string) for `foreignKey`, which ! means that the column references another class (which is another ! row in another table). The column name should end with ``ID``, ! and the database column is expected to end with ``_id``. This ! will create another method in your class. For instance, if the ``personID`` column points to the ``Person`` *************** *** 346,350 **** corresponding ``Person`` instance. ! Pass a *string* with `foreignKey`, not the actual class. `alternateID`: This boolean (default False) indicates if the column can be used --- 344,349 ---- corresponding ``Person`` instance. ! Pass a *string* with `foreignKey`, not the actual class. This ! avoids circular dependencies. `alternateID`: This boolean (default False) indicates if the column can be used *************** *** 352,356 **** class method will be added, like ``byUsername`` which will return that object. User `alternateMethodName` if you don't like the ! ``by*`` algorithm (e.g. ``alternateMethodName="username"``). The column should be declared ``UNIQUE`` in your table schema. --- 351,355 ---- class method will be added, like ``byUsername`` which will return that object. User `alternateMethodName` if you don't like the ! ``by*`` name (e.g. ``alternateMethodName="username"``). The column should be declared ``UNIQUE`` in your table schema. *************** *** 365,369 **** The connection object to use, from `DBConnection`. You can also set the variable `__connection__` in the enclosing module and ! it will be picked up. `_table`: The database name of the table for this class. If you don't give --- 364,369 ---- The connection object to use, from `DBConnection`. You can also set the variable `__connection__` in the enclosing module and ! it will be picked up. You can also pass a connection object in ! at instance creation time, as described in transactions_. `_table`: The database name of the table for this class. If you don't give *************** *** 379,382 **** --- 379,384 ---- then this is probably the only way to do so. You should also use it with transactions_ (it is not implied). + `_idName`: + The name of the primary key column (default ``id``). Relations Between Classes/Tables *************** *** 418,423 **** This will create another attribute ``person``, which will retrieve a ``Person`` object, while ``personID`` will still retrieve the integer ! ID. We use a string instead of a class here because circular ! dependencies will kill us otherwise. We also add an attribute `_joins` to ``Person``. This is a list of --- 420,424 ---- This will create another attribute ``person``, which will retrieve a ``Person`` object, while ``personID`` will still retrieve the integer ! ID. We also add an attribute `_joins` to ``Person``. This is a list of *************** *** 434,437 **** --- 435,440 ---- method. + .. _Many-to-Many: + Relations: Many-to-Many ~~~~~~~~~~~~~~~~~~~~~~~ *************** *** 541,544 **** --- 544,557 ---- selecting is always assumed to be included, of course. + You can use the keyword arguments `orderBy` and `groupBy` to create + ``ORDER BY`` and ``GROUP BY`` in the select statements: `orderBy` + takes a string, which should be the *database* name of the column, or + a column in the form ``Person.q.firstName``; `groupBy` is similar. + Both accept lists or tuples of arguments. + + You can use the special class variable `_defaultOrder` to give a + default ordering for all selects. To get an unordered result when + `_defaultOrder` is used, use ``orderBy=None``. + Select results are generators, which are lazily evaluated. So the SQL is only executed when you iterate over the select results, or if you *************** *** 552,557 **** the end of the SQL query. If the slice cannot be performed in the SQL (e.g., peeps[:-10]), then the select is executed, and the slice is ! performed on the list. This will only happen when you use negative ! indexes. You can get the length of the result without executing the full SQL. --- 565,570 ---- the end of the SQL query. If the slice cannot be performed in the SQL (e.g., peeps[:-10]), then the select is executed, and the slice is ! performed on the list of results. This will only happen when you use ! negative indexes. You can get the length of the result without executing the full SQL. *************** *** 567,572 **** While we haven't done so in the examples, you can include your own ! functionality in the object in the class definition. Including ! methods should be obvious enough (just define them). Initializing the Objects --- 580,586 ---- While we haven't done so in the examples, you can include your own ! methods in the class definition. Including methods should be obvious ! enough (just define them), but there are some other details to be ! aware of. Initializing the Objects *************** *** 575,580 **** With new-style classes, `__init__` is called everytime the class is called. That means it's called when an object is just fetched from ! the cache. That's useless in most cases, so it's better to use the ! `_init` method, which is only called once in an objects life (with one argument -- the object's ID). --- 589,594 ---- With new-style classes, `__init__` is called everytime the class is called. That means it's called when an object is just fetched from ! the cache. That's useless in most cases, so instead we use a `_init` ! method, which is only called once in an object's life (with one argument -- the object's ID). *************** *** 633,645 **** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ! It's a little complicated, though, if you want to figure out how to ! override the behavior of an attribute. For instance, imagine there's ! special code you want to run whenever someone's name changes -- you ! could make a subclass, and then use ``Person.__setattr__(self, ! 'lastName', value)`` to actually do the deed -- but that's obviously ! very awkward. SQLObject creates methods like ``_set_lastName`` for ! each of your columns (but no ``_del_`` or ``_doc_``), but again you ! can't use this, since there's no superclass to reference, and you want ! to override that ``_set_lastName`` method yourself. To deal with this, SQLObject creates two methods for each getter and --- 647,659 ---- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ! It's a little more complicated if you want to override the behavior of ! an attribute. For instance, imagine there's special code you want to ! run whenever someone's name changes -- you could make a subclass, and ! then use ``Person.__setattr__(self, 'lastName', value)`` to actually ! do the deed -- but that's obviously very awkward. SQLObject creates ! methods like ``_set_lastName`` for each of your columns (but no ! ``_del_`` or ``_doc_``), but again you can't use this, since there's ! no superclass to reference, and you want to override that ! ``_set_lastName`` method yourself. To deal with this, SQLObject creates two methods for each getter and *************** *** 684,693 **** then formatted the number into a nice string on the way out. This is one disadvantage of making actual work look like simple attribute ! access. Hopefully people will get used to this sort of thing, though. Transactions ------------ ! Transaction support for SQLObject is still a little vague. Transactions can be used like:: --- 698,707 ---- then formatted the number into a nice string on the way out. This is one disadvantage of making actual work look like simple attribute ! access. Transactions ------------ ! Transaction support in SQLObject is left to the database. Transactions can be used like:: *************** *** 714,737 **** ---------------------------------- ! The `DBConnection` module currently has three classes, `MySQLConnection`, ! `PostgresConnection`, and `SQLiteConnection`. `MySQLConnection` takes the keyword arguments `host`, `db`, `user`, and `passwd`, just like `MySQLdb.connect` does. `PostgresConnection` takes a single connection string, like ``"dbname=something user=some_user"``, just like `psycopg.connect`. ! `SQLiteConnection` takes the a single connection string. ! ! You can pass the keyword argument `debug` to either connector. If set ! to true, then any SQL sent to the database will also be printed to the ! console. SQLite ! ------ ! SQLite doesn't support a great deal of concurrency. For instance, say ! you want to delete a bunch of rows:: for p in Person.select(Person.q.firstName == 'Bob'): --- 728,775 ---- ---------------------------------- ! The `DBConnection` module currently has four external classes, ! `MySQLConnection`, `PostgresConnection`, `SQLiteConnection`, ! and `DBMConnection`. ! ! You can pass the keyword argument `debug` to any connector. If set to ! true, then any SQL sent to the database will also be printed to the ! console. ! ! MySQL ! ~~~~~ `MySQLConnection` takes the keyword arguments `host`, `db`, `user`, and `passwd`, just like `MySQLdb.connect` does. + MySQLConnection supports all the features, though MySQL does not + support transactions_. + + Postgres + ~~~~~~~~ + `PostgresConnection` takes a single connection string, like ``"dbname=something user=some_user"``, just like `psycopg.connect`. + You can also use the same keyword arguments as for `MySQLConnection`, + and a dsn string will be constructed. ! PostgresConnection supports transactions and all other features except ! `automatic class generation`_. SQLite ! ~~~~~~ ! `SQLiteConnection` takes the a single string, which is the path to the ! database file. ! ! SQLite puts all data into one file, with a journal file that is opened ! in the same directory during operation (the file is deleted when the ! program quits). SQLite does not restrict the types you can put in a ! column -- strings can go in integer columns, dates in integers, etc. ! ! SQLiteConnection doesn't support `automatic class generation`_ and ! SQLite does not support `runtime column changes`_ or transactions_. ! ! SQLite doesn't support much concurrency. For instance, say you want ! to delete a bunch of rows:: for p in Person.select(Person.q.firstName == 'Bob'): *************** *** 740,748 **** Because the ``select`` is an iterator, and keeps a connection open, when you do the ``p.destroy()`` you'll get an exception, because ! SQLite doesn't support this concurrency. Instead, do:: for p in list(Person.select(Person.q.firstName == 'Bob')): p.destroy() Exported Symbols ================ --- 778,880 ---- Because the ``select`` is an iterator, and keeps a connection open, when you do the ``p.destroy()`` you'll get an exception, because ! SQLite doesn't support two open connections. Instead, do:: for p in list(Person.select(Person.q.firstName == 'Bob')): p.destroy() + DBMConnection + ~~~~~~~~~~~~~ + + `DBMConnection` takes a single string, which is the path to a + directory in which to store the database. + + DBMConnection uses flat hash databases to store all the data. These + databases are created by the standard `anydbm` module. It's something + of an experiment, and things like safety under concurrent access + (multithreaded or multiprocess) should not be expected. `groupBy` is + also not supported, though select queries, ordering, and slices are + supported. + + DBMConnection allows any kind of objects to be put in columns -- all + values are pickled, and so only normal pickling restrictions apply. + + DBMConnection does not support `automatic class generation` or + transactions_. + + Automatic Schema Generation + --------------------------- + + All the connections support creating and droping tables based on the + class definition. First you have to prepare your class definition, + which means including type information in your columns (though + DBMConnection_ do not require or use type information). + + Columns Types + ~~~~~~~~~~~~~ + + A column type is indicated by using a subclass of `Col`: + + `StringCol`: + StringCol represents ``CHAR``, ``VARCHAR``, and ``TEXT``. + If you pass no `length` keyword argument, then ``TEXT`` will + be assumed. If indicate ``varchar=False`` then ``CHAR`` will + be used, otherwise ``VARCHAR`` is the default. + `IntCol`: + The ``INT`` type. + `FloatCol`: + The ``FLOAT`` type. + `KeyCol`: + A foreign key. Just like `Col` right now... the interface will + be trimmed down eventually. + `EnumCol`: + A MySQL ``ENUM``, i.e., one of a finite number of strings. + For other databases this will be a ``VARCHAR``. + `DateTimeCol`: + ``DATETIME``. + + Creating and Dropping Tables + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + To create a database call `createTable`. It takes two arguments: + + `ifNotExists`: + If the table already exists, then don't try to create it. Default + False. + `createJoinTables`: + If you used Many-to-Many_ relations, then the intermediate tables + will be created (but only for one of the two involved classes). + Default True. + + `dropTable` takes arguments `ifExists` and `dropJoinTables`, + self-explanatory. + + Automatic Class Generation + --------------------------- + + *Currently this is only available for with MySQL_* + + SQLObject can read the table description from the database, and fill + in the class columns (as would normally be described in the `_columns` + attribute). Do this like:: + + class Person(SQLObject): + + _fromDatabase = True + + You can still specify columns (in `_columns`), and only missing + columns will be added. + + Runtime Column Changes + ---------------------- + + *SQLite does not support this feature* + + You can add and remove columns to your class at runtime. Such changes + will effect all instances, since changes are made inplace to the + class. There are two methods, `addColumn` and `delColumn`, both of + which take a `Col` object (or subclass) as an argument. There's also + an option argument `changeSchema` which, if True, will add or drop the + column from the database (typically with an ``ALTER`` command). + Exported Symbols ================ *************** *** 759,768 **** * `RelatedJoin` * `getID` ! * `getObject`. From `DBConnection`: * `MySQLConnection` ! * `PostgresConnection`. From `SQLBuilder`: --- 891,902 ---- * `RelatedJoin` * `getID` ! * `getObject` From `DBConnection`: * `MySQLConnection` ! * `PostgresConnection` ! * `SQLiteConnection` ! * `DBMConnection` From `SQLBuilder`: *************** *** 775,779 **** * `CONTAINSSTRING` * `const` ! * `func`. For more information on SQLBuilder, read the `SQLBuilder --- 909,913 ---- * `CONTAINSSTRING` * `const` ! * `func` For more information on SQLBuilder, read the `SQLBuilder |