2011-06-15 24 views
8

supone lo siguiente en MySQL:SQLAlchemy y se une, que no tienen las claves externas

CREATE TABLE users (
    id integer auto_increment primary key, 
    username varchar(30), 
    active enum('N','Y'), 
    created_on int(11), 
    updated_on int(11), 
    points int(10), 
    // other fields 
); 

CREATE TABLE comments (
    id integer auto_increment primary key, 
    user_id integer, 
    forum_id integer, 
    favorited integer, 
    // other fields 
); 

Tenga en cuenta que no hay restricciones de clave externa formales se agregan a las tablas. Esto es algo que he heredado y no puedo cambiar en nuestra configuración actual. (Estamos revisando todo el sistema, pero mientras tanto tengo que trabajar con lo que se me ha dado)

Tengo problemas para entender las uniones de SQLalchemy cuando no hay una clave externa formal establecida entre las tablas.

Efectivamente, me gustaría hacer algo como:

SELECT 
    u.username, 
    c.forum_id, 
    count(c.id) 
FROM 
    users u 
    JOIN comments c ON u.id=c.user_id 
WHERE 
    u.id = 1234 
GROUP BY 
    u.username, 
    c.forum_id; 

Código tengo incluye cosas como la siguiente:

mapper(Users, users, primary_key=[users.c.id], 
    include_properties=['user_id', 'username', 'active', 'created_on', 
     'updated_on', 'points']) 
mapper(Comments, comments, primary_key=[comments.c.id], 
    include_properties=['active', 'user_id', 'favorited', 'forum_id']) 

j = join(users, comments) 
mapper(UserComments, j, properties={'user_id': [users.c.id, 
    comments.c.user_id]}) 

session = create_session() 
query = session.query(UserComments).filter(users.cid == 1234) 
rdata = run(query) 
for row in rdata: 
    print row 

... que por supuesto falla con:

sqlalchemy.exc.ArgumentError: Can't find any foreign key relationships 
between 'users' and 'comments'. 

No estoy seguro de cómo evitar esto cuando no tenemos claves externas. ¿De qué otra manera puedo definir la relación? Pensé que era parte de la llamada mapper():

mapper(UserComments, j, properties={'user_id': [users.c.id, 
    comments.c.user_id]}) 

... pero al parecer he leído mal la documentación.

Gracias de antemano por cualquier ayuda.

+0

¿Estás seguro de que deseas mapear realmente la expresión de unión? Aunque SQLAlchemy lo permite, probablemente tenga más sentido hacer algo como 'session.query ([Users, Comments]). Join (Comments, ...)' para que termine con instancias de sus usuarios y modelos de comentarios en su lugar de Frankenstein. Además, dado que una cláusula join no tiene una clave principal, los modelos resultantes son mucho menos útiles, no puede conservar las modificaciones a ese modelo. – SingleNegationElimination

Respuesta

25

Tiene dos opciones. Puede pasar la condición de unión en join así:

j = join(users, comments, onclause=users.c.id == commends.c.user_id) 

Si estás definiendo esto en términos de una propiedad orm.relationship, el parámetro de palabra clave será primaryjoin en lugar de onclause.

Sin embargo, el enfoque que prefiero es solo mentir. Informe a SQLAlchemy que hay una clave externa, aunque no la hay.  

comments = Table('comments', metadata, 
    Column('id', Integer, primary_key=True), 
    Column('user_id', Integer, ForeignKey('users.id')), 
    ... 
) 

SQLAlchemy será el proceder como si la clave externa eran de hecho presente, a pesar de que la base de datos real no tiene eso. Por supuesto, puede tener problemas si se viola la restricción de llave foriegn implícita (comments.user_id cuando no hay users.id correspondiente), pero probablemente tenga problemas de todos modos.

+1

Probé la primera solución usando 'onclause' pero me encontré con' TypeError'. Para resolverlo, eliminé la palabra clave 'onclause' y simplemente pasé' users.c.id == commends.c.user_id' como parámetro. –

Cuestiones relacionadas