This package provides SQLAlchemy integration in cone.app and basic
application nodes for publishing SQLAlchemy models.
Installation
Include cone.sql to install dependencies in your application’s
setup.py.
Create Model and Nodes
Define the SQLAlchemy model.
from cone.sql import SQLBase
from cone.sql.model import GUID
from sqlalchemy import Column
from sqlalchemy import String
class MyRecord(SQLBase):
__tablename__ = 'my_table'
uid_key = Column(GUID, primary_key=True)
field = Column(String)
Define an application node which represents the SQL row and uses the SQLAlchemy
model. The class holds a reference to the related SQLAlchemy model.
from cone.sql.model import SQLRowNode
class MyNode(SQLRowNode):
record_class = MyRecord
Define an application node which represents the table and acts as container for
the SQL row nodes. The class holds a reference to the related SQLAlchemy model
and the related SQLRowNode.
from cone.sql.model import SQLTableNode
class MyContainer(SQLTableNode):
record_class = MyRecord
child_factory = MyNode
Primary key handling
The node name maps to the primary key of the SQLAlchemy model (currenly no
multiple primary keys are supported). Node names are converted to the
primary key data type automatically. The conversion factories are defined at
SQLTableNode.data_type_converters which can be extended by more data types
if needed.
>>> SQLTableNode.data_type_converters
{<class 'sqlalchemy.sql.sqltypes.String'>: <type 'unicode'>,
<class 'cone.sql.model.GUID'>: <class 'uuid.UUID'>,
<class 'sqlalchemy.sql.sqltypes.Integer'>: <type 'int'>}
Integrate to the Application Model
In order to publish a SQL table node, the table node must be hooked up to the
application model. To hook up the at root level, register it as entry.
import cone.app
cone.app.register_entry('container', MyContainer)
Session setup handlers
There exists a sql_session_setup decorator which can be used to perform
session setup tasks like registering SQLAlchemy event listeners.
from cone.sql import sql_session_setup
from sqlalchemy import event
def after_flush(session, flush_context):
"""Do something after flush.
"""
@sql_session_setup
def bind_session_listener(session):
"""SQL session setup callback.
"""
event.listen(session, 'after_flush', after_flush)
Query the database
Querying the database is done via SQLAlchemy. If you are in a request/response
cycle, you should acquire the session from request via get_session and
perform arbitrary operations on it. By reading the session from request we ensure
the transaction manager to work properly if configured.
from cone.sql import get_session
session = get_session(request)
result = session.query(MyRecord).all()
If you need a session outside a request/response cycle you can create one by using
the session_factory.
from cone.sql import session_factory
session = session_factory()
result = session.query(MyRecord).all()
session.close()
Principal ACL’s
SQL based Principal ACL’s are implemented in cone.sql.acl. The related
table gets created as soon as you import from this module.
Using SQLPrincipalACL requires the model to implement node.interfaces.IUUID.
from cone.sql.acl import SQLPrincipalACL
from node.base import BaseNode
from node.interfaces import IUUID
from plumber import plumbing
from pyramid.security import Allow
from zope.interface import implementer
import uuid as uuid_module
@implementer(IUUID)
@plumbing(SQLPrincipalACL)
class SQLPrincipalACLNode(BaseNode):
uuid = uuid_module.UUID('1a82fa87-08d6-4e48-8bc2-97ee5a52726d')
@property
def __acl__(self):
return [
(Allow, 'role:editor', ['edit']),
(Allow, 'role:manager', ['manage']),
]
User and Group Management
cone.sql.ugm contains an implementation of the UGM contracts defined at
node.ext.ugm.interfaces, using sql as backend storage:
+------------+
| Principal |
|(data: JSON)|
+------------+
^
|
+-----------------------------------------+
| |
| |
+------+ +-------+
| User | | Group |
+------+ +-------+
1 1
| |
| |
+-------------+ +-------------+
| |
n m
| |
+-----------------+
| GroupAssignment |
+-----------------+
Currently SQLite and PostgreSQL are supported and tested, other DBs must
be evaluated concerning their JSON capabilities since users and groups
store additional payload data in a JSON field which brings the flexibility
to store arbitrary data as a dict in the JSON field.
To activate SQL based UGM backend, it needs to be configured via the application
ini config file.:
ugm.backend = sql
sql.user_attrs = id, mail, fullname, portrait
sql.group_attrs = description
sql.binary_attrs = portrait
sql.log_auth = True
sql.user_expires_attr = expires
UGM users and groups are stored in the same database as defined at
sql.db.url in the config file.
UGM dedicated config options:
sql.user_attrs is a comma separated list of strings defining the
available user attributes stored in the user JSON data field.
sql.group_attrs is a comma separated list of strings defining the
available group attributes stored in the group JSON data field.
sql.binary_attrs is a comma separated list of strings defining the
attributes which are considered binary and get stored base 64 encoded in the
JSON data field of users and groups.
sql.log_auth defaults to False. If set, the first login timestamp will
be stored during the first authentication and latest login timestamp will be
updated for each successful authentication.
sql.user_expires_attr defaults to None. If set, user expiration is
enabled and the value given is the attribute name of the JSON data field
where the expiration timestamp gets stored.
Users and groups can be managed with cone.ugm. If activated,
sql.user_attrs and sql.group_attrs can be omitted, relevant information
gets extracted from the ugm.xml config file.
ugm.backend = sql
ugm.config = %(here)s/ugm.xml
sql.log_auth = True
cone.plugins =
cone.ugm
cone.sql
0.7 (2022-12-05)
Implement expires and expired on cone.sql.ugm.UserBehavior.
Extend cone.sql.ugm.UgmBehavior by user_expires_attr which
enables used expiration support.
[rnix]
Add TestSQLSessionFactory and set to cone.sql.session_factory in
SQLLayer.init_sql if not present.
[rnix, toalba]
0.6 (2022-10-06)
Remove usage of Nodespaces behavior.
[rnix]
Replace deprecated use of IStorage by IMappingStorage.
[rnix]
Replace deprecated use of Nodify by MappingNode.
[rnix]
Replace deprecated use of Adopt by MappingAdopt.
[rnix]
Replace deprecated use of NodeChildValidate by MappingConstraints.
[rnix]
Replace deprecated use of allow_non_node_children by child_constraints.
[rnix]
0.3 (2020-07-09)
SQL database URL setting key in ini file changed from cone.sql.db.url
to sql.db.url.
[rnix]
Add SQL based UGM implementation.
[zworkb, rnix]
Patch maker on cone.sql.session_factory if present in
cone.sql.testing.SQLLayer to ensure working session factory when running
tests.
[rnix]
0.2 (2020-05-30)
Introduce cone.sql.SQLSessionFactory. Gets instanciated at application
startup as singleton at cone.sql.session_factory.
[rnix]
SQL database URL setting key in ini file changed from cone.sql.dbinit.url
to cone.sql.db.url.
[rnix]
SQL database URL definition is only required once in the app section of
the ini file. sqlalchemy.url can be removed from session filter.
[rnix]
Add SQL based principal ACL support.
[rnix]
Python 3 compatibility.
[rnix]
Fix hex formatting in cone.sql.model.GUID.process_bind_param.
[rnix]
Register SQL session to transaction manager with zope.sqlalchemy.register.
[rnix]
Use pyramid_tm instead of repoze.tm2. Disabled by default, must be
enabled explicitely via pyramid.includes.
[rnix]
Use pyramid_retry instead of repoze.retry. Disabled by default, must be
enabled explicitely via pyramid.includes.
[rnix]
Upgrade to cone.app 1.0b1.
[rnix]
0.1 (2017-03-28)
License
Copyright (c) 2017-2021, BlueDynamics Alliance, Austria
Copyright (c) 2021-2022, Cone Contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.