]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
(no commit message)
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 18 Nov 2005 00:52:05 +0000 (00:52 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 18 Nov 2005 00:52:05 +0000 (00:52 +0000)
doc/build/content/adv_datamapping.myt

index 5d8658a60e3881f86bd0e0e275eac39764307906..146a56a36f610fee1cee1e0637b33c824d527739 100644 (file)
 <%flags>inherit='document_base.myt'</%flags>
 <&|doclib.myt:item, name="adv_datamapping", description="Advanced Data Mapping" &>
+<p>This section is under construction.  For now, it has just the basic recipe for each concept without much else.  </p>
+
+<p>To start, heres the tables we will work with again:</p>
+       <&|formatting.myt:code&>
+        from sqlalchemy.schema import *
+        import sqlalchemy.engine as engine
+        db = engine.create_engine('sqlite', 'mydb', {}, echo=True)
+        
+        # a table to store users
+        users = Table('users', db,
+            Column('user_id', Integer, primary_key = True),
+            Column('user_name', String(40)),
+            Column('password', String(80))
+        )
+
+        # a table that stores mailing addresses associated with a specific user
+        addresses = Table('addresses', db,
+            Column('address_id', Integer, primary_key = True),
+            Column('user_id', Integer, ForeignKey("users.user_id")),
+            Column('street', String(100)),
+            Column('city', String(80)),
+            Column('state', String(2)),
+            Column('zip', String(10))
+        )
+
+        # a table that stores keywords
+        keywords = Table('keywords', db,
+            Column('keyword_id', Integer, primary_key = True),
+            Column('name', VARCHAR(50))
+        )
+
+        # a table that associates keywords with users
+        userkeywords = Table('userkeywords', db,
+            Column('user_id', INT, ForeignKey("users")),
+            Column('keyword_id', INT, ForeignKey("keywords"))
+        )
+       
+       </&>
 
 <&|doclib.myt:item, name="creating", description="Creating Mappers" &>
     <&|doclib.myt:item, name="customjoin", description="Custom Join Conditions" &>
+        <&|formatting.myt:code&>
+        </&>    
     </&>
 
     <&|doclib.myt:item, name="loadingoptions", description="Loading Options" &>
+        <&|formatting.myt:code&>
+        </&>    
     </&>
 
 </&>
 
 <&|doclib.myt:item, name="options", description="Mapper Options" &>
+    <&|formatting.myt:code&>
+    </&>    
 </&>
 
 <&|doclib.myt:item, name="custom", description="Custom Queries" &>
+    <&|formatting.myt:code&>
+        # a class
+        class User(object):
+            pass
+            
+        # basic mapper
+        User.mapper = mapper(User, users)
+        
+        # basic select with criterion
+        User.mapper.select(and_(users.c.user_name=='jane', users.c.user_id>12))
+        
+        # select with text criterion
+        User.mapper.select("user_name='jane' and user_id>12")
+
+        # select with totally textual query
+        User.mapper.select_text("select user_id, user_name, password from users")
+        
+        # select with a Select object
+        s = users.select(users, users.c.user_id==addresses.c.user_id)
+        User.mapper.select(s)
+    </&>    
+</&>
+
+<&|doclib.myt:item, name="inheritance", description="Mapping a Class with Table Inheritance" &>
+    <&|formatting.myt:code&>
+        class User(object):
+            """a user object."""
+            pass
+        User.mapper = mapper(User, users)
+
+        class AddressUser(User):
+            """a user object that also has the users mailing address."""
+            pass
+
+        # define a mapper for AddressUser that inherits the User.mapper, and joins on the user_id column            
+        AddressUser.mapper = mapper(
+                addresses, inherits = User.mapper, 
+                inherit_condition=User.c.user_id==addresses.c.user_id
+                )
+        
+        items = AddressUser.mapper.select()
+    </&>    
 </&>
 
 <&|doclib.myt:item, name="joins", description="Mapping a Class against Multiple Tables" &>
+    <&|formatting.myt:code&>
+        # a class
+        class AddressUser(object):
+            pass
+
+        # define a Join            
+        j = join(users, addresses, users.c.address_id==addresses.c.address_id)
+        
+        # map to it - the identity of an AddressUser object will be 
+        # based on (user_id, address_id) since those are the primary keys involved
+        m = mapper(AddressUser, j)
+        
+        # more complex join
+        j = join(users, userkeywords, 
+                users.c.user_id==userkeywords.c.user_id).join(keywords, 
+                   userkeywords.c.keyword_id==keywords.c.keyword_id)
+         
+        # a class 
+        class KeywordUser(object):
+            pass
+
+        # map to it - the identity of a KeywordUser object will be
+        # (user_id, keyword_id) since those are the primary keys involved
+        m = mapper(KeywordUser, j)
+    </&>    
 </&>
 <&|doclib.myt:item, name="multiple", description="Multiple Mappers for One Class" &>
+    <&|formatting.myt:code&>
+        class User(object):
+            pass
+        
+        # mapper one - mark it as "primary", meaning this mapper will handle
+        # saving and class-level properties
+        m1 = mapper(User, users, is_primary=True)
+        
+        # mapper two - this one will also eager-load address objects in
+        m2 = mapper(User, users, properties={
+                'addresses' : relation(Address, addresses, lazy=False)
+            })
+        
+        # get a user.  this user will not have an 'addreses' property
+        u1 = m1.select(User.c.user_id==10)
+        
+        # get another user.  this user will have an 'addreses' property.
+        u2 = m2.select(User.c.user_id==27)
+        
+        # make some modifications, including adding an Address object.
+        u1.user_name = 'jack'
+        u2.user_name = 'jane'
+        u2.addresses.append(Address('123 green street'))
+        
+        # upon commit, the User objects will be saved. 
+        # the Address object will not, since the primary mapper for User
+        # does not have an 'addresses' relationship defined
+        objectstore.commit()
+    </&>    
 </&>
 <&|doclib.myt:item, name="recursive", description="Self Referential Mappers" &>
+    <&|formatting.myt:code&>
+        # define a self-referential table
+        trees = Table('treenodes', engine,
+            Column('node_id', Integer, primary_key=True),
+            Column('parent_node_id', Integer, ForeignKey('treenodes.node_id'), nullable=True),
+            Column('node_name', String(50), nullable=False),
+            )
+
+        # treenode class
+        class TreeNode(object):
+            pass
+
+        # mapper defines "children" property, pointing back to TreeNode class,
+        # with the mapper unspecified.  it will point back to the primary 
+        # mapper on the TreeNode class.
+        TreeNode.mapper = mapper(TreeNode, trees, properties={
+                'children' : relation(
+                                TreeNode, 
+                                primaryjoin=tables.trees.c.parent_node_id==tables.trees.c.node_id, 
+                                lazy=True, uselist=True, private=True
+                             ),
+                )
+            )
+            
+        # or, specify the circular relationship after establishing the original mapper:
+        mymapper = mapper(TreeNode, trees)
+        
+        mymapper.add_property('children', relation(
+                                mymapper, 
+                                primaryjoin=tables.trees.c.parent_node_id==tables.trees.c.node_id, 
+                                lazy=True, uselist=True, private=True
+                             ))
+        
+    </&>    
+    <p>This kind of mapper goes through a lot of extra effort when saving and deleting items, to determine the correct dependency graph of nodes within the tree.</p>
 </&>
 <&|doclib.myt:item, name="resultset", description="Result-Set Mapping" &>
+    <p>Take any result set and feed it into a mapper to produce objects.  Multiple mappers can be combined to retrieve unrelated objects from the same row in one step.</p>
+    <&|formatting.myt:code&>
+        class User(object):
+            pass
+        class Address(object):
+            pass
+        User.mapper = mapper(User, users)
+        Address.mapper = mapper(Address, addresses)
+        
+        # select users
+        c = users.select().execute()
+        # get objects
+        userlist = User.mapper.instances(c)
+        
+        # select users and addresses in one query
+        s = select([users, addresses], users.c.user_id==addresses.c.user_id)
+
+        # execute it, and process the results with the User mapper, chained to the Address mapper
+        r = User.mapper.instances(s.execute(), Address.mapper)
+        # results rows are an array of objects, one for each mapper used
+        for entry in r:
+            user = r[0]
+            address = r[1]
+    </&>    
 </&>
 
 <&|doclib.myt:item, name="extending", description="Extending Mapper" &>
     <&|doclib.myt:item, name="class", description="How Mapper Modifies Mapped Classes" &>
+        <&|formatting.myt:code&>
+        </&>    
     </&>
     <&|doclib.myt:item, name="mapperextension", description="Adding/Replacing Functionality with Mapper Extension" &>
+        <&|formatting.myt:code&>
+        </&>    
     </&>
 </&>