root / elixir / trunk / elixir / options.py @ 267

Revision 267, 10.3 kB (checked in by ged, 7 years ago)
  • cleanup class attributes (in the attributes-based syntax) after the
    property is attached to its entity, so that SQLAlchemy is not confused.
    Only caused problem in the case of single inheritance and when omitting
    some values. See SA ticket #866.
  • some PEP8 fixes
Line 
1'''
2This module provides support for defining several options on your Elixir
3entities.  There are three different kinds of options that can be set
4up, and for this there are three different statements: using_options_,
5using_table_options_ and using_mapper_options_.
6
7Alternatively, these options can be set on all Elixir entities by modifying
8the `options_defaults` dictionary before defining any entity.
9
10`using_options`
11---------------
12The 'using_options' DSL statement allows you to set up some additional
13behaviors on your model objects, including table names, ordering, and
14more.  To specify an option, simply supply the option as a keyword
15argument onto the statement, as follows:
16
17.. sourcecode:: python
18
19    class Person(Entity):
20        name = Field(Unicode(64))
21
22        using_options(shortnames=True, order_by='name')
23
24The list of supported arguments are as follows:
25
26+---------------------+-------------------------------------------------------+
27| Option Name         | Description                                           |
28+=====================+=======================================================+
29| ``inheritance``     | Specify the type of inheritance this entity must use. |
30|                     | It can be one of ``single`` or ``multi``. Defaults to |
31|                     | ``single``. Concrete inheritance is currently not in  |
32|                     | a usable state.                                       |
33+---------------------+-------------------------------------------------------+
34| ``polymorphic``     | Whether the inheritance should be polymorphic or not. |
35|                     | Defaults to ``False``.                                |
36+---------------------+-------------------------------------------------------+
37| ``metadata``        | Specify a custom MetaData for this entity.            |
38|                     | By default, entities uses the global                  |
39|                     | ``elixir.metadata``.                                  |
40|                     | This option can also be set for all entities of a     |
41|                     | module by setting the ``__metadata__`` attribute of   |
42|                     | that module.                                          |
43+---------------------+-------------------------------------------------------+
44| ``autoload``        | Automatically load column definitions from the        |
45|                     | existing database table.                              |
46+---------------------+-------------------------------------------------------+
47| ``tablename``       | Specify a custom tablename. You can either provide a  |
48|                     | plain string or a callable. The callable will be      |
49|                     | given the entity (ie class) as argument and must      |
50|                     | return a string representing the name of the table    |
51|                     | for that entity.                                      |
52+---------------------+-------------------------------------------------------+
53| ``shortnames``      | Usually tablenames include the full module-path       |
54|                     | to the entity, but lower-cased and separated by       |
55|                     | underscores ("_"), eg.: "project1_model_myentity"     |
56|                     | for an entity named "MyEntity" in the module          |
57|                     | "project1.model".  If shortnames is ``True``, the     |
58|                     | tablename will just be the entity's classname         |
59|                     | lower-cased, ie. "myentity".                          |
60+---------------------+-------------------------------------------------------+
61| ``auto_primarykey`` | If given as string, it will represent the             |
62|                     | auto-primary-key's column name.  If this option       |
63|                     | is True, it will allow auto-creation of a primary     |
64|                     | key if there's no primary key defined for the         |
65|                     | corresponding entity.  If this option is False,       |
66|                     | it will disallow auto-creation of a primary key.      |
67+---------------------+-------------------------------------------------------+
68| ``version_id_col``  | If this option is True, it will create a version      |
69|                     | column automatically using the default name. If given |
70|                     | as string, it will create the column using that name. |
71|                     | This can be used to prevent concurrent modifications  |
72|                     | to the entity's table rows (i.e. it will raise an     |
73|                     | exception if it happens).                             |
74+---------------------+-------------------------------------------------------+
75| ``order_by``        | How to order select results. Either a string or a     |
76|                     | list of strings, composed of the field name,          |
77|                     | optionally lead by a minus (for descending order).    |
78+---------------------+-------------------------------------------------------+
79| ``session``         | Specify a custom contextual session for this entity.  |
80|                     | By default, entities uses the global                  |
81|                     | ``elixir.session``.                                   |
82|                     | This option accepts Objectstore                       |
83|                     | (found in Elixir and ActiveMapper), SessionContext    |
84|                     | (found in SQLAlchemy 0.3) or ScopedSession (found in  |
85|                     | SQLAlchemy 0.4) objects. It also supports ``None``,   |
86|                     | in which case your entity will be mapped using a      |
87|                     | non-contextual mapper. This option can also be set    |
88|                     | for all entities of a module via by setting the       |
89|                     | ``__session__`` attribute of that module.             |
90+---------------------+-------------------------------------------------------+
91| ``autosetup``       | Specify whether that entity will contain automatic    |
92|                     | setup triggers. That is if this entity will be        |
93|                     | automatically setup (along with all other entities    |
94|                     | which were already declared) if any of the following  |
95|                     | condition happen: some of its attributes are accessed |
96|                     | ('c', 'table', 'mapper' or 'query'), instanciated     |
97|                     | (called) or the create_all method of this entity's    |
98|                     | metadata is called. Defaults to ``True``.             |
99+---------------------+-------------------------------------------------------+
100| ``allowcoloverride``| Specify whether it is allowed to override columns.    |
101|                     | By default, Elixir forbids you to add a column to an  |
102|                     | entity's table which already exist in that table. If  |
103|                     | you set this option to ``True`` it will skip that     |
104|                     | check. Use with care as it is easy to shoot oneself   |
105|                     | in the foot when overriding columns.                  |
106+---------------------+-------------------------------------------------------+
107
108
109For examples, please refer to the examples and unit tests.
110
111`using_table_options`
112---------------------
113The 'using_table_options' DSL statement allows you to set up some
114additional options on your entity table. It is meant only to handle the
115options which are not supported directly by the 'using_options' statement.
116By opposition to the 'using_options' statement, these options are passed
117directly to the underlying SQLAlchemy Table object (both non-keyword arguments
118and keyword arguments) without any processing.
119
120For further information, please refer to the `SQLAlchemy table's documentation
121<http://www.sqlalchemy.org/docs/04/sqlalchemy_schema.html
122#docstrings_sqlalchemy.schema_Table>`_.
123
124You might also be interested in the section about `constraints
125<http://www.sqlalchemy.org/docs/04/metadata.html#metadata_constraints>`_.
126
127`using_mapper_options`
128----------------------
129The 'using_mapper_options' DSL statement allows you to set up some
130additional options on your entity mapper. It is meant only to handle the
131options which are not supported directly by the 'using_options' statement.
132By opposition to the 'using_options' statement, these options are passed
133directly to the underlying SQLAlchemy mapper (as keyword arguments)
134without any processing.
135
136For further information, please refer to the `SQLAlchemy mapper
137function's documentation
138<http://www.sqlalchemy.org/docs/04/sqlalchemy_orm.html
139#docstrings_sqlalchemy.orm_modfunc_mapper>`_.
140'''
141
142from elixir.statements import ClassMutator
143from sqlalchemy import Integer, String
144
145__doc_all__ = ['options_defaults']
146
147# format constants
148FKCOL_NAMEFORMAT = "%(relname)s_%(key)s"
149M2MCOL_NAMEFORMAT = "%(tablename)s_%(key)s"
150CONSTRAINT_NAMEFORMAT = "%(tablename)s_%(colnames)s_fk"
151
152# other global constants
153DEFAULT_AUTO_PRIMARYKEY_NAME = "id"
154DEFAULT_AUTO_PRIMARYKEY_TYPE = Integer
155DEFAULT_VERSION_ID_COL_NAME = "row_version"
156DEFAULT_POLYMORPHIC_COL_NAME = "row_type"
157POLYMORPHIC_COL_SIZE = 40
158POLYMORPHIC_COL_TYPE = String(POLYMORPHIC_COL_SIZE)
159
160#
161options_defaults = dict(
162    autosetup=True,
163    inheritance='single',
164    polymorphic=False,
165    autoload=False,
166    tablename=None,
167    shortnames=False,
168    auto_primarykey=True,
169    version_id_col=False,
170    allowcoloverride=False,
171    mapper_options=dict(),
172    table_options=dict(),
173)
174
175
176valid_options = options_defaults.keys() + [
177    'metadata',
178    'session',
179    'collection',
180    'order_by',
181]
182
183
184def using_options_handler(entity, *args, **kwargs):
185    for kwarg in kwargs:
186        if kwarg in valid_options:
187            setattr(entity._descriptor, kwarg, kwargs[kwarg])
188        else:
189            raise Exception("'%s' is not a valid option for Elixir entities." 
190                            % kwarg)
191
192
193def using_table_options_handler(entity, *args, **kwargs):
194    entity._descriptor.table_args = list(args)
195    entity._descriptor.table_options.update(kwargs)
196
197
198def using_mapper_options_handler(entity, *args, **kwargs):
199    entity._descriptor.mapper_options.update(kwargs)
200
201
202using_options = ClassMutator(using_options_handler)
203using_table_options = ClassMutator(using_table_options_handler)
204using_mapper_options = ClassMutator(using_mapper_options_handler)
Note: See TracBrowser for help on using the browser.