= S3Model = [[TOC]] See also: - [wiki:S3/S3Model/ComponentResources Component Resources] - [wiki:S3/S3Model/SuperEntities Super-Entities] == Purpose == The {{{S3Model}}} class defines the framework for data models in Eden. It extends the ''web2py'' concept by: - implicit and lazy model loading - an extensible, per-table configuration pattern - a meta-model for projected entities (the so-called "resource component model") - a meta-model for multi-table keys (the so-called "super-entity model") Data models can be implemented as subclasses of S3Model, and then loaded on demand - with automatic resolution of cross-model dependencies. This saves processing time as it will always only load those models which are actually needed to process the request. == Defining Models == === Modules === S3 data models reside in {{{modules/s3db}}}. The file name of each ''Python module'' in {{{modules/s3db}}} corresponds to the ''Eden module'' prefix. All names with this prefix will be looked up from this file. '''Example:''' - ''Tablename'': org_office => ''Module Prefix'': "org" => ''Looked up from'': modules/s3db/org.py All S3 data models need to be imported in models/00_tables.py: {{{#!python import s3db.assess import s3db.asset import s3db.auth import s3db.cap ... }}} Every Python module in modules/s3db must have an {{{__all__}}} statement declaring the classes and functions to be imported: {{{#!python __all__ = ["S3DeploymentModel", "S3DeploymentAlertModel", "deploy_rheader", "deploy_apply", "deploy_alert_select_recipients", "deploy_response_select_mission", ] }}} '''Important:''' Undeclared classes or functions are not available to the model loader! All names in {{{__all__}}} starting with the module prefix (e.g. {{{deploy_}}}) can be accessed globally with {{{current.s3db.}}} (e.g. {{{current.s3db.deploy_apply}}}), without need to import them explicitly. The {{{modules/s3db/skeleton.py}}} module is a well-commented skeleton module to explain how things should look like inside an S3 model. === Model Classes === Every data model is defined as a subclass of S3Model: {{{#!python class S3DeploymentModel(S3Model): }}} ==== Names ==== All names from the model which shall be globally accessible (i.e. tables, functions, variables, classes) must be declared in the names-variable: {{{#!python class S3DeploymentModel(S3Model): names = ["deploy_event_type", "deploy_mission", "deploy_mission_id", "deploy_mission_document", "deploy_application", "deploy_assignment", "deploy_assignment_appraisal", "deploy_assignment_experience", ] }}} These names can then be accessed via {{{current.s3db.}}} (e.g. {{{current.s3db.deploy_mission_id}}}). '''Important:''' All table names and names which are returned from a model class '''must''' use the module prefix (otherwise they can't be found). ==== model() function ==== Every {{{S3Model}}} subclass '''must''' implement the model() function. This function defines all tables, functions and variables of the model: {{{#!python class S3DeploymentModel(S3Model): ... def model(self): }}} To define a table, the model() function must use {{{self.define_table}}} (instead of {{{current.db.define_table}}}): {{{#!python def model(self): tablename = "deploy_mission" table = self.define_table(tablename, ...) }}} The model function '''must''' return a dict with the definitions of all names as declared in the {{{names}}} class-variable ('''except''' table names): {{{#!python class MyModel(S3Model): names = ["my_function", "my_variable"] def model(self): my_variable = "example" return dict(my_own_function = self.my_function my_variable = my_variable ) @staticmethod def my function(): ... return }}} Ideally, custom functions in model classes which are returned from model() should be declared @staticmethod or @classmethod to allow the instance to be garbage-collected (i.e. release the thread-global pointer to the instance from current.s3db). ==== defaults() function ==== Every model class ''should'' define a {{{defaults()}}} function which returns safe defaults for the declared names in case the Eden module has been disabled per deployment-settings. This is particularly important for re-usable fields holding foreign keys to tables defined in this model: {{{#!python class S3DeploymentModel(S3Model): names = [... "deploy_mission_id", ] def model(self): ... mission_id = S3ReusableField("mission_id", table, ... ) return dict(deploy_mission_id = mission_id) def defaults(self): # Module disabled, define a safe default for "mission_id": mission_id = S3ReusableField("mission_id", "integer", readable=False, writable=False) return dict(deploy_mission_id = mission_id) }}} ==== Utility functions ==== The {{{S3Model}}} base class implements a number of useful helper functions to implement models, among others: - {{{super_entity}}} and {{{super_link}}} to define or reference super entities - {{{add_component}}} to define resource components - {{{configure}}} to define table configuration settings These functions should not be overwritten in the subclass. == Concepts == === Resources === ''- tbw'' === Resource Components === ''- tbw'' === Resource Configuration === ''- tbw'' === Resource Methods === ''- tbw'' === Super-Entities === ''- tbw'' ---- DeveloperGuidelines