Under the hood

A lot of things happen when a Camelot application starts up. In this section we give a brief overview of those which might need to be adapted for more complex applications

Global settings

Camelot has a global settings object of which the attributes are used throughout Camelot whenever a piece of global configuration is needed. Examples of such global configuration are the location of the database and the location of stored files and images. To access the global configuration, simply import the object

from camelot.core.conf import settings
print settings.CAMELOT_MEDIA_ROOT()

To manipulate the global configuration, create a class with the needed attributes and methods and append it to the global configuration :

class MySettings( SimpleSettings ):

    # add an ENGINE or a CAMELOT_MEDIA_ROOT method here to connect
    # to another database or change the location where files are stored
    #
    # def ENGINE( self ):
    #     from sqlalchemy import create_engine
    #     return create_engine( 'postgresql://user:passwd@127.0.0.1/database' )
    
    def setup_model( self ):
        """This function will be called at application startup, it is used to 
        setup the model"""
        from camelot.core.sql import metadata
        from camelot.core.orm import setup_all
        metadata.bind = self.ENGINE()
        import camelot.model.authentication
        import camelot.model.i18n
        import camelot.model.memento
        import myapplication.model
        setup_all()
        metadata.create_all()

my_settings = MySettings( 'My Company', 'My Application' ) 
settings.append( my_settings )

The settings object should have a method named ENGINE, uses the create_engine SQLAlchemy function to create a connection to the database. Camelot provides a default sqlite URI scheme. But you can set your own.

    def ENGINE( self ):
        from sqlalchemy import create_engine
        return create_engine(u'sqlite:///%s/%s'%( self._local_folder,
                                                  self.data ) )

Older versions of Camelot looked for a settings module on sys.path to look for the global configuration. This approach is still supported.

Setting up the ORM

When the application starts up, the setup_model method of the Settings class is called. In this function, all model files should be imported, to make sure the model has been completely setup. The importing of these files is enough to define the mapping between objects and tables.

    def setup_model( self ):
        """This function will be called at application startup, it is used to 
        setup the model"""
        from camelot.core.sql import metadata
        from camelot.core.orm import setup_all
        metadata.bind = self.ENGINE()
        import camelot.model.authentication
        import camelot.model.i18n
        import camelot.model.memento
        import myapplication.model
        setup_all()
        metadata.create_all()

The import of these model definitions should happen before the call to create_all to make sure all models are known before the tables are created.

Setting up the Database

Engine

The Settings class should contain a method named ENGINE that returns a connection to the database. Whenever a connection to the database is needed, this method will be called. The camelot.core.conf.SimpleSettings has a default ENGINE method that returns an SQLite database in a user directory.

Metadata

SQLAlchemy defines the MetaData class. A MetaData object contains all the information about a database schema, such as Tables, Columns, Foreign keys, etc. The camelot.core.sql contains the singleton metadata object which is the default MetaData object used by Camelot. In the setup_model function, this metadata object is bound to the database engine.

class MySettings( SimpleSettings ):

    # add an ENGINE or a CAMELOT_MEDIA_ROOT method here to connect
    # to another database or change the location where files are stored
    #
    # def ENGINE( self ):
    #     from sqlalchemy import create_engine
    #     return create_engine( 'postgresql://user:passwd@127.0.0.1/database' )
    
    def setup_model( self ):
        """This function will be called at application startup, it is used to 
        setup the model"""
        from camelot.core.sql import metadata
        from camelot.core.orm import setup_all
        metadata.bind = self.ENGINE()
        import camelot.model.authentication
        import camelot.model.i18n
        import camelot.model.memento
        import myapplication.model
        setup_all()
        metadata.create_all()

In case an application works with multiple database schemas in parallel, this step needs to be adapted.

Creating the tables

By simply importing the modules which contain parts of the model definition, the needed table information is added to the metadata object. At the end of the setup_model function, the create_all method is called on the metadata, which will create the tables in the database if they don’t exist yet.

class MySettings( SimpleSettings ):

    # add an ENGINE or a CAMELOT_MEDIA_ROOT method here to connect
    # to another database or change the location where files are stored
    #
    # def ENGINE( self ):
    #     from sqlalchemy import create_engine
    #     return create_engine( 'postgresql://user:passwd@127.0.0.1/database' )
    
    def setup_model( self ):
        """This function will be called at application startup, it is used to 
        setup the model"""
        from camelot.core.sql import metadata
        from camelot.core.orm import setup_all
        metadata.bind = self.ENGINE()
        import camelot.model.authentication
        import camelot.model.i18n
        import camelot.model.memento
        import myapplication.model
        setup_all()
        metadata.create_all()

Working without the default model

Camelot comes with a default model for Persons, Organizations, History tracking, etc.

To turn these on or off, simply add or remove the import statements of those modules from the setup_model method in the Settings class.

Transactions

Transactions in Camelot can be used just as in normal SQLAlchemy. This means that inside a camelot.admin.action.base.Action.model_run() method a transaction can be started and committed

with model_context.session.begin()
    ...do some modifications...

More information on the transactional behavior of the session can be found in the SQLAlchemy documentation ...

Using Camelot without the GUI

Often a Camelot application also has a non GUI part, like batch scripts, server side scripts, etc.

It is of course perfectly possible to reuse the whole model definition in those non GUI parts. The easiest way to do so is to leave the Camelot GUI application as it is and then in the non GUI script, initialize the model first

from camelot.core.conf import settings
settings.setup_model()

From that point, all model manipulations can be done. Access to the single session can be obtained from anywhere through the Session factory method

from camelot.core.orm import Session
session = Session()

After the manipulations to the model have been done, they can be flushed to the db

session.flush()