Django Admin应用:构建动态管理员操作列表

7 投票
3 回答
3571 浏览
提问于 2025-04-15 17:00

我正在尝试使用get_actions()方法动态构建一个管理员操作的列表,这个方法是属于ModelAdmin的。每个操作都和另一个模型的特定实例有关,由于可能会添加或删除新的实例,我想确保操作列表能够反映这些变化。

下面是我的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))

(返回的奇怪的重复字典和元组的值可以在Django文档中找到关于get_actions()的解释。)

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

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

我猜我用lambda关键字创建的闭包都包含对同一个q对象的引用,所以每次循环都会改变每个函数的q值。

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


编辑:我意识到在这个例子中其实不需要lambda。我可以直接使用def

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

我可以简单地使用def

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

3 个回答

0

我很惊讶在这个循环中,q这个对象一直没有变化。

在你的lambda函数里,quality=q.id这样写可以吗?

5

正如我在对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())
8

尝试一下

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

撰写回答