Composite Primary Key mapping that works in 0.4.8 is broken in 0.5.3

Issue #1329 resolved
Former user created an issue

+------------+--------------+------+-----+-------------------+-------+

| Field | Type | Null | Key | Default | Extra |

+------------+--------------+------+-----+-------------------+-------+

| userid | int(11) | NO | PRI | 0 | |

| fieldname | varchar(255) | NO | PRI | | |

| fieldvalue | varchar(255) | NO | | | |

| timestamp | timestamp | NO | | CURRENT_TIMESTAMP | |

+------------+--------------+------+-----+-------------------+-------+

4 rows in set (0.00 sec)

user_info_table = Table("UserInfo", registration_metadata, Column("userid", types.Integer(11), nullable=False), Column("fieldname", types.String(255), nullable = False, default = None), Column("fieldvalue", types.String(255), nullable = False, default = None), Column("timestamp", types.DateTime, nullable = False), PrimaryKeyConstraint("userid", "fieldname"),

mysql_engine = "myIsam"

)

The above mapping works correctly using 0.4.8. When upgrading to 5.3 I get the following error:

Traceback (most recent call last): File "/usr/local/bin/paver", line 8, in <module> load_entry_point('Paver==0.8.1', 'console_scripts', 'paver')() File "/Library/Python/2.5/site-packages/Paver-0.8.1-py2.5.egg/paver/command.py", line 48, in main setuputils.setup(setupargs) File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/distutils/core.py", line 151, in setup dist.run_commands() File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/distutils/dist.py", line 974, in run_commands self.run_command(cmd) File "/Library/Python/2.5/site-packages/Paver-0.8.1-py2.5.egg/paver/setuputils.py", line 167, in run_command cmd_obj.run() File "/Library/Python/2.5/site-packages/Paver-0.8.1-py2.5.egg/paver/runtime.py", line 328, in run self.task_obj() File "/Library/Python/2.5/site-packages/Paver-0.8.1-py2.5.egg/paver/runtime.py", line 377, in call return self.func(*args, kw) File "pavement.py", line 47, in start_local_server from dartoo.application import get_wsgi_application File "src/dartoo/application.py", line 10, in <module> import dartoo.state as state File "src/dartoo/state.py", line 2, in <module> from dartoo.models.registration import User, UserInfo,UserP File "src/dartoo/models/registration.py", line 109, in <module> column_prefix = "SA", File "/Library/Python/2.5/site-packages/SQLAlchemy-0.5.2-py2.5.egg/sqlalchemy/orm/init.py", line 752, in mapper return Mapper(class_, local_table, args, *params) File "/Library/Python/2.5/site-packages/SQLAlchemy-0.5.2-py2.5.egg/sqlalchemy/orm/mapper.py", line 199, in init self._configure_pks() File "/Library/Python/2.5/site-packages/SQLAlchemy-0.5.2-py2.5.egg/sqlalchemy/orm/mapper.py", line 443, in _configure_pks "key columns for mapped table '%s'" % (self, self.mapped_table.description)) sqlalchemy.exc.ArgumentError: Mapper Mapper|UserInfo|UserInfo could not assemble any primary key columns for mapped table 'UserInfo'.

The issue appears to be around the composite primary key. Mapping the primary keys using the "primary_key" argument int The column constructor yields the same behavior. However, if I just make 1 column a PK there is no exception.

Comments (2)

  1. Mike Bayer repo owner

    sorry, this can't be reproduced.

    from sqlalchemy import *
    from sqlalchemy.orm import *
    import datetime
    
    e = create_engine('mysql://scott:tiger@localhost/test', echo=True)
    
    metadata = MetaData(e)
    user_info_table = Table("UserInfo", metadata,
        Column("userid", Integer(11), nullable=False), 
        Column("fieldname", String(255), nullable = False, default = None), 
        Column("fieldvalue", String(255), nullable = False, default = None), 
        Column("timestamp", DateTime, nullable = False), 
        PrimaryKeyConstraint("userid", "fieldname"),
        mysql_engine = "myIsam"
    )
    
    metadata.drop_all()
    metadata.create_all()
    
    class Foo(object):
        def __init__(self, **kw):
            for k in kw:
                setattr(self, k, kw[k](k))
    
    class Bar(object):
        def __init__(self, **kw):
            for k in kw:
                setattr(self, k, kw[k](k))
    
    mapper(Foo, user_info_table)
    mapper(Bar, user_info_table, primary_key=[user_info_table.c.fieldname](user_info_table.c.userid,))
    
    
    sess = create_session()
    
    f1 = Foo(userid=1, fieldname='foo', fieldvalue='bar', timestamp=datetime.datetime.today())
    
    b1 = Bar(userid=2, fieldname='foo', fieldvalue='bar', timestamp=datetime.datetime.today())
    
    sess.add_all([f1](b1,))
    sess.flush()
    
    assert [for c in class_mapper(Foo).primary_key](c.key) == ['fieldname']('userid',)
    assert [for c in class_mapper(Bar).primary_key](c.key) == ['fieldname']('userid',)
    
    assert sess.query(Foo.userid, Foo.fieldname).order_by(Foo.userid).all() == ['foo'), (2, 'foo')]((1,)
    assert sess.query(Bar).get((2, 'foo')) is b1
    

    output:

    SHOW VARIABLES LIKE 'sql_mode'
    ()
    DESCRIBE `UserInfo`
    ()
    
    DROP TABLE `UserInfo`
    ()
    COMMIT
    DESCRIBE `UserInfo`
    ()
    ROLLBACK
    
    CREATE TABLE `UserInfo` (
        userid INTEGER NOT NULL AUTO_INCREMENT, 
        fieldname VARCHAR(255) NOT NULL, 
        fieldvalue VARCHAR(255) NOT NULL, 
        timestamp DATETIME NOT NULL, 
        PRIMARY KEY (userid, fieldname)
    )ENGINE=myIsam
    
    ()
    COMMIT
    BEGIN
    INSERT INTO `UserInfo` (userid, fieldname, fieldvalue, timestamp) VALUES (%s, %s, %s, %s)
    ['foo', 'bar', datetime.datetime(2009, 3, 1, 17, 47, 2, 705484)](1,)
    INSERT INTO `UserInfo` (userid, fieldname, fieldvalue, timestamp) VALUES (%s, %s, %s, %s)
    ['foo', 'bar', datetime.datetime(2009, 3, 1, 17, 47, 2, 707517)](2,)
    COMMIT
    SELECT `UserInfo`.userid AS `UserInfo_userid`, `UserInfo`.fieldname AS `UserInfo_fieldname` 
    FROM `UserInfo` ORDER BY `UserInfo`.userid
    []
    
  2. Log in to comment