Django 管理应用程序:构建管理操作的动态列表

发布于 2024-08-14 05:22:32 字数 1603 浏览 1 评论 0 原文

我正在尝试使用 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))

元组返回值的奇怪重复字典由 get_actions() 的 Django 文档。)

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

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

我假设使用 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)

I am trying to dynamically build a list of admin actions using the get_actions() method on a ModelAdmin. Each action relates to a particular instance of another model, and as new instances may be added or removed, I want to make sure the list of actions reflects that.

Here's the 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))

(The weird repetitive dict of tuples return value is explained by the Django docs for get_actions().)

As expected, this results in a list of appropriately named admin actions for bulk assignment of Quality foreign keys to Package objects.

The problem is that whichever action I choose, the same Quality object gets assigned to the selected Packages.

I assume that the closures I am creating with the lambda keyword all contain a reference to the same q object, so every iteration changes the value of q for every function.

Can I break this reference, allowing me to still use a list of closures containing different values of q?


Edit: I realise that lambda is not necessary in this example. Instead of:

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

I could simply use def:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

橙幽之幻 2024-08-21 05:22:32

如果这不起作用,请尝试

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

try

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

if that doesn't work, i suspect the bug has something to do with your use of yield. maybe try:

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()])
雨后咖啡店 2024-08-21 05:22:32

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

As I mentioned in my comment to andylei's answer, I just found a solution; using another function to create the closure seems to break the reference, meaning that now every action refers to the correct instance of 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())
东风软 2024-08-21 05:22:32

我很惊讶 q 在循环中保持相同的对象。

它可以与您的 lambda 中的 quality=q.id 一起使用吗?

I am surprised that q stays the same object within the loop.

Does it work with quality=q.id in your lambda?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文