Python 如何在Django Admin中将自定义操作添加到变更模型表单中?

Python 如何在Django Admin中将自定义操作添加到变更模型表单中?,python,django,django-admin,Python,Django,Django Admin,我正在使用Django admin,我希望能够使用模型的现有实例作为模板来创建新对象,因此使用Django admin的用户在创建新对象时不需要重新设置对象上所有相同属性的关键帧 我在Django管理表单的底部描绘了一个类似的场景,用于更新单个对象: django文档解释了如何通过添加到模型上的操作来添加批量操作,如下所示: class ArticleAdmin(admin.ModelAdmin): actions = ['make_published'] def make

我正在使用Django admin,我希望能够使用模型的现有实例作为模板来创建新对象,因此使用Django admin的用户在创建新对象时不需要重新设置对象上所有相同属性的关键帧

我在Django管理表单的底部描绘了一个类似的场景,用于更新单个对象:

django文档解释了如何通过添加到模型上的操作来添加批量操作,如下所示:

class ArticleAdmin(admin.ModelAdmin):

    actions = ['make_published']

    def make_published(self, request, queryset):
        queryset.update(status='p')

    make_published.short_description = "Mark selected stories as published"
然而,对于一个对象上的单个
更改模型
表单,对于我一次只想应用于模型的操作,我不太清楚如何做到这一点

我该怎么做

我猜我可能需要用它四处转转,但除此之外,我不太确定


有没有一种快速的方法可以在不覆盖模板加载的情况下完成此操作?

Django Admin不提供为更改表单添加自定义操作的方法

然而,你可以通过几次黑客攻击得到你想要的

首先,您必须覆盖提交行

你的应用程序/templates/admin/submit\u line.html

{% load i18n admin_urls %}
<div class="submit-row">
{% if show_save %}<input type="submit" value="{% trans 'Save' %}" class="default" name="_save" />{% endif %}
{% if show_delete_link %}
    {% url opts|admin_urlname:'delete' original.pk|admin_urlquote as delete_url %}
    <p class="deletelink-box"><a href="{% add_preserved_filters delete_url %}" class="deletelink">{% trans "Delete" %}</a></p>
{% endif %}
{% if show_save_and_copy %}<input type="submit" value="{% trans 'Create a new item based on this one' %}" name="_save_and_copy" />{% endif %}
{% if show_save_as_new %}<input type="submit" value="{% trans 'Save as new' %}" name="_saveasnew" />{% endif %}
{% if show_save_and_add_another %}<input type="submit" value="{% trans 'Save and add another' %}" name="_addanother" />{% endif %}
{% if show_save_and_continue %}<input type="submit" value="{% trans 'Save and continue editing' %}" name="_continue" />{% endif %}
</div>
这个例子是针对你的具体情况,如果你需要的话,你可以让它更通用


也就是说,对于您的特定案例,您也可以单击“保存并继续”保存您的工作,然后单击“另存为新”制作副本。是吗?

正如所指出的,没有办法,需要被黑客攻击。我认为这是一个优雅的技巧,可以将自定义操作添加到列表视图和更改表单视图中。它实际上并没有保存表单,只是对当前对象执行您想要的任何自定义操作,然后返回到相同的更改表单页面

从django.db.models导入模型
从django.contrib导入管理,消息
从django.contrib.admin.options导入(
不引用,
csrf\u保护\u m,
HttpResponseRedirect,
)
类ArticleAdmin(admin.ModelAdmin):
change\u form\u template='book/admin\u change\u form\u book.html'
操作=['make_published']
def发布(自我、请求、查询集):
如果是实例(查询集,模型):
obj=查询集
对象状态='p'
obj.save()
更新的\u计数=1
其他:
updated_count=queryset.update(status='p')
msg=“已标记{}现有对象中的新对象”。格式(更新的\u计数)
self.message\u用户(请求、消息、消息.成功)
make_published.short_description=“将选定的故事标记为已发布”
@保护
def changeform_视图(self、request、object_id=None、form_url=''、extra_context=None):
如果request.method==“POST”和“request.POST”中的“\u make\u published”:
obj=self.get_对象(请求,取消引用(对象id))
自我发布(请求,obj)
返回HttpResponseRedirect(request.get_full_path())
返回admin.ModelAdmin.changeform\u视图(
自我,请求,
object\u id=object\u id,
form_url=form_url,
额外上下文=额外上下文,
)
现在,您可以为自定义模板视图中的操作添加一个
(本例在change\u form\u模板中使用
book/admin\u change\u form\u book.html

{%extends'admin/change\u form.html%}
{%block form_top%}
{%endblock%}
如果查看
admin/change\u form.html
(即“django/contrib/admin/templates/admin/change\u form.html”),可以在页面上的
标记之间的任意位置插入此自定义
操作。包括这些区块:

  • {%block form\u top%}
  • {%block after\u related\u objects%}
  • {%block submit\u按钮\u bottom%}

谢谢你的指点,安托万。“另存为新”的行为非常接近,通常是理想的选择,但在这种情况下,我需要清除一些内联模型,否则我会使用“另存为新”选项。这里有足够的内容供我使用,所以我将接受您的回答。我遵循了这个示例,但是我在update()中添加的任何新上下文在submit_line.html模板中都没有任何效果。有什么好处?我使用Django1.5.1.@ PrimHsie422,这是因为上下文没有传递给模板标签的SuMITIL.L.HTML:您应该真正考虑升级Django版本。Django 1.5.1太旧了,不受支持。我没有升级的原因是因为新事务我必须迁移旧代码以使用transaction.commit_手动到新的transaction.atomic机制。嗨,如果我只想在用户“更改”对象而不是“添加”时显示按钮,该怎么办?干净!效果非常好。
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect

class ArticleAdmin(admin.ModelAdmin):

    def render_change_form(self, request, context, *args, **kwargs):
        """We need to update the context to show the button."""
        context.update({'show_save_and_copy': True})
        return super().render_change_form(request, context, *args, **kwargs)

    def response_post_save_change(self, request, obj):
        """This method is called by `self.changeform_view()` when the form
        was submitted successfully and should return an HttpResponse.
        """
        # Check that you clicked the button `_save_and_copy`
        if '_save_and_copy' in request.POST:
            # Create a copy of your object
            # Assuming you have a method `create_from_existing()` in your manager
            new_obj = self.model.objects.create_from_existing(obj)

            # Get its admin url
            opts = self.model._meta
            info = self.admin_site, opts.app_label, opts.model_name
            route = '{}:{}_{}_change'.format(*info)
            post_url = reverse(route, args=(new_obj.pk,))

            # And redirect
            return HttpResponseRedirect(post_url)
        else:
            # Otherwise, use default behavior
            return super().response_post_save_change(request, obj)