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

Chr*_*ams 6 python django django-admin

我正在使用Django管理员,我希望能够使用模型的现有实例作为制作新对象的模板,因此使用django admin的人不需要重新键入所有相同的属性在制作新物体时,在物体上.

我在Django管理表单底部想象它有点像这样更新单个对象:

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"
Run Code Online (Sandbox Code Playgroud)

但是,对于我来说,如何change model对一个对象上的单个表单执行此操作并不是很清楚,因为我只想一次应用于模型.

我该怎么做?

我猜我可能需要使用change_model形式,但除此之外,我不太确定.

有没有一种快速的方法来做到这一点而不覆盖大量的模板?

Ant*_*ard 7

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

但是,你可以通过一些黑客获得你想要的东西.

首先,您必须覆盖提交行.

your_app /模板/管理/ submit_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>
Run Code Online (Sandbox Code Playgroud)

在上面的模板中,我刚添加了这一行{% if show_save_and_copy %}<input type="submit" value="{% trans 'Create a new item based on this one' %}" name="_save_and_copy" />{% endif %}.所有其他行都来自默认的django实现.

然后你将不得不处理你的按钮'_save_and_copy'

your_app/admin.py

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)
Run Code Online (Sandbox Code Playgroud)

此示例适用于您的具体情况,如果您需要,可以使其更通用.

话虽如此,根据您的具体情况,您也可以单击"保存并继续"保存您的工作,然后单击"另存为新"以复制它.不是吗?


The*_*tor 6

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

from django.db.models import Model

from django.contrib import admin, messages
from django.contrib.admin.options import (
    unquote,
    csrf_protect_m,
    HttpResponseRedirect,
)


class ArticleAdmin(admin.ModelAdmin):
    change_form_template = 'book/admin_change_form_book.html'

    actions = ['make_published']

    def make_published(self, request, queryset):
        if isinstance(queryset, Model):
            obj = queryset
            obj.status = 'p'
            obj.save()
            updated_count = 1
        else:
            updated_count = queryset.update(status='p')

        msg = "Marked {} new objects from existing".format(updated_count)
        self.message_user(request, msg, messages.SUCCESS)

    make_published.short_description = "Mark selected stories as published"

    @csrf_protect_m
    def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
        if request.method == 'POST' and '_make_published' in request.POST:
            obj = self.get_object(request, unquote(object_id))
            self.make_published(request, obj)
            return HttpResponseRedirect(request.get_full_path())

        return admin.ModelAdmin.changeform_view(
            self, request,
            object_id=object_id,
            form_url=form_url,
            extra_context=extra_context,
        )

Run Code Online (Sandbox Code Playgroud)

现在您可以<input>为自定义模板视图添加一个用于操作的操作(此示例book/admin_change_form_book.html在 change_form_template 中使用)

{% extends 'admin/change_form.html' %}

{% block form_top %}
<input
    type="submit"
    name="_make_published"            
    value="Mark Published"
    class="grp-button grp-default"
>
{% endblock %}
Run Code Online (Sandbox Code Playgroud)

如果您查看admin/change_form.html(即“django/contrib/admin/templates/admin/change_form.html”),您可以在页面上的标记<input>之间的任何位置插入此自定义操作<form...> </form>。包括这些块:

  • {% block form_top %}
  • {% block after_related_objects %}
  • {% block submit_buttons_bottom %}