我想使用django管理员生成一个对象的只读视图,其中包含一个“编辑”按钮,可以切换到同一对象的常见更改视图。
我知道如何使用readonly属性来生成只读视图,但我不知道如何生成两个视图,一个是只读的,一个是允许更改的。
我想尽可能多地重用管理界面,而不是从头开始编写视图。
请注意,此问题与权限无关:所有用户都有权更改对象。只是我希望他们不使用change_view,除非他们打算做出改变,减少意外更改或同时更改的风险。
答案 0 :(得分:17)
这是一个答案,从字面上看我只用了几行代码就做了,只做了几个模板更改:
class MyModelAdmin(admin.ModelAdmin):
fieldsets = [...]
def get_readonly_fields(self, request, obj=None):
if 'edit' not in request.GET:
return <list all fields here>
else:
return self.readonly_fields
现在,change_form的常用网址将生成只读的change_form,但如果您在网址上附加“?edit = 1”,则可以进行修改。
还可以自定义change_form模板,具体取决于URL中是否有“?edit = 1”。为此,请将'django.core.context_processors.request'
放入TEMPLATE_CONTEXT_PROCESSORS
settings.py
,然后在模板中使用request.GET.edit
。
例如,要在不处于编辑模式时添加“编辑”按钮,请插入
{% if not request.GET.edit %}
<li><a href="?edit=1">Edit</a></li>
{% endif %}
<ul class="object-tools">
之后的change_form.html
。
另一个例子是,将change_form.html
更改为包含
{% if save_on_top and request.GET.edit %}{% submit_row %}{% endif %}
表示提交行仅以编辑模式显示。也可以使用此方法隐藏内联等的删除按钮。
供参考,以下是我在settings.py
中的内容:
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.contrib.messages.context_processors.messages',
# Above here are the defaults.
'django.core.context_processors.request',
)
答案 1 :(得分:1)
我建议重新考虑使用自定义视图。在通用 DetailView
的帮助下,您需要编写两行代码。该模板也不需要太多工作。您只需扩展标准change_form.html模板,覆盖field_sets
阻止。
我知道如何使用readonly属性来生成只读视图,但我不知道如何生成两个视图,一个是只读的,一个是允许更改的。
您实际上可以使用proxy models在管理员中注册一个模型[1]两次。 (代理模型的权限存在一些不一致之处,但在您的情况下可能不是问题。)
似乎也可以注册多个管理站点[2]。
我想尽可能多地重用管理界面,而不是从头开始编写视图。
接口重用与视图几乎没有关系,主要是模板和样式相关的东西。但是,View应该提供接口重用所需的模板上下文,正如您正确指出的那样。
如果您决定每个ModelAdmin
使用多个视图,那么检查django-reversion
项目如何实现其管理集成可能很有用:reversion/admin.py。
答案 2 :(得分:0)
您需要更改django admin用于模型表单的模板。将其设为只读,并将链接添加到链接到另一个网址的原始模板。
注意:强>
我强烈反对这种做法,你肯定不会阻止同时发生变化。这应该通过锁定来解决。
另外,我建议使用 django-reversion 来保存对象的历史记录并消除“意外更改”的风险。
答案 3 :(得分:0)
您可以创建自定义视图并在那里显示您的对象。
要在管理模块中创建自定义视图,请覆盖get_urls()
方法:
class MyAdmin(admin.ModelAdmin):
…
def get_urls(self):
urls = super(MyAdmin, self).get_urls()
my_urls = patterns('',
url(r'^custom_view/(?P<my_id>\d+)/$', self.admin_site.admin_view(self.custom_viem), name='custom_view')
)
return my_urls + urls
def custom_view(self, request, my_id):
"""Define your view function as usual in views.py
Link to this view using reverse('admin:custom_view')
"""
from myapp import views
return views.custom_view(request, my_id, self)
在views.py中:
def custom_view(request, object_id, model_admin):
admin_site = model_admin.admin_site
opts = model_admin.model._meta
my_object = get_object_or_404(MyObject, pk=object_id)
# do stuff
context = {
'admin_site': admin_site.name,
'opts': opts,
'title': _('My custom view'),
'root_path': '%s' % admin_site.root_path,
'app_label': opts.app_label,
'my_object': my_object,
}
return render_to_response('my_template.html', context,
context_instance=RequestContext(request))
在您的模板中,使用{% extends "admin/base_site.html" %}
来保持管理员的外观。
答案 4 :(得分:0)
以下代码是使用proxy models.
<强> Models.py 强>
//真实模特
class CompetitionEntry(models.Model):
pass
//代理模型
class ReviewEntry(CompetitionEntry):
class Meta:
proxy = True
def save(self, *args, **kwargs):
pass
<强> admin.py 强>
//可编辑管理员
class CompetitionEntryAdmin(admin.ModelAdmin):
pass
admin.site.register(CompetitionEntry, CompetitionEntryAdmin)
//只读管理员(仅为此分配“更改”权限)
class ReviewEntryAdmin(admin.ModelAdmin):
pass
admin.site.register(ReviewEntry, ReviewEntryAdmin)