Python web2py:如何使用SQLFORM.smartgrid在删除之前执行指令

Python web2py:如何使用SQLFORM.smartgrid在删除之前执行指令,python,web2py,Python,Web2py,我使用SQLFORM.smartgrid显示表(服务类型)中的记录列表。smartgrid的每一行都有一个删除链接/按钮,用于删除记录。我想在smartgrid/web2py实际删除该记录之前执行一些代码,例如,我想知道是否有引用该记录的子记录(servicestable),如果有,闪现一条消息,告诉用户该记录无法删除。这是怎么做到的 db.py db.define_table('service_types', Field('type_name', require

我使用SQLFORM.smartgrid显示表
(服务类型)
中的记录列表。smartgrid的每一行都有一个删除链接/按钮,用于删除记录。我想在smartgrid/web2py实际删除该记录之前执行一些代码,例如,我想知道是否有引用该记录的子记录(
services
table),如果有,闪现一条消息,告诉用户该记录无法删除。这是怎么做到的

db.py

db.define_table('service_types',
                Field('type_name', requires=[IS_NOT_EMPTY(), IS_ALPHANUMERIC()]),
                format='%(type_name)s',
    )

db.define_table('services',
                Field('service_name',requires=[IS_NOT_EMPTY(),IS_NOT_IN_DB(db,'services.service_name')]),
                Field('service_type','reference service_types',requires=IS_IN_DB(db,db.service_types.id,
                                                                                '%(type_name)s',
                                                                                error_message='not in table',
                                                                                zero=None),
                                                                                ondelete='RESTRICT',
                                                                                ),
                Field('interest_rate','decimal(15,2)',requires=IS_DECIMAL_IN_RANGE(0,100)),
                Field('max_term','integer'),
                auth.signature,
                format='%(service_name)s',
    )
db.services._plural='Services'
db.services._singular='Service'

if db(db.service_types).count() < 1:
    db.service_types.insert(type_name='Loan')
    db.service_types.insert(type_name='Contribution')
    db.service_types.insert(type_name='Other')
查看

{{extend 'layout.html'}}
{{=grid}}

有两种选择。首先,
deletable
参数可以是一个函数,它接受给定记录的
对象,并返回
True
False
,以指示该记录是否可删除。如果返回
False
,则不会显示该记录的“删除”按钮,也不允许在服务器上执行删除操作

def can_delete(row):
    return True if [some condition involving row] else False

grid = SQLFORM.smartgrid(..., deletable=can_delete)
其次,有一个
ondelete
参数,它接受
db
对象和记录ID。它在删除操作之前被调用,因此为了防止删除,您可以在该函数中执行重定向:

def ondelete(table, record_id):
    record = table(record_id)
    if [some condition]:
        session.flash = 'Cannot delete this record'
        redirect(URL())

grid = SQLFORM.smartgrid(..., ondelete=ondelete)
注意,如果网格是通过Ajax组件加载的,因此其操作是通过Ajax执行的,那么在如上所示的
ondelete
方法中使用
redirect
将无法正常工作,因为重定向将不起作用,并且仍将在浏览器中从网格中删除表行(即使数据库记录没有被删除)。在这种情况下,另一种方法是向浏览器返回非200 HTTP响应,这将阻止客户端Javascript从表中删除行(删除仅在Ajax请求成功时发生)。我们还应该设置
response.flash
,而不是
session.flash
(因为我们没有重定向/重新加载整个页面):

注意,
deletable
ondelete
参数都可以是以表名为键的字典,因此您可以为可能从smartgrid链接的不同表指定不同的值


最后,请注意删除URL看起来像
/appname/list\u services/services/delete/services/[record ID]
。因此,在控制器中,您可以通过检查request.args中的
'delete'来确定是否请求删除。在这种情况下,
request.args[-2:]
表示表名和记录ID,您可以使用它进行任何检查。

根据Anthony的回答,我选择了第二个选项,并得出以下结论:

def ondelete_service_type(service_type_table, service_type_id):
    count = db(db.services.service_type == service_type_id).count()
    if count > 0:        
        session.flash = T("Cant delete")
        #redirect(URL('default','list_service_types#'))        
    else:
        pass
    return locals()

def list_service_types():
    grid = SQLFORM.smartgrid(db.service_types
        , fields = [db.service_types.type_name, db.services.service_name]
        , ondelete = ondelete_service_type
        )
    return locals()
但是,如果我这样做

if count > 0:        
    session.flash = T("Cant delete")
else:
    pass
return locals()
我得到这个错误:

如果我这样做:

if count > 0:        
    session.flash = T("Cant delete")
    redirect(URL('default','list_service_types#'))   <== please take note
else:
    pass
return locals()
如果计数>0:
session.flash=T(“无法删除”)

重定向(URL('default','list_service_types'))请查看我的相关评论的答案。这让我意识到这些选项都不是我想要的。我必须返回并编写我自己的视图。我的视图、我的按钮、我的操作。你不必自定义所有内容。网格有一个
链接
参数,可用于添加自定义链接/按钮。因此,你可以回复将标准的“删除”按钮与自定义按钮进行比较,自定义按钮可以满足您的需要。好的,我正在尝试链接。请回答新问题。注意,答案已经更新,使用的解决方案即使在Ajax组件内的网格中也能很好地工作。
if count > 0:        
    session.flash = T("Cant delete")
else:
    pass
return locals()
if count > 0:        
    session.flash = T("Cant delete")
    redirect(URL('default','list_service_types#'))   <== please take note
else:
    pass
return locals()