In my image-labeling app I want to display a list of labels assigned to an image along with lable-type and user information, who assigned this lable. The main table is imageLabel. The tables auth_user and labelType contain additional information to the label.
Could you help me converting this SQL-statement to web2py:
SELECT labelType.name, imageLabel.labelValue, auth_user.first_name, auth_user.last_name from imageLabel
LEFT JOIN labelType
ON imageLabel.labelId = labelType.id
LEFT JOIN auth_user
ON imageLabel.userId = auth_user.id
WHERE imageLabel.imageId = 581
ORDER BY labelType.name
The data model is like this:
db.define_table('labelType',
Field('name','string'),
)
db.define_table('imageLabel',
Field('imageId','string'),
Field('labelId','integer'),
Field('userId','integer'),
Field('labelValue','text'),
)
db.define_table('image',
Field('imageId','string')
)
# + built-in auth tables
My attempt was:
labels = db((db.imageLabel.id == db.labelType.id) ).select(
db.imageLabel.labelValue, db.labelType.name, db.auth_user.first_name, db.auth_user.last_name, db.imageLabel.labelTimeStamp,
left=db.auth_user.on(db.imageLabel.userId==db.auth_user.id)
)
Which abviously doesn't work as there is no WHERE imageLabel.imageId = 581 part in the code. And I can't figure out how to use WHERE along with 2 "JOINS" in web2py :-(
Thank you very much in advance for any help!
EDIT: SOLUTION After reading answer from Anthony:
labels = db(
db.imageLabel.imageId == img.id
).select(
db.imageLabel.labelValue,
db.labelType.name,
db.auth_user.first_name,
db.auth_user.last_name,
db.imageLabel.labelTimeStamp,
left=[
db.labelType.on(db.imageLabel.labelId == db.labelType.id),
db.auth_user.on(db.imageLabel.userId==db.auth_user.id)
],
orderby=~db.labelType.name
)
In general, a select looks like db(query).select(...)
. The query
part of that represents the WHERE
clauses. If you have multiple WHERE
clauses, you just use the &
operator:
db((condition 1) & (condition 2) & ...)
As for left joins, the left
argument of the .select()
method can be a list if you need to specify multiple left joins:
left=[db.auth_user.on(db.imageLabel.userId==db.auth_user.id),
db.labelType.on(db.imageLabel.labelId==db.labelType.id)]
However, it's not clear that you really want left joins here -- you might just want inner joins (which can be specified using the join
argument to the .select()
method, or more simply as conditions in the query):
db((db.imageLabel.labelId == db.labelType.id) & # joins imageLabel and labelType
(db.imageLabel.userId == db.auth_user.id) & # joins imageLabel and auth_user
(db.imageLabel.imageId == 581))\
.select(db.imageLabel.labelValue, db.labelType.name, db.auth_user.first_name,
db.auth_user.last_name, db.imageLabel.labelTimeStamp)
Also, you should probably specify the three "Id" fields as reference type fields:
db.define_table('imageLabel',
Field('imageId', 'reference image'),
Field('labelId', 'reference labelType'),
Field('userId', 'reference auth_user'),
Field('labelValue', 'text'),
)
Finally, why do you need an imageId string field? The db.image table will already have an auto-incrementing integer "id" field to serve as a primary key for the table and uniquely identify each image.