【问题标题】:Add a link to custom django admin view添加指向自定义 django 管理视图的链接
【发布时间】:2018-12-10 19:56:29
【问题描述】:

我已经创建了一个自定义管理视图,记录在 here

class MyAdmin(admin.ModelAdmin):
    def get_urls(self):
        urls = super().get_urls()
        my_urls = [
            path('stats/', self.admin_site.admin_view(self.stats)),
        ]
        return my_urls + urls

    def stats(self, request):
        request.current_app = self.admin_site.name

        context = dict(
           # Include common variables for rendering the admin template.
           self.admin_site.each_context(request),
           # Anything else you want in the context...
           key='blah',
        )
        return TemplateResponse(request, "sometemplate.html", context)

网址正在运行,模板正在加载。 但是,我怎样才能将我的新自定义视图链接到 Django 管理员的概述中?

【问题讨论】:

标签: django django-admin


【解决方案1】:

已经有一个类似的问题How do you add a new entry into the django admin index?,但提供的所有答案对我来说都不是很满意。

因此,我浏览了源代码,并正在寻找一种不涉及覆盖任何模板的可能性,既不是index.html,也不是app_index.html

文件django/contrib/admin/sites.py包含负责渲染index.htmlapp_index.html的代码,第一个是显示问题中所示内容的模板。

方法index 渲染模板index.html 并显示注册模型管理员的可用应用程序。它使用方法get_app_list 来获取应用程序。在这个方法中调用了方法_build_app_dict,获取模型和模型管理员。

方法app_index 呈现模板app_index.html 并显示单个应用程序的注册模型管理员。它使用了前面提到的方法_build_app_dict

因此,我决定在我的自定义管理员中覆盖此方法。根据问题中的示例,它可能看起来像这样(与原始示例的差异以粗体显示):

class MyAdmin(admin.AdminSite):
    def get_urls(self):
        urls = super().get_urls()
        my_urls = [
            path('stats/', self.admin_site.admin_view(self.stats), name='stats'),
        ]
        return my_urls + urls

    def stats(self, request):
        request.current_app = self.admin_site.name

        context = dict(
           # Include common variables for rendering the admin template.
           self.admin_site.each_context(request),
           # Anything else you want in the context...
           key='blah',
        )
        return TemplateResponse(request, "sometemplate.html", context)

    def _build_app_dict(self, request, label=None):
        # we create manually a dict to fake a model for our view 'stats'
        # this is an example how the dict should look like, i.e. which keys
        # should be present, the actual values may vary
        stats = {
            'name': 'Stats',
            'admin_url': reverse('my_admin:stats'),
            'object_name': 'Stats',
            'perms': {'delete': False, 'add': False, 'change': False},
            'add_url': ''
        }
        # get the app dict from the parent method
        app_dict = super(MyAdmin, self)._build_app_dict(request, label)
        # check if there is value for label, then the app_index will be rendered
        if label:
            # append the manually created dictionary 'stats'
            app_dict['models'].append(stats)
        # otherwise the index will be rendered
        # and we have to get the entry for our app,
        # which is in this case 'traffic'
        # using TrafficConfig.name or TrafficConfig.label
        # might be better than hard coding the value
        else:
            app = app_dict.get('traffic', None)
            # if an entry for 'traffic' has been found
            # we append our manually created dictionary
            if app:
                app['models'].append(stats)
        return app_dict

my_admin = MyAdmin(name='my_admin')
my_admin.register(Traffic)

现在,当我们打开自定义管理员时,我们会看到如下内容:


TRAFFIC
---------------------------------  
  Traffics    + Add   \ Change  
  Stats               \ Change  

这是因为我们操纵了用于渲染模板的字典,它使用了我们指定的值,在这种情况下,最相关的是 name Statsadmin_url 将调用自定义视图stats。由于我们将add_url留空,因此不会显示+添加链接。

重要的是倒数第二行,在这里我们调用我们的自定义管理员并传递一个名称,它将用作 url 命名空间。

编辑:
不幸的是,我在发布答案后才注意到问题是询问如何显示在ModelAdmin 中创建的自定义视图的链接,而我的答案解释了如何为自定义管理员AdminSite 执行此操作。我希望它仍然有一些帮助。

【讨论】:

    【解决方案2】:

    虽然不是一个好办法,但是你可以尝试覆盖django admin的默认index.html为:

       {% for model in app.models %}
            <tr class="model-{{ model.object_name|lower }}">
            {% if model.admin_url %}
                <th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
            {% else %}
                <th scope="row">{{ model.name }}</th>
            {% endif %}
    
            {% if model.add_url %}
                <td><a href="{{ model.add_url }}" class="addlink">{% trans 'Add' %}</a></td>
            {% else %}
                <td>&nbsp;</td>
            {% endif %}
    
            {% if model.admin_url %}
                <td><a href="{{ model.admin_url }}" class="changelink">{% trans 'Change' %}</a></td>
            {% else %}
                <td>&nbsp;</td>
            {% endif %}
            </tr>
    
       {% endfor %}
        <!-- extra link you want to display -->
        <tr>
        <th scope="row"><a href="link_url">link_name</a></th>
        <td><a href="link_url" class="changelink">{% trans 'Change' %}</a></td>
        </tr>
    

    覆盖此块后,将 index.html 放入项目的模板/管理目录中。希望这会有所帮助。

    【讨论】:

    • 这个方案不能用应用实现,只能用项目模板文件夹对吧?
    • 是的,整个项目都需要覆盖它。
    • 好的,如果我们找不到任何基于应用的答案,这最终可能是一种“解决方法”。
    • 还有其他更简洁的方法来实现这一点吗?
    【解决方案3】:

    我知道这有点老了,但我遇到了同样的问题,我找到了一种更简单(但可能更混乱)的方法,它不涉及覆盖模板或方法。

    我刚刚在models.py中创建了一个代理模型如:

    class Proxy(models.Model):
    
        id = models.BigAutoField(db_column='id', primary_key=True)
    
        def __str__(self):
            return "<Label: id: %d>" % self.id
    
        class Meta:
            managed = False
            verbose_name_plural = 'proxies'
            db_table = 'proxy'
            ordering = ('id',)
    

    这只是一个从现有表创建的 mysql 视图

     create view proxy
        as select id
        from samples
        LIMIT 10;
    

    最后在 admin.py

    @admin.register(Proxy)
    class LabelAdmin(admin.ModelAdmin):
        change_list_template = 'label_view.html'
        def changelist_view(self, request, extra_context=None):
          ...
            return render(request, "label_view.html", context)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-09
      • 2014-06-23
      • 1970-01-01
      • 2019-10-08
      • 1970-01-01
      • 2016-08-11
      • 2021-05-13
      • 1970-01-01
      相关资源
      最近更新 更多