web2py: как выполнить инструкции перед удалением с помощью SQLFORM.smartgrid - PullRequest
0 голосов
/ 14 января 2019

Я использую SQLFORM.smartgrid для отображения списка записей из таблицы (service_types). В каждой строке SmartGrid есть ссылка / кнопка удаления, чтобы удалить запись. Я хочу выполнить некоторый код перед тем, как smartgrid / web2py фактически удалит запись, например, я хочу знать, есть ли дочерние записи (таблица services), ссылающиеся на эту запись, и, если таковые имеются, высветить сообщение, сообщающее пользователю, что запись не может быть удалена , Как это сделать?

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')

Контроллер

def list_services():
    grid = SQLFORM.smartgrid(db.services
        , fields = [db.services.service_name,db.services.service_type]
        )
    return locals()

вид

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

Ответы [ 2 ]

0 голосов
/ 17 января 2019

Из ответа Энтони я выбрал второй вариант и придумал следующее:

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()

Я получаю эту ошибку:

Screenshot of error

И если я сделаю это:

if count > 0:        
    session.flash = T("Cant delete")
    redirect(URL('default','list_service_types#'))   <== please take note
else:
    pass
return locals()

Я получаю сообщение об ошибке флэш-памяти Cant delete, но запись кажется удаленной из списка и появляется снова после обновления страницы с помощью F5 (очевидно, потому что удаление не разрешено в базе данных, которая предназначена).

Screenshot

Что мне починить и как?

Примечание Если какой-либо из этих вопросов будет решен, я могу принять ответ Энтони.

0 голосов
/ 15 января 2019

Есть два варианта. Во-первых, аргумент deletable может быть функцией, которая принимает объект Row данной записи и возвращает True или False, чтобы указать, является ли запись удаляемой. Если он возвращает False, кнопка «Удалить» не будет отображаться для этой записи, и операция удаления не будет разрешена на сервере.

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

grid = SQLFORM.smartgrid(..., deletable=can_delete)

Во-вторых, есть аргумент ondelete, который принимает объект db Table и идентификатор записи. Он вызывается непосредственно перед операцией удаления, поэтому для предотвращения удаления вы можете выполнить перенаправление внутри этой функции:

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, использование redirect в методе ondelete, как показано выше, не будет работать должным образом, поскольку перенаправление не будет иметь никакого эффекта, и Строка таблицы все равно будет удалена из сетки в браузере (даже если запись базы данных не была удалена). В этом случае альтернативный подход заключается в возврате HTTP-ответа не-200 в браузер, что не позволит Javascript на стороне клиента удалить строку из таблицы (удаление происходит только при успешном выполнении запроса Ajax). Мы также должны установить response.flash вместо session.flash (потому что мы не перенаправляем / перезагружаем всю страницу):

def ondelete(table, record_id):
    record = table(record_id)
    if [some condition]:
        response.flash = 'Cannot delete this record'
        raise HTTP(403)

Обратите внимание, что аргументы deletable и ondelete могут быть словарями с именами таблиц в качестве ключей, так что вы можете указывать разные значения для разных таблиц, которые могут быть связаны из smartgrid.

Наконец, обратите внимание, что URL-адреса для удаления выглядят как /appname/list_services/services/delete/services/[record ID]. Таким образом, в контроллере вы можете определить, запрашивается ли удаление, проверив, если 'delete' in request.args. В этом случае request.args[-2:] представляет имя таблицы и идентификатор записи, которые вы можете использовать для любых проверок.

...