{ "info": { "author": "Juergen Kartnaller and the Zope Community", "author_email": "zope3-dev@zope.org", "bugtrack_url": null, "classifiers": [], "description": "=====================\nSQLAlchemy and Zope 3\n=====================\n\n\"z3c.zalchemy\" integrates the object relational mapper SQLAlchemy into Zope 3\nas SQLOS integrates sqlobject.\n\nzalchemy tries to do its best not to interfere with the standard SQLAlchemy\nusage. The main part of zalchemy is the integration of the SQLAlchemy\ntransaction into the Zope transaction. This is solved by using a data manager\nwhich joins the Zope transaction for every newly created thread.\n\nzalchemy uses the two phase commit system from zope.\n\nThis is how the two phase commit is used in zope.\n\n 1. tpc_begin(txn)\n 2. commit(txn)\n 3. tpc_vote(txn)\n 4. tpc_finish(txn)\n\n - commit does a session.flush() which actually executes all sql statements.\n - tpc_finish() does a transaction.commit() in the sqlalchemy transaction\n - tpc_abort() does a transaction.rollback() in the sqlalchemy transaction\n\nIf commit fails or another DataManager fails data is not commited to the\ndatabase.\n\n\nImportant\n=========\n\nZope uses the transaction module to handle transactions. zalchemy plugs into\nthis mechanism and uses its own data manager to use Zope's transaction module.\n\nzalchemy provides the method z3c.zalchemy.getSession to obtain a SQLAlchemy\nsession object. This method makes sure the session is connected to Zope's\ntransactions.\n\nNever get a session directly from SQLAlchemy!\n\nIt is also important to never store an instance of a session. Always directly\nuse z3c.zalchemy.getSession. This is necessary because you never know when\na transaction is commited. A commit always invalidates the current session.\nA new call to getSession makes sure a new session is created.\n\n\nzalchemy Class Implementation\n=============================\n\nThere is no difference between the usage of SQLAlchemy together with Zope.\n\nzalchemy provides a transparent way to connect a table to a database (engine).\n\nA SQLAlchemy engine is represented as a utility:\n\n >>> from z3c.zalchemy.datamanager import AlchemyEngineUtility\n >>> engineUtility = AlchemyEngineUtility(\n ... 'database',\n ... 'sqlite:///%s'%dbFilename,\n ... echo=False,\n ... )\n\nWe create our table as a normal SQLAlchemy table. The important thing\nhere is, that the metadata from zalchemy must be used. Please note that you\nneed to call z3c.zalchemy.metadata.\n\n >>> import sqlalchemy\n >>> import z3c.zalchemy\n >>> table3 = sqlalchemy.Table(\n ... 'table3',\n ... z3c.zalchemy.metadata(),\n ... sqlalchemy.Column('id', sqlalchemy.Integer,\n ... sqlalchemy.Sequence('atable_id'), primary_key=True),\n ... sqlalchemy.Column('value', sqlalchemy.Integer),\n ... )\n\nDefine a simple class which will be used later to map to a database table.\n\n >>> class A(object):\n ... pass\n\nNow we map the table to our class.\n\n >>> sqlalchemy.mapper(A, table3) is not None\n True\n\nTo let zalchemy do its work we need to register our database utility.\n\n >>> from z3c.zalchemy.interfaces import IAlchemyEngineUtility\n >>> from zope.component import provideUtility\n >>> provideUtility(engineUtility, IAlchemyEngineUtility)\n\nTables can be created without an open transaction or session.\nIf no session is created then the table creation is deferred to the next\ncall to zalchemy.getSession.\n\n >>> z3c.zalchemy.createTable('table3', '')\n\nzalchemy automatically coordinates Zope's transaction manager with\nSQLAlchemy's sessions. All mapped classes are automatically associated with\nthread-local session, which in turn is automatically connected to a special\ndata manager that coordinates with Zope's transactions.\n\n >>> a = A()\n >>> a.value = 1\n\nCommitting a transaction will automatically trigger a flush and clear the\nsession.\n\n >>> import transaction\n >>> transaction.commit()\n\nNow let's try to get the object back in a new transaction (we're in a new\ntransaction already because the old transaction was committed):\n\n >>> from z3c.zalchemy.datamanager import getSession as session\n >>> a = session().get(A, 1)\n >>> a.value\n 1\n\n >>> transaction.commit()\n\n\nMultiple databases\n------------------\n\nThe above example assumed that there is only one database. The database\nengine was registered as an unnamed utility. The unnamed utility is always\nthe default database for new sessions.\n\nThis automatically assigns every table to the default engine.\n\nFor multiple databases tables can be assigned to engines.\n\nWe create a new database engine :\n\n >>> engine2Util = AlchemyEngineUtility(\n ... 'engine2',\n ... 'sqlite:///%s'%dbFilename2,\n ... echo=False,\n ... )\n\nBecause there is already a default engine we must provide a name for the\nnew engine.\n\n >>> provideUtility(engine2Util, IAlchemyEngineUtility, name='engine2')\n\n >>> bTable = sqlalchemy.Table(\n ... 'bTable',\n ... z3c.zalchemy.metadata(),\n ... sqlalchemy.Column('id', sqlalchemy.Integer,\n ... sqlalchemy.Sequence('btable_id'), primary_key=True),\n ... sqlalchemy.Column('value', sqlalchemy.String),\n ... )\n\n >>> class B(object):\n ... pass\n >>> B.mapper = sqlalchemy.mapper(B, bTable)\n\nAssign bTable to the new engine and create the table.\nThis time we do it inside of a session.\n\n >>> z3c.zalchemy.assignTable('bTable', 'engine2')\n >>> z3c.zalchemy.createTable('bTable', 'engine2')\n\n >>> b = B()\n >>> b.value = 'b1'\n\n >>> a = A()\n >>> a.value = 321\n\n >>> transaction.commit()\n\n >>> a = session().get(A, 1)\n >>> b = session().get(B, 1)\n >>> str(b.value)\n 'b1'\n\n >>> transaction.commit()\n\nIt is also possible to assign a class to a database :\n\n >>> class Aa(object):\n ... pass\n >>> sqlalchemy.mapper(Aa, table3) is not None\n True\n\nNow we can assign the class to the engine :\n\n >>> z3c.zalchemy.assignClass(Aa, 'engine2')\n\nThe problem is now that we do not have the table in 'engine2'.\nWe can use an additional parameter to createTable :\n\n >>> z3c.zalchemy.createTable('table3', 'engine2')\n\n >>> aa = Aa()\n >>> aa.value = 100\n\n >>> transaction.commit()\n\n\nTables With The Same Name In Different Databases\n------------------------------------------------\n\nIF we have two databases containing tables with the same name but with a\ndifferent structure we need to assign a table explicitely to a database. This\nmust be done by requesting metadata for a specific engine.\n\n >>> b2Table = sqlalchemy.Table(\n ... 'bTable',\n ... z3c.zalchemy.metadata('b2Engine'),\n ... sqlalchemy.Column('id', sqlalchemy.Integer,\n ... sqlalchemy.Sequence('btable_id'), primary_key=True),\n ... sqlalchemy.Column('b2value', sqlalchemy.String),\n ... )\n\nWe can now request the table by providing the engine.\n\n >>> z3c.zalchemy.metadata.getTable('b2Engine', 'bTable', True)\n Table('bTable',...\n\nIf we have specified a table for the 'default' engine then we can request\n'bTable' for 'b2Engine' with a fallback to the default engine.\n\n >>> z3c.zalchemy.metadata.getTable('b2Engine', 'table3', True)\n Table('table3',...\n\n\n\n=======\nChanges\n=======\n\n0.2.2 (2011-08-05)\n==================\n\n - Fix packaging problem: Declare namespace package 'z3c'.\n\n0.2.1 - 2007-11-13 \n==================\n\n - Conflict detection did not work with savepoints.\n\n\n0.2 - 2007-09-27\n================\n\n - Added a way to register database specific adapters for conflict detection\n and possible re-do by the publisher.\n\n - Using the threadlocal strategy of sqlalchemy instead of doing that\n ourselves.\n\n - Added support for optimistic savepoints. This can be used, similarly to\n what happens with ZODB, to flush intermediary work without committing.\n\n - Provide a tighter integration with Zope's transaction mechanism. Sessions\n are now automatically associated with new objects. We rely on SQLAlchemy's\n SessionContext object which hands out a session for each thread. Your code\n rarely should never have to call `session.save(object)` now.\n\n One incompatible change was introduced: You can not call `getSession`\n before registering an (unnamed) engine utility first. Doing so will raise\n a ValueError.\n\n\n0.1.1 - 2007-06-27\n==================\n\n - Fixed a failing test in TRANSACTION.txt where an exception demonstrated a\n string being returned but it was a unicode string.\n\n\n0.1 - never released\n====================\n\n - This was supposed to be the first release, but we missed a broken test.\n See 0.1.1", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://pypi.python.org/pypi/z3c.sqlalchemy", "keywords": null, "license": "ZPL 2.1", "maintainer": null, "maintainer_email": null, "name": "z3c.zalchemy", "package_url": "https://pypi.org/project/z3c.zalchemy/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/z3c.zalchemy/", "project_urls": { "Download": "UNKNOWN", "Homepage": "http://pypi.python.org/pypi/z3c.sqlalchemy" }, "release_url": "https://pypi.org/project/z3c.zalchemy/0.2.2/", "requires_dist": null, "requires_python": null, "summary": "SQLAlchemy integration into Zope 3", "version": "0.2.2" }, "last_serial": 802130, "releases": { "0.1.1": [ { "comment_text": "", "digests": { "md5": "a228b6d112a3475ee1cb3f8199503e49", "sha256": "866bb873654fd2515d44a1074db3351f6149ca6fa24ac30d2c7b72ee91e1d5be" }, "downloads": -1, "filename": "z3c.zalchemy-0.1.1.tar.gz", "has_sig": false, "md5_digest": "a228b6d112a3475ee1cb3f8199503e49", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23597, "upload_time": "2007-06-27T14:25:38", "url": "https://files.pythonhosted.org/packages/ca/7c/43c26318fb99d7e54c77f6cf60252a735355b5d76cccea9dfb45315433af/z3c.zalchemy-0.1.1.tar.gz" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "bb849a9ccd13c86fea7706d9ee5c1eae", "sha256": "dc8bef21db8bcb0b199cb6ec6f35f3e4a8819fe294cf8afb5e8bbcb9b5ee6675" }, "downloads": -1, "filename": "z3c.zalchemy-0.2.tar.gz", "has_sig": true, "md5_digest": "bb849a9ccd13c86fea7706d9ee5c1eae", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24203, "upload_time": "2007-09-27T11:36:16", "url": "https://files.pythonhosted.org/packages/e8/15/348e16709e19ad7fd7f8a0687b394f23cfe101b62e31332612ea22fa1dcf/z3c.zalchemy-0.2.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "ff43a4205256afa5cdbba8a887a97b6f", "sha256": "4c35ff33e6ba00301fe3efbc24f12deab8b8764e35f32a6865a8ca501f25cb86" }, "downloads": -1, "filename": "z3c.zalchemy-0.2.1.tar.gz", "has_sig": false, "md5_digest": "ff43a4205256afa5cdbba8a887a97b6f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28981, "upload_time": "2007-11-13T08:54:55", "url": "https://files.pythonhosted.org/packages/a8/7e/8d03421e2e6e1d482d1455039580c53c0707275f6dcfc3894a31966cd10d/z3c.zalchemy-0.2.1.tar.gz" } ], "0.2.2": [ { "comment_text": "", "digests": { "md5": "4377616ae8864b7e03145e93f76606f7", "sha256": "c1bbab9f0f84c34d621800a2858257f78ff08b5400924154ff23ea39cd78d04b" }, "downloads": -1, "filename": "z3c.zalchemy-0.2.2.tar.gz", "has_sig": false, "md5_digest": "4377616ae8864b7e03145e93f76606f7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29628, "upload_time": "2011-08-05T11:28:45", "url": "https://files.pythonhosted.org/packages/c1/e2/68a40f171850c318be1628f34db1c7a2a05be8983f842eebef5fe6bca39a/z3c.zalchemy-0.2.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "4377616ae8864b7e03145e93f76606f7", "sha256": "c1bbab9f0f84c34d621800a2858257f78ff08b5400924154ff23ea39cd78d04b" }, "downloads": -1, "filename": "z3c.zalchemy-0.2.2.tar.gz", "has_sig": false, "md5_digest": "4377616ae8864b7e03145e93f76606f7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29628, "upload_time": "2011-08-05T11:28:45", "url": "https://files.pythonhosted.org/packages/c1/e2/68a40f171850c318be1628f34db1c7a2a05be8983f842eebef5fe6bca39a/z3c.zalchemy-0.2.2.tar.gz" } ] }