> Another option would be to have the callable return a (url, message) tuple, and let the view handle HttpResponseRedirect and request.user.add_message.
I think you should use a dictionary. For example, you could pass in the following dictionary: {None:'../report1/%s'} and then in the default method: else: request.user.add_message(msg) redir = redir_dict.get(None, '../../') return HttpResponseRedirect(redir) etc. for all types of POST in the method. Anyway, you could pass this into the change_stage method via the admin class, or via urls.py (which is how I'm using this technique). ('url1/', 'change_list', {'app_label':'myapp', 'module_name':'mymod'}), ('url1/\d+/', 'change_stage', {'app_label':'myapp', 'module_name': 'mymod', 'redir_dict':{None:'../report1/%s'}}), ('url1/add/', 'add_stage', {'app_label':'myapp','module_name':'mymod','redir_dict':{None:'../report1/%s'}}), or you could write a tiny custom view that does the same and looks cleaner! Of course you could throw the same dict into the admin class to achieve the same. The reason I think it is nice to do this without a custom "after_change_action" method is that much of the after_change_action code would be duplicated on different modules, but the actual url is the part that changes. Also much of the time you will just want to redir the "Save" action and none of the others. -rob