我正在与Django管理员合作,我希望能够使用模型的现有实例作为制作新对象的模板,因此使用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"
但是,对于我来说,如何对一个对象上的单个change model
表单执行此操作并不是很清楚,对于我一次只想应用于模型的操作。
我该怎么做?
我猜我可能需要用change_model form进行攻击,但除此之外,我不太确定。
有没有一种快速的方法可以在不覆盖大量模板的情况下执行此操作?
答案 0 :(得分:5)
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>
在上面的模板中,我刚添加了行{% if show_save_and_copy %}<input type="submit" value="{% trans 'Create a new item based on this one' %}" name="_save_and_copy" />{% endif %}
。所有其他行都是from default django implementation。
然后你必须处理你的按钮'_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)
此示例适用于您的具体情况,如果您需要,可以使其更通用。
话虽如此,对于您的具体情况,您也可以单击“保存并继续”以保存您的工作,然后单击“另存为新”以复制它。不是吗?
答案 1 :(得分:2)
如前所述,没有办法,需要被黑客入侵。我认为这是一个优雅的技巧,可以在列表和更改表单视图中添加自定义操作。它实际上并不保存表单,而只是对当前对象执行任何所需的自定义操作,然后将您返回到相同的更改表单页面。
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,
)
现在,您可以将操作的<input>
添加到自定义模板视图中(此示例在change_form_template中使用book/admin_change_form_book.html
)
{% extends 'admin/change_form.html' %}
{% block form_top %}
<input
type="submit"
name="_make_published"
value="Mark Published"
class="grp-button grp-default"
>
{% endblock %}
如果您查看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 %}