4

コンテナ内のアイテムを削除した後、コンテナの親にリダイレクトしたいと考えています。この目的のために、私は購読しようとしましたzope.lifecycleevent's IObjectRemovedEvent

@grok.subscribe(ISite, IObjectRemovedEvent)
def redirect_to_trial_on_delete(obj, event):
    request = getattr(obj, 'REQUEST', None)
    if request:
        trial_url = obj.aq_parent.aq_parent.absolute_url()
        request.response.redirect(trial_url)

をクリックすると削除がトリガーされcontainer/id/delete_confirmationますが、これにより、予想よりも多くのイベントが発生します。サブスクライブした関数が 2 回呼び出されます。リンクをクリックしたときに 1 回、削除を確認したときにもう一度呼び出されます。さらにややこしいのは、削除をキャンセルした場合に呼び出されることです。オブジェクトがコンテナーから削除された場合にのみ、イベントが発生することを期待していました。

3つのケースすべてで、イベント オブジェクトは同じで、oldName、oldParent などのプロパティ値も同じです。

アイテムの削除依頼、そのリクエストのキャンセル、および実際のアイテムの削除をどのように区別できますか?

更新:リンクの整合性をチェックするためにオブジェクトがコンテナから削除され、その時点でロールバックがあるため、最初のイベントが呼び出されたようです。

4

4 に答える 4

3

同僚が実用的な解決策を思いついた:

import transaction

def redirect_to_trial(trans, obj=None, parent=None):
    if obj.id not in parent:
        request = getattr(obj, 'REQUEST', None)
        if request:
            trial_url = obj.__parent__.__parent__.absolute_url()
            request.response.redirect(trial_url)

@grok.subscribe(ISite, IObjectRemovedEvent)
def on_site_delete(obj, event):
    kwargs = dict(
        obj = obj,
        parent = event.oldParent,
    )
    transaction.get().addAfterCommitHook(redirect_to_trial, kws=kwargs)

これは、コミット後、リダイレクトを実行する前に、オブジェクトが実際に削除されたことを確認するためにチェックします。

ただし、これが適切なアプローチであるかどうかを確認していただければ幸いです。

于 2012-06-27T04:33:01.110 に答える
1

同じ天才の同僚からの別の可能性があります。

from zope.interface import implements
from transaction.interfaces import ISavepointDataManager
from transaction._transaction import AbortSavepoint
import transaction

class RedirectDataManager(object):

    implements(ISavepointDataManager)

    def __init__(self, request, url):
        self.request = request
        self.url = url
        # Use the default thread transaction manager.
        self.transaction_manager = transaction.manager

    def tpc_begin(self, transaction):
        pass

    def tpc_finish(self, transaction):
        self.request.response.redirect(self.url)

    def tpc_abort(self, transaction):
        self.request.response.redirect(self.url)

    def commit(self, transaction):
        pass

    def abort(self, transaction):
        pass

    def tpc_vote(self, transaction):
        pass

    def sortKey(self):
        return id(self)

    def savepoint(self):
        """
        This is just here to make it possible to enter a savepoint with this manager active.
        """
        return AbortSavepoint(self, transaction.get())

def redirect_to_trial(obj, event):
    request = getattr(obj, 'REQUEST', None)
    if request:
        trial_url = obj.__parent__.__parent__.absolute_url()
        transaction.get().join(RedirectDataManager(request, trial_url))

サブスクリプションに zcml を使用して、複数のコンテンツ タイプに簡単にバインドできるようになりました。

<subscriber
    zcml:condition="installed zope.lifecycleevent"
    for=".schema.ISite zope.lifecycleevent.IObjectRemovedEvent"
    handler=".base.redirect_to_trial"
/>

これは、私がキャッチしたイベントが本当に必要なイベントであるかどうかを手動でチェックするよりも、何が起こっているかについてより明確であることがわかったため、私が最終的に行ったソリューションです。

于 2012-06-27T05:17:03.613 に答える
1

イベント ハンドラーを使用する代わりに、アクションをカスタマイズできます。delete_confirmationこれらは Web でも変更でき、タイプごとにカスタマイズできます。このdelete_confirmationスクリプトはCMF フォーム コントローラー スクリプトであり、動作を変更するためのオプションがいくつかあります。

現在、アクションは次のように定義されています。

[actions]
action.success=redirect_to:python:object.aq_inner.aq_parent.absolute_url()
action.confirm=traverse_to:string:delete_confirmation_page

action.success.TypeNameたとえば、 を定義することで、タイプ固有のアクションを追加できます。

Web 経由で行うには、ZMI にアクセスしてツールを見つけ、次のタブportal_form_controllerをクリックします。Actions

[アクション] タブが強調表示されたフォーム コントローラーの概要画面

このスクリーンショットからわかるように、ツールに関するドキュメントもここで入手できます。

アクション タブには、新しいアクションを追加するためのフォームがあります。

例が事前に入力された新しいアクションオーバーライドフォームを追加します

ご覧のとおり、コンテキスト タイプは、タイプ固有のアクションを簡単に指定できるように、すべての既存のタイプ登録を含むドロップダウンになっています。redirect_to通常のアクション (式で指定されたアクション) をコピーし、コンテナーの親を選択するためにpython:エクストラを追加しました。.aq_parent

.addFormActionツールのメソッドを使用して、そのようなアクションを追加することもできます。

fctool = getToolByName(context, 'portal_form_controller')
fctool.addFormAction('delete_confirmation', 'success', 'Event', None,
     'redirect_to',
     'python:object.aq_inner.aq_parent.aq_parent.absolute_url()')

最後になりcmfformcontroller.xmlましたが、GenericSetup プロファイルのファイルでそのようなカスタム アクションを指定できます。上記のアクションに基づく例を次に示します。

<?xml version="1.0" ?>
<cmfformcontroller>
  <action
      object_id="delete_confirmation" 
      status="success"
      context_type="Event"
      action_type="redirect_to"
      action_arg="python:object.aq_inner.aq_parent.aq_parent.absolute_url()"
      />
</cmfformcontroller>

この形式は、Plone で十分に文書化されていないものの 1 つです。これは、GS インポートおよびエクスポート コードの CMFFormController ソースコードから取得しました。

于 2012-06-27T11:45:56.000 に答える