Python入门自学进阶-Web框架——23DjangoAdmin项目应用-定制页面
Posted kaoa000
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python入门自学进阶-Web框架——23DjangoAdmin项目应用-定制页面相关的知识,希望对你有一定的参考价值。
一、单个菜单页面实现:类似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找到对应的对象,然后传递到前端,在前端遍历对象中的数据就可以了。
以上是关于Python入门自学进阶-Web框架——23DjangoAdmin项目应用-定制页面的主要内容,如果未能解决你的问题,请参考以下文章
Python入门自学进阶-Web框架——18FormModelForm
Python入门自学进阶-Web框架——18FormModelForm
Python入门自学进阶-Web框架——20Django其他相关知识2