root / elixir / trunk / elixir / __init__.py @ 82

Revision 82, 3.4 kB (checked in by ged, 6 years ago)

- Added support for autoloading/reflecting databases with

has_and_belongs_to_many relationships. The tablename argument is now
optional, but still recommended, otherwise you'll have to use the same exact
name for your intermediary table than the one generated.

- Made the colname argument optional for belongs_to relationships in

autoloaded entities. It is only required to specify it if you have several
belongs_to relationships between two entities/tables.

- Fixed bug preventing having entities without any statement.
- Made some PEP8 tweaks in many places. Used the pep8 script provided with

Cheesecake.

- Foreign key names generated by belongs_to relationships use column names

instead of relation names in case we have a relation with the same name
defined in several entities inheriting from the same entity using single-
table inheritance (and we set a custom column name in one of them to avoid
a column-name conflict).

- Actually make the code python 2.3 compatible (Robin's patch was based on

0.1.0 while I had introduced more decorators in the trunk in the mean time).

- Some cleanup/useless code removal (namely the foreign_key stuff in

relationships).

Line 
1'''
2Elixir package
3
4A declarative layer on top of SQLAlchemy, which is intended to replace the
5ActiveMapper SQLAlchemy extension, and the TurboEntity project.  Elixir is a
6fairly thin wrapper around SQLAlchemy, which provides the ability to define
7model objects following the Active Record design pattern, and using a DSL
8syntax similar to that of the Ruby on Rails ActiveRecord system.
9
10Elixir does not intend to replace SQLAlchemy's core features, but instead
11focuses on providing a simpler syntax for defining model objects when you do
12not need the full expressiveness of SQLAlchemy's manual mapper definitions.
13
14For an example of how to use Elixir, please refer to the examples directory
15and the unit tests. The examples directory includes a TurboGears application
16with full identity support called 'videostore'.
17'''
18
19import sqlalchemy
20
21from sqlalchemy.ext.sessioncontext  import SessionContext
22from sqlalchemy.types               import *
23from elixir.options                 import *
24from elixir.entity                  import Entity, EntityDescriptor
25from elixir.fields                  import *
26from elixir.relationships           import *
27
28try:
29    set
30except NameError:
31    from sets import Set as set
32
33__all__ = ['Entity', 'Field', 'has_field', 'with_fields',
34           'belongs_to', 'has_one', 'has_many', 'has_and_belongs_to_many',
35           'using_options', 'using_table_options', 'using_mapper_options',
36           'options_defaults', 'metadata', 'objectstore',
37           'create_all', 'drop_all', 'setup_all', 'cleanup_all',
38           'delay_setup'] + \
39          sqlalchemy.types.__all__
40
41__pudge_all__ = ['create_all', 'drop_all', 'setup_all', 'cleanup_all',
42                 'metadata', 'objectstore', 'delay_setup']
43
44# connect
45metadata = sqlalchemy.DynamicMetaData('elixir')
46
47try:
48    # this only happens when the threadlocal extension is used
49    objectstore = sqlalchemy.objectstore
50except AttributeError:
51    # thread local SessionContext
52    class Objectstore(object):
53
54        def __init__(self, *args, **kwargs):
55            self.context = SessionContext(*args, **kwargs)
56
57        def __getattr__(self, name):
58            return getattr(self.context.current, name)
59        session = property(lambda s:s.context.current)
60
61    objectstore = Objectstore(sqlalchemy.create_session)
62
63metadatas = set()
64
65
66def create_all():
67    'Create all necessary tables for all declared entities'
68    for md in metadatas:
69        md.create_all()
70
71
72def drop_all():
73    'Drop all tables for all declared entities'
74    for md in metadatas:
75        md.drop_all()
76
77delayed_entities = set()
78delay_setup = False
79
80
81def setup_all():
82    '''Setup the table and mapper for all entities which have been delayed.
83
84    This should be used in conjunction with setting ``delay_setup`` to ``True``
85    before defining your entities.
86    '''
87    for entity in delayed_entities:
88        entity.setup_table()
89    for entity in delayed_entities:
90        entity.setup_mapper()
91
92    # setup all relationships
93    for entity in delayed_entities:
94        for rel in entity.relationships.itervalues():
95            rel.setup()
96
97    delayed_entities.clear()
98
99    # issue the "CREATE" SQL statements
100    create_all()
101
102
103def cleanup_all():
104    '''Drop table and clear mapper for all entities, and clear all metadatas.
105    '''
106    drop_all()
107    for md in metadatas:
108        md.clear()
109    metadatas.clear()
110    EntityDescriptor.uninitialized_rels.clear()
111
112    objectstore.clear()
113    sqlalchemy.clear_mappers()
Note: See TracBrowser for help on using the browser.