我认为您无法使用网格(或一般使用 DAL)进行这样的查询。作为替代方案,您可以使用该links
参数生成一个自定义列,其中包含每个项目的标签列表:
def taglist(row):
tags = db((db.itemtag.item_id == row.id) &
(db.itemtag.tag_id == db.tag.id)).select()
return ', '.join(tag.name for tag in tags)
items = SQLFORM.grid(db.items, orderby=[db.items.title],
fields=[db.items.id, db.items.title, db.items.rating],
create=False, editable=False, details=False,
showbuttontext=False, paginate=50,
links = [lambda row: A(I(_class="icon-edit"), _href=URL("default",
"item_edit", args=[row.items.id])),
dict(heading='Tags', body=taglist)])
列表中的项目links
可以是带有header
和body
键的字典,在这种情况下,它将显示在具有指定标题的单独列中。
请注意,此方法效率较低,因为它会导致对网格中的每一行进行额外查询,以便检索该行的标签列表。
另一种选择是使用虚拟字段(只有最新版本的 web2py 在网格中显示虚拟字段):
def taglist(row):
tags = db((db.itemtag.item_id == row.items.id) &
(db.itemtag.tag_id == db.tag.id)).select()
return ', '.join(tag.name for tag in tags)
db.items.tags = Field.Virtual('tags', taglist)
db.items
为表格定义“标签”虚拟字段后,您可以像任何其他字段一样在网格中显示它。注意,taglist()
本例中函数的定义与上面原来的略有不同——在定义虚拟字段时,需要引用行对象内的表和字段,所以查询包括row.items.id
而不是仅仅包含row.id
.
请注意,与links
解决方案一样,虚拟字段替代方案也会导致网格的每行单独查询。
使用虚拟字段的好处是一旦定义,它也可以在其他上下文中使用。但是,请记住,只要您从db.items
表中选择记录,它的值就会被填充,因此如果您不需要其他上下文中的标签列表,您可能希望有条件地定义虚拟字段(例如,只定义它在需要它的控制器中)以避免不必要的数据库查询。
list:reference
更新:要考虑的另一个选项是用表中的类型字段替换多对多数据库模型,db.items
以存储对表的引用db.tag
列表(参见示例)。只要您将表格的format
属性设置为标签名称(或显式设置字段的属性以显示标签名称),您将获得网格中该字段的标签名称的逗号分隔列表。db.tag
represent
list:reference
此方法仍需要每行查询来获取标签名称,但该查询不涉及连接。但是,使用list:reference
字段的限制是,需要对标签进行聚合的操作(例如,构建标签云)可能效率较低,因为您不再拥有完全规范化的数据。
请注意,上述方法均不允许在网格中搜索标签。对于可搜索性,最简单的方法是使用list:string
类型字段db.items
来存储标签。但是,这使得对标签进行操作变得更加困难,因为不再有一个标签表,每个标签只有一条记录(相反,标签在db.items
表的记录中重复)。
另一种选择可能是保留多对多模型,但添加一个计算字段以db.items
存储从多对多关系派生的标签名称列表。该计算字段将显示在网格中并且可以搜索。您可能还希望在表中添加.after_insert
和.after_update
回调,以便在进行插入/更新时db.itemtag
自动更新db.items
计算字段。db.itemtag
最后,您可以创建自定义网格搜索功能。SQLFORM.grid
接受一个search_widget
用于在 UI 中实现自定义搜索小部件的参数,该searchable
参数可以是一个可调用对象,该对象接受搜索小部件关键字提交并生成一个子查询来过滤记录。
如需有关这些更高级选项的帮助,请在Google Group上提问。