【问题标题】:Django Admin app: building a dynamic list of admin actionsDjango Admin 应用程序:构建管理操作的动态列表
【发布时间】:2009-12-14 17:35:59
【问题描述】:

我正在尝试在ModelAdmin 上使用get_actions() 方法动态构建管理操作列表。每个动作都与另一个模型的特定实例相关,并且随着可能添加或删除新实例,我想确保动作列表反映这一点。

这是ModelAdmin

class PackageAdmin(admin.ModelAdmin):
    list_display = ('name', 'quality')

    def _actions(self, request):
        for q in models.Quality.objects.all():
            action = lambda modeladmin, req, qset: qset.update(quality=q)
            name = "mark_%s" % (q,)
            yield (name, (action, name, "Mark selected as %s quality" % (q,)))

    def get_actions(self, request):
        return dict(action for action in self._actions(request))

(元组返回值的奇怪重复dict由Django docs for get_actions()解释。)

正如预期的那样,这会生成一个适当命名的管理操作列表,用于将Quality 外键批量分配给Package 对象。

问题是无论我选择哪个操作,相同的Quality 对象都会分配给选定的Packages。

我假设我使用 lambda 关键字创建的闭包都包含对同一 q 对象的引用,因此每次迭代都会更改 每个函数q 的值。

我可以打破这个引用,让我仍然使用包含不同 q 值的闭包列表吗?


编辑:我意识到在这个例子中lambda 不是必需的。而不是:

action = lambda modeladmin, req, qset: qset.update(quality=q)

我可以简单地使用def:

def action(modeladmin, req, qset):
    return qset.update(quality=q)

【问题讨论】:

    标签: python django closures


    【解决方案1】:

    试试

       def make_action(quality):
            return lambda modeladmin, req, qset: qset.update(quality=quality)
    
       for q in models.Quality.objects.all():
           action = make_action(q)
           name = "mark_%s" % (q,)
           yield (name, (action, name, "Mark selected as %s quality" % (q,)))
    

    如果这不起作用,我怀疑该错误与您对yield 的使用有关。也许试试:

    def make_action(quality):
        name = 'mark_%s' % quality
        action = lambda modeladmin, req, qset: qset.update(quality=quality)
        return (name, (action, name, "Mark selected as %s quality" % quality))
    
    def get_actions(self, request):
        return dict([make_action for q in models.Quality.objects.all()])
    

    【讨论】:

    • 谢谢,我刚刚找到了一个类似于您的第二个建议的解决方案,并且在我读到这篇文章时正要发布。为您的时间 +1。
    • 我正在努力让它工作。您能否为此发布完整的工作示例?
    • 啊。怀疑它:(编辑 - 在 cmets 中没有代码格式!糟糕...) qset.update(quality=quality) return (name, (action, name, "Mark selected as %s quality" % quality)) return dict(make_action(q) for q in models.Quality.objects.all()) `
    【解决方案2】:

    正如我在对 andylei 的回答的评论中提到的,我刚刚找到了解决方案;使用另一个函数来创建闭包似乎破坏了引用,这意味着现在每个动作都引用了 Quality 的正确实例。

    def create_action(quality):
        fun = lambda modeladmin, request, queryset: queryset.update(quality=quality)
        name = "mark_%s" % (quality,)
        return (name, (fun, name, "Mark selected as %s quality" % (quality,)))
    
    class PackageAdmin(admin.ModelAdmin):
        list_display = ('name', 'quality')
    
        def get_actions(self, request):
            return dict(create_action(q) for q in models.Quality.objects.all())
    

    【讨论】:

      【解决方案3】:

      我很惊讶 q 在循环中保持同一个对象。

      它是否适用于您的 lambda 中的 quality=q.id

      【讨论】:

      • 感谢您的宝贵时间,但这并不能解决问题。我猜 lambda 中的 q.id 仍然是通过引用传递的。
      猜你喜欢
      • 2012-02-17
      • 2023-03-22
      • 2018-10-23
      • 1970-01-01
      • 1970-01-01
      • 2017-12-20
      • 2016-04-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多