django admin:单独的只读视图和更改视图

时间:2011-07-13 14:35:32

标签: django django-admin

我想使用django管理员生成一个对象的只读视图,其中包含一个“编辑”按钮,可以切换到同一对象的常见更改视图。

我知道如何使用readonly属性来生成只读视图,但我不知道如何生成两个视图,一个是只读的,一个是允许更改的。

我想尽可能多地重用管理界面,而不是从头开始编写视图。

请注意,此问题与权限无关:所有用户都有权更改对象。只是我希望他们不使用change_view,除非他们打算做出改变,减少意外更改或同时更改的风险。

5 个答案:

答案 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)