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

2023-11-08

一、单个菜单页面实现:类似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找到对应的对象,然后传递到前端,在前端遍历对象中的数据就可以了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • API 端点的 Django 子域配置

    我已经建立了一个 Django 项目 它使用django rest framework提供一些 ReST 功能 网站和其他功能都运行良好 然而有一个小问题 我需要我的 API 端点指向一个不同的子域 例如 当用户访问该网站时 他 她可以根据
  • 与 iexact 一起使用时,Django get_or_create 无法设置字段

    我想用name iexact with get or create尽可能避免用户输入字段的重复 我的提供者模型有一个名称字段 我在其中使用get or create 查找工作正常 但在第一次创建实例时 如下面的 p1 Timber 示例 名
  • Python:记录垃圾收集器

    我有一个 python 应用程序 有一些性能问题 我想将垃圾收集器的事件 特别是何时调用 添加到我的日志中 是否可以 thanks http docs python org library gc html gc set debug http
  • Python 中的安全解除引用

    Groovy 有一个很好的安全取消引用运算符 这有助于避免 NullPointerExceptions variable method The method仅当以下情况时才会被调用variable is not null 有没有办法在 Py
  • Python sqlite3游标没有属性commit

    当我运行这段代码时 path Scripts wallpapers single png conn sqlite3 connect Users Heaven Library Application Support Dock desktopp
  • conda 无法从 yml 创建环境

    我尝试运行下面的代码来从 YAML 文件创建虚拟 Python 环境 我在 Ubuntu 服务器上的命令行中运行代码 虚拟环境名为 py36 当我运行下面的代码时 我收到下面的消息 环境也没有被创建 这个问题是因为我有几个必须使用 pip
  • 如何从谷歌云存储桶读取音频文件并在datalab笔记本中使用ipd播放

    我想在数据实验室笔记本中播放我从谷歌云存储桶中读取的声音文件 这个怎么做 import numpy as np import IPython display as ipd import librosa import soundfile as
  • html 解析器 python

    我正在尝试解析一个网站 我正在使用 HTMLParser 模块 问题是我想解析第一个 a href 评论后 但我真的不知道该怎么做 所以我在文档中发现有一个函数叫做handle comment 但我还没有找到如何正确使用它 我有以下内容 i
  • 字典中的列表,Python 中的循环

    我有以下代码 TYPES hotmail type hotmail lookup mixed dkim no signatures S Return Path email protected cdn cgi l email protecti
  • Python 正则表达式部分匹配或“hitEnd”

    我正在编写一个扫描器 因此我将任意字符串与正则表达式规则列表进行匹配 如果我可以模拟 Java hitEnd 功能 不仅知道正则表达式何时不匹配 还知道何时匹配 这将非常有用 can t匹配 当正则表达式匹配器在决定拒绝输入之前到达输入末尾
  • 如何使用循环将十进制转换为二进制?

    我想编写一个程序 将十进制数 0 到 9 转换为二进制数 我可以编写如何使用重复除法将十进制数转换为二进制数的代码 但是 我在创建一个以二进制格式打印十进制数字 0 到 9 的循环时遇到了麻烦 这是我的代码 number 0 remaind
  • 为 Networkx 图添加标题?

    我希望我的代码创建一个带有标题的图 使用下面的代码 可以创建绘图 但没有标题 有人可以告诉我我做错了什么吗 import pandas as pd import networkx as nx from networkx algorithms
  • 如何使用 Pandas 将巨大的 CSV 转换为 SQLite?

    我有一个巨大的表 大约 60 GB 采用存档的 CSV 文件形式 我想将其转换为 SQLite 文件 我现在所做的事情如下 import pandas import sqlite3 cnx sqlite3 connect db sqlite
  • 杂乱的扭曲连接在不干净的时尚中消失了。没有代理。已经尝试过标题

    我正在尝试抓取这个网站 https www5 apply2jobs com jupitermed ProfExt index cfm fuseaction mExternal searchJobs https www5 apply2jobs
  • pip 安装软件包两次

    不幸的是我无法重现它 但我们已经见过几次了 pip 将一个软件包安装两次 如果卸载第一个 第二个就会可见并且也可以被卸载 我的问题 如果一个包安装了两次 如何用 python 检查 背景 我想编写一个测试来检查这一点 devOp Updat
  • 求解不等式系统时“多项式错误:仅允许使用单变量多项式”

    我想找到以下两个常数的区间cons1 and cons2我写了下面的代码 from sympy import Poly from sympy import Abs from sympy solvers inequalities import
  • smooth_idf 是多余的吗?

    The scikit learn 文档 http scikit learn org stable modules generated sklearn feature extraction text TfidfTransformer html
  • 如何在C++中列出Python模块的所有函数名称?

    我有一个 C 程序 我想导入一个 Python 模块并列出该模块中的所有函数名称 我该怎么做 我使用以下代码从模块中获取字典 PyDictObject pDict PyDictObject PyModule GetDict pModule
  • SQLAlchemy:避免声明式样式类定义中的重复

    我正在使用 SQLAlchemy 并且我的对象模型中的许多类具有相同的两个属性 id 和 整数和主键 以及名称 字符串 我试图避免在每个类中声明它们 如下所示 class C1 declarative base id Column Inte
  • 获取调用者文件的绝对路径

    假设我在不同的目录中有两个文件 1 py 比如说 在C FIRST FOLDER 1 py and 2 py 比如说 在C SECOND FOLDER 2 py 文件1 py进口2 py using sys path insert 0 pa

随机推荐