【问题标题】:Customizing django admin site - in row buttons自定义 django 管理站点 - 行中按钮
【发布时间】:2013-12-14 18:02:25
【问题描述】:

假设我有一个这样的模型:

class Foo(models.Model):
    name = models.CharField(max_length=50)
    year = models.IntegerField(max_length=4)
    some_value = models.IntegerField(default=0)

class Bar(models.Model)
    name = models.CharField(max_length=50)
    foo = models.ForeignKey(Foo)

然后我使用 FooAdmin 类在 django AdminSite 中注册我的模型:

class FooAdmin(admin.ModelAdmin):
    list_display = ['name', 'year', 'some_value']

它工作正常,但出于某种原因,我需要为我的管理站点中的每个 Foo 行添加两个按钮。假设我称它们为“Related_button”和“Action_button”

我需要这些按钮位于每一行中,并且表现如下:
-当用户点击“Related_button”时,他被重定向到 django 管理站点,其中列出了与特定 Foo 对象相关的所有 Bars
- 当用户点击“Action_button”时,类 Foo 对象中的 some_value 字段设置为自定义值,例如 15。但在此之前,应出现确认弹出窗口(您确定吗?y/n)。

如何做到这一点?我发现我可以这样做:

def button(self, obj):
    return '''<input type="button" value="button" />'''
button.short_description = 'Action'
button.allow_tags = True
list_display = ['name', 'year', 'some_value', 'action']

在我的 FooAdmin 中,这会导致每行中出现一个按钮。但是如何为该按钮设置操作?

【问题讨论】:

    标签: python django


    【解决方案1】:

    列表页是一个表单。

    <form id="changelist-form" action="" method="post">
    

    向其添加按钮将提交表单。要对 formdata 进行操作,您必须创建一个自定义管理表单。它会很脏,因为它是一个包含所有显示行的起始集,而不仅仅是你的单行。我想是可以做到的,但还有更好的方法:

    大多数时候Admin Actions 会做得很好。管理员操作如下所示:

    def rename_action(modeladmin, request, queryset):
        queryset.update(name='Ni')
    make_published.short_description = "Rename selected objects to 'Ni'"
    
    class FooAdmin(admin.ModelAdmin):
        actions = [rename_action, ...]
    

    但是,如果您想要比管理员操作更大的灵活性,请随时为管理员编写自定义视图。管理员由 Django 本身提供支持,您可以编写与身份验证系统挂钩的自定义视图,检查权限并执行他们需要执行的任何其他操作。它是这样的:

    class Foo(models.Model):
        ...
    
        def my_action_link(self, obj):
            return '<a href="/admin/app/foo/my_custom_action/%d/" class="link">Action name</a>' %obj.id
        my_action_link.short_description = 'My action'
        my_action_link.allow_tags = True
    

    现在我的操作是指向某个custom url and custom admin view 的链接。创建自定义管理视图:

    class FooAdmin(admin.ModelAdmin):
        ...
    
        list_display = ['name', 'my_action_link', ...]
    
        def get_urls(self):
            urls = super(FooAdmin, self).get_urls()
            my_urls = patterns('',
                (r'^my_custom_action/(?P<pk>\d+)/$', self.my_view)
            )
            return my_urls + urls
    
        @permission_required('foo.can_change')
        def my_view(self, request):
            obj = get_object_or_404(Foo, pk=pk)
            obj.do_something()
            # Redirect back to the change list. Or something else?
            # You could add some modelform to this view. :)
    

    我没有测试这段代码。但我希望你能明白。快乐的黑客攻击!

    [已编辑]:链接参考 Django 1.6 URL 不再工作。添加了 Django 1.11 URL

    【讨论】:

    • 谢谢,看起来很棒!但我担心一件事——我还在我的 FooAdmin 中修改了查询集方法,如下所示:return Foo.objects.filter(created_by=request.user)。 my_view 是在我的过滤集中寻找 Foo 对象还是直接从数据库中检索它?我不想让我的用户看到他不允许看到的东西。
    • 我猜你的用户可能在摆弄 url。但是您可以这样做:obj = get_object_or_404(Foo, pk=pk, created_by=request.user) 如果该用户未创建 obj,它将引发 404。
    • 当然还有其他方法。检查并返回有用的消息:if request.user != obj.created_by: return "This incident will be reported."
    • 回答您的评论问题:这是一个常规视图,将查询数据库。它与 admin qs 方法无关。
    • 谢谢。最后一个问题:是否可以更改 django 管理操作,以便它们作为按钮而不是您上面显示的菜单工作?
    【解决方案2】:

    添加自定义js到管理类:

    class FooAdmin(admin.ModelAdmin):
        list_display = ['name', 'year', 'some_value']
    
        class Media:
            js = ("/media/javascript/yourjs.js",)
    

    【讨论】:

    • 你能再写点什么吗?不幸的是,我不知道java脚本。它应该解决我的哪一个问题?
    猜你喜欢
    • 2019-08-18
    • 1970-01-01
    • 2018-12-16
    • 2011-11-28
    • 2020-03-04
    • 2021-06-07
    • 1970-01-01
    • 1970-01-01
    • 2016-08-15
    相关资源
    最近更新 更多