Python入门自学进阶-Web框架——23、DjangoAdmin项目应用-定制页面

一、单个菜单页面实现:类似DjangoAdmin中点击一个管理表打开的样子。

以客户首页为例:

这里cust_index就是路由表中的name字段的值,即别名,对应的就是路由项中的cust.html,即对应视图函数cust_index。

 视图函数:

def cust_index(req):
    return render(req,"cust/cust_index.html")

 返回的是/templates下的cust子目录下的cust_index.html文件:

 此时的cust_index.html:

{% extends "index.html" %}

{% block page-content %}
    客户首页
{% endblock %}

 超级用户登陆后点击客户首页菜单项:

 对于菜单项显示,主要程序如下:

        <ul class="nav flex-column">
          {% for role in request.user.userprofile.roles.all %}
              <!-- {{ role }}    测试role的值-->   
            {% for menu in role.menus.all %}
                <li class="nav-item">
                <a class="nav-link active" href="{%  url menu.url_name %}">
              <span data-feather="home"></span>
                    {{ menu.name }} <span class="sr-only">(current)</span>
            </a>
          </li>
            {% endfor %}

          {% endfor %}

        </ul>

对于应用DjangoAdmin的项目,request即请求对象中会带有对应的登录用户信息,即request.user是登录的用户的类,DjangoAdmin已经将user加入request中了(相应的,还有一些如request.session、request.method、),通过这个对象,可以链式关联到UserProfile,再关联到roles,在模板中使用all列出所有roles,也可以使用select_related,{{role}}打印的是role类的__str__()方法的返回值。这是for外循环遍历role,for内循环是对role关联的菜单进行循环,role.menus关联角色的菜单项,all是取所有菜单项,进行遍历,此时menu就是一个个menu类,{% url menu.url_name %},menu.url_name取出menu类中url_name属性值,就是路由项的别名,url 别名就是解析别名,解析成正确的路由项,这里就是/plcrm/cust.html,当点击菜单,通过路由项,找到对应的视图函数view.cust_index,函数返回对应的静态页面cust/cust_index.html。

通过上面的分析,如果角色中菜单项重复,则在页面中就会重复显示菜单项。如超级用户再加一个销售角色,如下:(暂时先搁置解决)

 二、管理首页的实现

看DjangoAdmin登录后的页面:

我们就是要自己实现这个页面。

首先是要显示这些表(或Model类),需要在admin.py中进行注册,我们模拟admin.py,写自己的admin.py。

创建自己的App来实现这些功能,创建mytestapp,在此app下创建mytestapp_admin.py

 

 mytestapp_admin.py模拟admin.py的功能,定义一个全局字典,用来保存app名以及Models类名以及admin_class类,即配置类,如:
enable_admins = {“plcrm”:{“Customer”:“CustomerAdmin”},}

app的名字,可以通过:models.Customer._meta.app_label获取到。

from plcrm import models

enable_admins = {}
# 定义全局字典,用于保存项目、表名、admin_class的对应关系,最终形式如下
# {'plcrm': {'customer': <class 'mytestapp.mytestapp_admin.CustomerAdmin'>, }}

class BaseAdmin(object):
    list_display = []
    list_filter = []

class CustomerAdmin(BaseAdmin):
    list_display = ['qq','name']

class CustomerFollowUpAdmin(BaseAdmin):
    list_display = ['content','intention']

def register(model_class,admin_class=None):
    if model_class._meta.app_label not in enable_admins:
        enable_admins[model_class._meta.app_label] = {}
    admin_class.model = model_class  
    # 将Models类与admin_class绑定,这样通过admin_class就很容易找到对应的Models类
    enable_admins[model_class._meta.app_label][model_class._meta.model_name] = admin_class

register(models.Customer,CustomerAdmin)
register(models.CustomerFollowUp,CustomerFollowUpAdmin)

查询项目中类的相关信息,可以在项目目录下执行python manage.py shell,然后导入相关类:

 ============================================

启动python有两种方式:python manage.py shell和python。

这两个命令 都会启动交互解释器,可是manage.py shell命令有一个重要的不一样: 在启动解释器以前,它告诉Django使用 哪一个设置文件。 Django框架的大部分子系统,包括模板系统,都依赖于配置文件;若是Django不知道使用哪 个配置文件,这些系统将不能工做。

其背后的工作原理,DJANGO_SETTINGS_MODULE环境变 量,它被设置在settings.py中。例如,假设mysite在你的Python搜索路径中,那么 DJANGO_SETTINGS_MODULE应该被设置为:’mysite.settings’。
当你运行命令:python manage.py shell,它将自动帮你处理DJANGO_SETTINGS_MODULE。 在当前的这 些示例中,使用`` python manage.py shell``这个方法,能够免去配置环境变量。
随着你愈来愈熟悉Django,你可能会偏向于废弃使用`` manage.py shell`` ,而是在你的配置文 件.bash_profile中手动添加 DJANGO_SETTINGS_MODULE这个环境变量。

因此,另两种解决方案就是:

1.使用 python manage.py shell启动Pythonit

2.在你的配置文 件.bash_profile中手动添加 DJANGO_SETTINGS_MODULE这个环境变量。

在终端,通过python manage.py shell,
使用这个命令而不是简单的使用“python”是因为 manage.py 会设置 DJANGO_SETTINGS_MODULE 环境变量,这个变量会让 Django 根据 mysite/settings.py 文件来设置 Python 包的导入路径。

映射,通过字符串引入模块:
正常引入:from crm import models
现在有字符串“crm” 
import importlib
importlib.import_module("crm")
models = importlib.import_module("crm.models")

char_crm = "crm.models"
models = importlib.import_module(char_crm)

models.Customer

====================================================

前端显示项目名称和model类名称的代码:

{% for app_name,app_tables in table_list.items %}
          <table class="table">
              <thead>
                    <tr class="text-danger" style="background-color: #9fcdff;">
                      <th colspan="3">{{ table_list }} {{ app_name }}</th>
                    </tr>
              </thead>
              <tbody>
                    {% for  table_name,admin in app_tables.items %}
                    <tr class="border-bottom">
                      <td style="padding-bottom: 3px;padding-top: 3px;">{{table_name}}</td>
                      <td style="padding-bottom: 3px;padding-top: 3px;">Add</td>
                      <td style="padding-bottom: 3px;padding-top: 3px;">Change</td>
                    </tr>
                    {% endfor %}
              </tbody>
          </table>
 {% endfor %}

页面显示如下:

 看DjangoAdmin的显示结果,第一列显示的Model类的名称复数形式,通过在python manage.py shell中查询:

 将{{table_name}}换成{{ admin.model._meta.object_name }},结果就应该显示Model对象名称:

注意:是admin中包含了Model对象。

<tr class="border-bottom">
    <td style="padding-bottom: 3px;padding-top: 3px;">{{admin.model._meta.object_name}} 
    </td>
    <td style="padding-bottom: 3px;padding-top: 3px;">Add</td>
    <td style="padding-bottom: 3px;padding-top: 3px;">Change</td>
 </tr>

此时前端会出现错误:

错误原因是模板中变量或属性中不能有以下划线开始的变量或属性,这里就是_meta。解决的方法是使用自定义标签:

在mytestapp应用下,创建包templatetags,在包中创建python文件:

 

 在前端使用自定义标签:

文件开始引入标签:{% load tags %}

 <td style="padding-bottom: 3px;padding-top: 3px;">{{admin.model._meta.object_name}} 修改为

 <td style="padding-bottom: 3px;padding-top: 3px;">{%render_app_name admin%} 

 这就与DjangoAdmin差不多了。实际上观察DjangoAdmin的首页,显示的是Users,后面多了个s。

如果Model类中没有定义verbose_name和verbose_name_plural,django的admin管理界面在显示这个model的名称时,会将驼峰式的名称拆分为独立的单词,并最后一个单词使用复数。例如User显示为“Users”,“CustomerFollowUp”这个model,在admin中会被显示为“Customer follow ups”,十分难看。

models.Model类的内部类Meta,有两个特殊的选项:verbose_name和verbose_name_plural。顾名思义,verbose_name为model提供了一个更容易让人阅读的名称,而verbose_name_plural则是这个名称的复数形式。只定义verbose_name,最终显示的是verbose_name后加上s,只定义verbose_name_plural,显示的就是其本身,二者都定义,显示verbose_name_plural。所以将自定义标签修改为返回verbose_name_plural。

from django import template

register = template.Library()

@register.simple_tag
def render_app_name(admin_class):
    return admin_class.model._meta.verbose_name_plural

 三、 具体页面页面的实现

点击客户首页菜单,实现类似如下的功能页面,就是djangoAdmin的表管理功能

有查询、过滤、列表等

 注意的点,除了页面的内容,还要注意地址栏的变化,客户表的地址:http://127.0.0.1:80/admin/plcrm/customer/,是app名称加上表名的小写形式。那么,通过表名能否映射到表对应的Model类?有了Model类,就可以列出各个字段的数据。所以我们要做的就是获取app名称和相应的表名称,传递给一个统一的处理模板,循环展示数据就可以了。

对于路由项,因为是要匹配应用名和表明,所以使用匹配项,如下:path('<str:app_name>/<str:table_name>/',views.display_table_objs,name="table_objs")

就是说匹配到mytestapp/app名/表名/的格式,就转到视图函数display_table_objs进行处理。这个路由项的别名是table_objs

视图函数的框架如下:

def display_table_objs(req,app_name,table_name):
    print("====>",app_name,table_name)
    return render(req,"mytestapp/table_objs.html",{})

 前端的index.html进行修改,将表名加上链接:

<td style="padding-bottom: 3px;padding-top: 3px;">
    <a href="{% url 'table_objs' app_name table_name %}">{% render_app_name admin %}</a>
</td>

点击对应的表名,进入相应表的管理页面:

 

 现在的问题是怎么通过app_name和table_name找到对应的对象,然后传递到前端,在前端遍历对象中的数据就可以了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值