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

django管理:单独的只读视图和更改视图,django,django-admin,Django,Django Admin,我想使用django admin生成一个对象的只读视图,其中包含一个“编辑”按钮,该按钮可以将您切换到同一对象的常规更改视图 我知道如何使用readonly属性生成只读视图,但我不知道如何生成两个视图,一个只读视图,另一个允许更改 我希望为此尽可能多地重用管理界面,而不是从头开始编写视图 请注意,这个问题与权限无关:所有用户都有权更改对象。我只是希望他们不要使用“更改”视图,除非他们确实打算进行更改,以降低意外更改或同时更改的风险。您需要更改django admin用于模型表单的模板。将其设置为

我想使用django admin生成一个对象的只读视图,其中包含一个“编辑”按钮,该按钮可以将您切换到同一对象的常规更改视图

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

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


请注意,这个问题与权限无关:所有用户都有权更改对象。我只是希望他们不要使用“更改”视图,除非他们确实打算进行更改,以降低意外更改或同时更改的风险。

您需要更改django admin用于模型表单的模板。将其设置为只读,并在链接到其他url的原始模板中添加一个按钮

注意:

我强烈反对这种方法,因为您肯定不会阻止同时进行更改。这应该通过锁定来解决

另外,我建议使用django反转来保存对象的历史记录并消除“意外更改”风险。

我建议重新考虑使用自定义视图。在generic的帮助下,您将需要编写两行代码。模板也不需要太多工作。您只需扩展标准模板,覆盖
字段集

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

实际上,您可以使用在admin中注册一个模型两次[1]。(代理模型的权限存在一些不一致之处,但在您的案例中可能不是问题。)

似乎也可以注册多个管理站点[2]

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

接口重用本身与视图关系不大,主要与模板和样式相关。然而,正如您正确指出的,视图应该提供接口重用所必需的模板上下文

如果您决定对每个
ModelAdmin
使用多个视图,那么检查
django reversion
项目如何实现其管理集成可能会很有用:

工具书类
  • [1]
  • [2]

您可以创建自定义视图,并在其中显示您的对象

要在管理模块中创建自定义视图,请重写
get\u url()
方法:

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)

在您的模板中,使用
{%extends“admin/base\u site.html”%}
保持管理员的外观。

这里有一个答案,只需几行代码和几处模板更改即可实现我的要求:

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\u 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',                                   
)

下面的代码是使用代理模型实现只读管理。

型号.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)
//只读管理员(仅为此分配“更改”权限)


Django管理员已经知道如何很好地呈现内容,包括标签、帮助文本、隐藏/显示等。如果我编写自己的模板,我不需要复制所有这些功能吗?我不知道如何轻松地扩展change_form.html,因为它试图访问通用视图中不存在的变量。没错,视图还需要提供所有必要的上下文,这可能需要一些工作。无论如何,似乎有更好的方法;我已经更新了答案。谢谢,这看起来是实现我想要的目标的好方法。当我有足够的代表时,我会立即更新投票。我还发布了一个不同的方法,很容易,并且很快会发布第三个方法。你的方法很有趣,不知道只读字段可以根据请求被覆盖。然而,我认为在这里,对模型使用两个
ModelAdmin
s更合适。它更简单,并且允许轻松地实现在这种情况下常见的进一步自定义(例如在任一视图中显示字段或内联线的子集)。您能否提供有关如何执行此操作的更多详细信息?(关于你的其他评论:我不认为你会认为拥有一个对象的只读视图是一个坏主意,不管其他东西是如何设计的。我在这个问题上的唯一目标是通过利用管理界面已经能够很好地呈现事物来获得只读视图。)这与仅使用泛型视图有什么区别?泛型视图只需要几行代码(除了模板之外)?如果可以使用泛型视图获得相同的结果,这应该是一种方法。看起来这将显示一个看起来可编辑的视图,但是,当用户保存页面时,它会悄悄地丢弃任何更改。是的,它会这样做。但是您可以使用modeladmin.save_model()方法抛出警告消息。
class ReviewEntry(CompetitionEntry):
    class Meta:
        proxy = True
    def save(self, *args, **kwargs):
        pass
class CompetitionEntryAdmin(admin.ModelAdmin):
     pass
admin.site.register(CompetitionEntry, CompetitionEntryAdmin)
class ReviewEntryAdmin(admin.ModelAdmin):
    pass
admin.site.register(ReviewEntry, ReviewEntryAdmin)