【发布时间】:2017-08-14 14:10:29
【问题描述】:
管理操作似乎适用于django 管理界面的列表视图中选择的几个项目:
就我而言,我希望在更改(一项)视图上有一个简单的操作按钮。
有没有办法让 django 管理操作在那里可用?
我知道我可以通过转到列表视图并在那里选择一项来解决这个问题。但是直接提供会更好。
【问题讨论】:
标签: django django-admin
管理操作似乎适用于django 管理界面的列表视图中选择的几个项目:
就我而言,我希望在更改(一项)视图上有一个简单的操作按钮。
有没有办法让 django 管理操作在那里可用?
我知道我可以通过转到列表视图并在那里选择一项来解决这个问题。但是直接提供会更好。
【问题讨论】:
标签: django django-admin
在您的应用中为您的模型创建一个模板。
templates/admin/<yourapp>/<yourmodel>/change_form.html
使用此示例内容在更改现有对象时添加按钮。
{% extends "admin/change_form.html" %}
{% block submit_buttons_bottom %}
{{ block.super }}
{% if original %} {# Only show if changing #}
<div class="submit-row">
<a href="{% url 'custom-model-action' original.pk %}">
Another action
</a>
</div>
{% endif %}
{% endblock %}
将该操作链接到任何 url 并重定向回您的模型更改对象视图。 More information about extending admin templates.
更新:添加了对现有对象进行自定义操作的完整常见用例
urls.py
urlpatterns = [
url(r'^custom_model_action/(?P<object_pk>\d+)/$',
core_views.custom_model_action, name='custom-model-action')
]
views.py
from django.urls import reverse
from django.contrib import messages
from django.http import HttpResponse, HttpResponseRedirect
def custom_model_action(request, object_pk):
messages.info(request, 'Performed custom action!')
return HttpResponseRedirect(
reverse('admin:<yourapp>_<yourmodel>_change', args=[object_pk])
)
【讨论】:
from django.urls import reverse
与主题启动者询问的不同,但此 sn-p 允许从列表页面上以 最少代码量
执行单个对象操作BaseAction 代码
class AdminActionError(Exception):
pass
class AdminObjectAction:
"""Base class for Django Admin actions for single object"""
short_description = None
exp_obj_state = {}
def __init__(self, modeladmin, request, queryset):
self.admin = modeladmin
self.request = request
self.queryset = queryset
self.__call__()
def validate_qs(self):
count = self.queryset.count()
if count != 1:
self.error("You must select one object for this action.")
if self.exp_obj_state:
if self.queryset.filter(**self.exp_obj_state).count() != 1:
self.error(f'Selected object does not meet the requirements: {self.exp_obj_state}')
def error(self, msg):
raise AdminActionError(msg)
def get_object(self):
return self.queryset.get()
def process_object_action(self, obj):
pass
def validate_obj(self, obj):
pass
def __call__(self, *args, **kwargs):
try:
self.validate_qs()
obj = self.get_object()
self.validate_obj(obj)
except AdminActionError as e:
self.admin.message_user(self.request, f"Failed: {e}", level=messages.ERROR)
else:
with transaction.atomic():
result = self.process_object_action(obj)
self.admin.message_user(self.request, f"Success: {self.short_description}, {result}")
自定义操作[最少代码量]
class RenewSubscriptionAction(AdminObjectAction):
short_description = 'Renew subscription'
exp_obj_state = {
'child': None,
'active_status': True,
}
def process_object_action(self, obj):
manager = RenewManager(user=obj.user, subscription=obj)
return manager.process()
AdminClass
class SomeAdmin(admin.ModelAdmin):
actions = [RenewSubscriptionAction]
【讨论】:
内置的管理操作对查询集进行操作。
您可以使用 calable 来执行您想要的操作或显示其他内容:
class ProductAdmin(admin.ModelAdmin):
list_display ('name' )
readonly_fields('detail_url)
def detail_url(self, instance):
url = reverse('product_detail', kwargs={'pk': instance.slug})
response = format_html("""<a href="{0}">{0}</a>""", product_detail)
return response
或使用表格
class ProductForm(forms.Form):
name = forms.Charfield()
def form_action(self, product, user):
return Product.value(
id=product.pk,
user= user,
.....
)
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
# render buttons and links to
def product_actions(self, obj):
return format_html(
'<a class="button" href="{}">Action1</a> '
'<a class="button" href="{}">Action 2</a>',
reverse('admin:product-action-1', args=[obj.pk]),
reverse('admin:aproduct-action-3', args=[obj.pk]),
)
【讨论】:
如果你真的需要单个对象,我建议你使用这个解决方案,例如:
class Gallery(TimeStampedModel):
title = models.CharField(max_length=200)
attachment = models.FileField(upload_to='gallery/attachment/%Y/%m/%d')
def __str__(self):
return self.title
def process_button(self):
return ('<button id="%(id)s class="btn btn-default process_btn" '
'data-value="%(value)s>Process</button>' % {'id': self.pk, 'value': self.attachment.url})
process_button.short_description = 'Action'
process_button.allow_tags = True
在您的admin.py 中,将process_button 插入list_display;
class GalleryAdmin(admin.ModelAdmin):
list_display = ['title', 'process_button', 'created']
search_fields = ['title', 'pk']
....
class Media:
js = ('path/to/yourfile.js', )
那么,在yourfile.js里面,你也可以处理它..
$('.process_btn').click(function(){
var id = $(this).attr('id'); // single object id
var value = $(this).data('value'); // single object value
...
});
希望对您有所帮助..
【讨论】: