我的第一個python web開發框架(36)——後臺菜單管理功能

来源:https://www.cnblogs.com/EmptyFS/archive/2018/08/30/9557316.html
-Advertisement-
Play Games

對於後臺管理系統來說,要做好許可權管理離不開菜單項和頁面按鈕控制項功能的管理。由於程式沒法智能的知道有什麼菜單和控制項,哪些人擁有哪些操作許可權,所以首先要做的是菜單管理功能,將需要管理的菜單項和各個功能項添加(註冊)到菜單管理表中,方便後續許可權控制管理。 要開發一個菜單管理功能,離不開這些功能:菜單列表展 ...


  對於後臺管理系統來說,要做好許可權管理離不開菜單項和頁面按鈕控制項功能的管理。由於程式沒法智能的知道有什麼菜單和控制項,哪些人擁有哪些操作許可權,所以首先要做的是菜單管理功能,將需要管理的菜單項和各個功能項添加(註冊)到菜單管理表中,方便後續許可權控制管理。

  要開發一個菜單管理功能,離不開這些功能:菜單列表展示(需要菜單列表獲取介面)、新增菜單(新增介面)、編輯菜單(獲取菜單記錄以及提交修改介面)、刪除菜單(刪除介面),由於菜單是多層級的關係,所以還需要增加菜單樹列表獲取介面來綁定菜單層級,在主頁面還需要增加菜單列表項輸出介面,用來展示菜單項。

  在正式編寫菜單管理功能之前,我們需要先在邏輯層(logic文件夾)中添加菜單邏輯類:menu_info_logic.py,繼承前面我們開發的ORM基類,讓當前的菜單管理邏輯類擁有ORM的所有方法。

#!/usr/bin/env python
# coding=utf-8

from logic import _logic_base
from config import db_config


class MenuInfoLogic(_logic_base.LogicBase):
    """菜單管理表邏輯類"""

    def __init__(self):
        # 表名稱
        __table_name = 'menu_info'
        # 初始化
        _logic_base.LogicBase.__init__(self, db_config.DB, db_config.IS_OUTPUT_SQL, __table_name)

  為了方便管理,我們在api文件中創建system文件夾,用來存放所有後臺許可權管理功能的代碼,並創建menu_info.py文件,來存放菜單管理介面

  

  

  接下來我們先實現菜單列表獲取介面,由第一部分的後端管理功能可以知道,我們前端使用的是jqGrid插件,這一塊我們在前面已經實現過了,而ORM中也封裝好對應的方法,所以直接調用就可以了。(這個介面在實現時,我們要瞭解清楚的是,前端插件jqGrid它會傳遞什麼參數和需要返回什麼格式的數據回去)

  jqGrid會通過介面,將當前頁面索引值page、頁面顯示記錄行數rows、排序欄位sidx和排序方式sord(順序或倒序)提交到伺服器端介面,如果我們使用樹列表,它還會提交當前節點id參數nodeid

  所以我們在伺服器端介面需要做好這幾個參數的接收與使用操作,然後我們通過調用前面實現的ORM的get_list方法,就可以獲取對應的數據返回給客戶端了,具休代碼如下:

 1 @get('/system/menu_info/')
 2 def callback():
 3     """
 4     獲取列表數據
 5     """
 6     # 菜單列表中,當前節點id,即父節點id
 7     parent_id = convert_helper.to_int0(web_helper.get_query('nodeid', '', is_check_null=False))
 8     # 頁面索引
 9     page_number = convert_helper.to_int1(web_helper.get_query('page', '', is_check_null=False))
10     # 頁面頁碼與顯示記錄數量
11     page_size = convert_helper.to_int0(web_helper.get_query('rows', '', is_check_null=False))
12     # 接收排序參數
13     sidx = web_helper.get_query('sidx', '', is_check_null=False)
14     sord = web_helper.get_query('sord', '', is_check_null=False)
15     # 初始化排序欄位
16     order_by = 'sort asc'
17     if sidx:
18         order_by = sidx + ' ' + sord
19 
20     _menu_info_logic = menu_info_logic.MenuInfoLogic()
21     # 讀取記錄
22     wheres = 'parent_id=' + str(parent_id)
23     result = _menu_info_logic.get_list('*', wheres, page_number, page_size, order_by)
24     if result:
25         return json.dumps(result)
26     else:
27         return web_helper.return_msg(-1, "查詢失敗")

  7到18行,是接收參數。

  20行初始化菜單邏輯類

  22行是設置查詢條件,預設菜單列表我們只顯示第一級菜單,也就是父id為0的菜單。在列表第一次載入時,列表提交上來的nodeid為空(即父節點為預設為0),所以設置查詢條件時父節點會賦值為parent_id=0。當我們點擊樹菜單展開時,才載入下一級菜單出來,這時jqGrid控制項會再次訪問介面,提交當前要展開發節點id給介面,介面接收到參數以後返回對應的子節點列表給客戶端。

  get_list是前端ORM中封裝好的參數,它會返回jqGrid所需要的數據格式,所以第25行直接將符合jqGrid要求的數據返回給列表展示出來。

 

  我們在後臺main.html中添加菜單,方便登錄後臺查看效果

  前端菜單管理的hmtl頁面大家自行下載源碼包查看,下麵是完成後展示效果

  由於當前還沒有數據,所以暫時列表是空的,下麵我們創建添加和修改功能

 

  先看看新增頁面效果(頁面內容項一般我們是根據數據字典和原型來設計的,大家可以參照一下上一章菜單管理的數據結構)

  我們需要接收頁面提交上來的這些參數,然後向資料庫中添加一條記錄

  上級菜單選項,這裡我們點擊選擇時,需要顯示菜單樹列表,讓我們選擇當前新增菜單項所屬菜單層級,方便菜單層級的管理,如果為頂級菜單,則不需要進行選擇

  為了讓後臺菜單好看一些,我們可以增加菜單小圖標,H-ui框架中,提供了字體圖標,這裡的查看增加鏈接到官網中,可以直接查詢字體圖標編碼複製過來使用

  排序可以輸入任意的數字,通過從 小到大順序排列菜單項,為了方便排序項可以自行累加,代碼中可以獲取當前菜單層級最大值加1的方式來進行賦值

 1 @post('/api/system/menu_info/')
 2 def callback():
 3     """
 4     新增記錄
 5     """
 6     name = web_helper.get_form('name', '菜單名稱')
 7     icon = web_helper.get_form('icon', '菜單小圖標', True, 10, False, is_check_special_char=False)
 8     icon = icon.replace('\'', '').replace('|', '').replace('%', '')
 9     page_url = web_helper.get_form('page_url', '頁面URL', is_check_null=False)
10     interface_url = web_helper.get_form('interface_url', '介面url', is_check_null=False, is_check_special_char=False)
11     # 替換編碼
12     interface_url = interface_url.replace('@', '').replace('\'', '').replace('|', '').replace('%', '')
13     parent_id = convert_helper.to_int0(web_helper.get_form('parent_id', '父id', is_check_null=False))
14     sort = convert_helper.to_int0(web_helper.get_form('sort', '排序', is_check_null=False))
15     is_leaf = web_helper.get_form('is_leaf', '是否最終節點', is_check_null=False)
16     is_show = web_helper.get_form('is_show', '是否顯示', is_check_null=False)
17     is_enabled = web_helper.get_form('is_enabled', '是否啟用', is_check_null=False)
18 
19     _menu_info_logic = menu_info_logic.MenuInfoLogic()
20     # 計算深度級別,即當前菜單在哪一級
21     if parent_id == 0:
22         level = 0
23     else:
24         level = _menu_info_logic.get_value_for_cache(parent_id, 'level') + 1
25     # 如果沒有設置排序,則自動獲取當前級別最大的序號加1
26     if sort == 0:
27         sort = _menu_info_logic.get_max('parent_id', 'parent_id=' + str(parent_id)) + 1
28 
29     # 組合更新欄位
30     fields = {
31         'name': string(name),
32         'icon': string(icon),
33         'page_url': string(page_url),
34         'interface_url': string(interface_url),
35         'parent_id': parent_id,
36         'sort': sort,
37         'level': level,
38         'is_leaf': is_leaf,
39         'is_show': is_show,
40         'is_enabled': is_enabled,
41     }
42     # 新增記錄
43     result = _menu_info_logic.add_model(fields)
44     if result:
45         return web_helper.return_msg(0, '提交成功')
46     else:
47         return web_helper.return_msg(-1, "提交失敗")

  前端菜單新增頁面(menu_info_edit.html)大家下載源碼包查看

 

  新增菜單頁面樹列表我們使用的是zTree插件,它需要我們輸出指定的數據格式才能正常顯示,所以調用介面返回:id、parent_id、name、open這幾個欄位,在菜單項中,我們有是否最終節點的欄位,所以查詢條件中我們指定查詢出所有非最終節點的項就可以了

 1 @get('/api/system/menu_info/tree/')
 2 def callback():
 3     """
 4     獲取列表數據(樹列表)
 5     """
 6     _menu_info_logic = menu_info_logic.MenuInfoLogic()
 7     # 讀取記錄
 8     result = _menu_info_logic.get_list('id, parent_id, name, not is_leaf as open', 'is_leaf=false', orderby='sort asc')
 9     if result:
10         return web_helper.return_msg(0, "成功", {'tree_list': result.get('rows')})
11     else:
12         return web_helper.return_msg(-1, "查詢失敗")

  完成後直接填寫參數就可以提交新增菜單記錄了。

  

  對於編輯介面,它基本上和新增介面代碼相差不大,區別地方有下麵幾點:

  1.為了減少菜單層級變更所造成的錯誤,在編輯記錄介面我們需要屏蔽對父節點id的修改

  2.不需要再計算當前菜單所在層級的深度

  3.將新增方法add_model()更改為edit_model()方法

 1 @put('/api/system/menu_info/<id:int>/')
 2 def callback(id):
 3     """
 4     修改記錄
 5     """
 6     name = web_helper.get_form('name', '菜單名稱')
 7     icon = web_helper.get_form('icon', '菜單小圖標', True, 10, False, is_check_special_char=False)
 8     icon = icon.replace('\'', '').replace('|', '').replace('%', '')
 9     page_url = web_helper.get_form('page_url', '頁面URL', is_check_null=False)
10     interface_url = web_helper.get_form('interface_url', '介面url', is_check_null=False, is_check_special_char=False)
11     # 替換編碼
12     interface_url = interface_url.replace('\'', '').replace('|', '').replace('%', '')
13     parent_id = convert_helper.to_int0(web_helper.get_form('parent_id', '父id', is_check_null=False))
14     sort = convert_helper.to_int0(web_helper.get_form('sort', '排序', is_check_null=False))
15     is_leaf = web_helper.get_form('is_leaf', '是否最終節點', is_check_null=False)
16     is_show = web_helper.get_form('is_show', '是否顯示', is_check_null=False)
17     is_enabled = web_helper.get_form('is_enabled', '是否啟用', is_check_null=False)
18 
19     _menu_info_logic = menu_info_logic.MenuInfoLogic()
20     # 如果沒有設置排序,則自動獲取當前級別最大的序號加1
21     if sort == 0:
22         sort = _menu_info_logic.get_max('parent_id', 'parent_id=' + str(parent_id)) + 1
23 
24     # 組合更新欄位
25     fields = {
26         'name': string(name),
27         'icon': string(icon),
28         'page_url': string(page_url),
29         'interface_url': string(interface_url),
30         'sort': sort,
31         'is_leaf': is_leaf,
32         'is_show': is_show,
33         'is_enabled': is_enabled,
34     }
35     # 修改記錄
36     result = _menu_info_logic.edit_model(id, fields)
37     if result:
38         return web_helper.return_msg(0, '提交成功')
39     else:
40         return web_helper.return_msg(-1, "提交失敗")

  大家可以比較一下新增與編輯介面代碼,可以發現代碼幾乎都是一樣的。

  

 

  最後增加刪除介面

 1 @delete('/api/system/menu_info/<id:int>/')
 2 def callback(id):
 3     """
 4     刪除指定記錄
 5     """
 6     _menu_info_logic = menu_info_logic.MenuInfoLogic()
 7     # 判斷要刪除的節點是否有子節點,是的話不能刪除
 8     if _menu_info_logic.exists('parent_id=' + str(id)):
 9         return web_helper.return_msg(-1, "當前菜單存在子菜單,不能直接刪除")
10 
11     # 刪除記錄
12     result = _menu_info_logic.delete_model(id)
13     if result:
14         return web_helper.return_msg(0, '刪除成功')
15     else:
16         return web_helper.return_msg(-1, "刪除失敗")

  刪除介面跟前端產品分類刪除介面一樣,在刪除前需要判斷當前菜單是否已被引用(即當前菜單下是否存在子菜單)

 

  菜單管理項添加完成後,列表效果圖

 

  完成這些之後,我們還需要改造一下管理主界面左欄的菜單列表,改為從菜單管理數據表中讀取方式

  為了方便後續許可權的管理改造,我們在介面中組合菜單代碼來實現菜單的展示效果。

  首先我們通過查看左欄菜單列表的html代碼,提取出菜單html展示代碼

  然後在介面中,獲取設置為顯示並啟用狀態的菜單列表

  通過迴圈判斷,拼接一級菜單和二級菜單項的html輸出代碼

  最後將結果輸出到前端展示出來

 1 @get('/api/main/menu_info/')
 2 def callback():
 3     """
 4     主頁面獲取菜單列表數據
 5     """
 6     _menu_info_logic = menu_info_logic.MenuInfoLogic()
 7     # 讀取記錄
 8     result = _menu_info_logic.get_list('*', 'is_show and is_enabled', orderby='sort')
 9     if result:
10         # 定義最終輸出的html存儲變數
11         html = ''
12         for model in result.get('rows'):
13             # 提取出第一級菜單
14             if model.get('parent_id') == 0:
15                 # 添加一級菜單
16                 temp = """
17                 <dl id="menu-%(id)s">
18                     <dt><i class="Hui-iconfont">%(icon)s</i> %(name)s<i class="Hui-iconfont menu_dropdown-arrow">&#xe6d5;</i></dt>
19                     <dd>
20                         <ul>
21                 """ % {'id': model.get('id'), 'icon': model.get('icon'), 'name': model.get('name')}
22                 html = html + temp
23 
24                 # 從所有菜單記錄中提取當前一級菜單下的子菜單
25                 for sub_model in result.get('rows'):
26                     # 如果父id等於當前一級菜單id,則為當前菜單的子菜單
27                     if sub_model.get('parent_id') == model.get('id'):
28                         temp = """
29                         <li><a data-href="%(page_url)s" data-title="%(name)s" href="javascript:void(0)">%(name)s</a></li>
30                     """ % {'page_url': sub_model.get('page_url'), 'name': sub_model.get('name')}
31                         html = html + temp
32 
33                 # 閉合菜單html
34                 temp = """
35                         </ul>
36                     </dd>
37                 </dl>
38                     """
39                 html = html + temp
40 
41         return web_helper.return_msg(0, '成功', {'menu_html': html})
42     else:
43         return web_helper.return_msg(-1, "查詢失敗")

  執行後會輸出下麵結果:

{
    "data": {
        "menu_html": "\n                <dl id=\"menu-1\">\n                    <dt><i class=\"Hui-iconfont\">&#xe62e;</i> 系統管理<i class=\"Hui-iconfont menu_dropdown-arrow\">&#xe6d5;</i></dt>\n                    <dd>\n                        <ul>\n                \n                        <li><a data-href=\"menu_info.html\" data-title=\"菜單管理\" href=\"javascript:void(0)\">菜單管理</a></li>\n                    \n                        </ul>\n                    </dd>\n                </dl>\n                    "
    },
    "msg": "成功",
    "state": 0
}

  前端通過AJAX獲取菜單列表hmtl代碼,然後添加到後臺左欄菜單列表中就實現我們想要的效果了

<aside class="Hui-aside">
    <div class="menu_dropdown bk_2" id="menu">

    </div>
</aside>


<script type="text/javascript">
    $(function () {
        $.ajax({
            url: "/api/main/menu_info/?" + 100 * Math.random(),
            type: "GET",
            dataType:'json',
            success: function (data) {
                if (checkLogin(data, true))
                {
                    $("#menu").html(data.data.menu_html);
                    $.Huifold(".menu_dropdown dl dt",".menu_dropdown dl dd","fast",1,"click");
                }
            }
        });
    });
</script>

  頁面展示效果

  對於菜單管理的改造,完成上面這些項就算完厲了。對於菜單許可權的控制,後續完成整個改造後會專門講解。

 

  許可權系統中的部門管理(角色許可權組管理),它的基本功能和菜單功能相似,所以就不開新章節進行講解,大家可以根據數據結構嘗試編寫,也可以參考本節提供的源碼進行研究。

  PS:部門管理中,部門編碼生成是一個比較特殊的方法,需要多debug理解。

 

 

  本文對應的源碼下載 (內附本章源碼對應資料庫表單和記錄創建sql代碼,上傳的圖片如果顯示不了,可以nginx.conf配置的location項中添加upload,第一部分章節的nginx那裡忘記添加了)

 

版權聲明:本文原創發表於 博客園,作者為 AllEmpty 本文歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則視為侵權。

python開發QQ群:669058475    作者博客:http://www.cnblogs.com/EmptyFS/

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 註:大家如果沒有VB6.0的安裝文件,可自行百度一下下載,一般文件大小在200M左右的均為完整版的軟體,可以使用。 特別提示:安裝此軟體的時候最好退出360殺毒軟體(包括360安全衛士,電腦管家等,如果電腦上有這些軟體的話),因為現如今的360殺毒軟體直接會對VB6.0軟體誤報,這樣的話就可能會在安 ...
  • 題目:平安果 題目介紹:給出一個m*n的格子,每個格子里有一定數量的平安果,現在要求從左上角頂點(1,1)出發,每次走一格並拿走那一格的所有平安果,且只能向下或向右前進,最終到達右下角頂點(m,n),要求求出能拿走的平安果的最大數值。 輸入:第一行有兩個數值m,n,然後是m行n列數值。 輸出:一個數 ...
  • 最近在重構後端代碼,很多同學對Spring體系下的後端組件如Controller、Service、Repository、Component等認識不夠清晰,導致代碼里常常會出現Controller里直接使用RestTemplate、直接訪問資料庫的情況。下麵談談我對這些組件功能邊界的認識,一家之言,歡 ...
  • 剛開始學習SpringBoot,記錄一下舊項目整合到SpringBoot時遇到的問題(後續踩的坑也會持續加入) PS:通過查看他人博客自己東拼西湊出來的,不一定完全正確,請謹慎對待 1:打包為jar或war後發現jsp文件無法訪問或404等: 可能原因1:controller控制類不在啟動類所在的目 ...
  • 寫代碼: 1,明確需求。我要做什麼? 2,分析思路。我要怎麼做?1,2,3。 3,確定步驟。每一個思路部分用到哪些語句,方法,和對象。 4,代碼實現。用具體的java語言代碼把思路體現出來。 學習新技術的四點: 1,該技術是什麼? 2,該技術有什麼特點(使用註意): 3,該技術怎麼使用。demo 4 ...
  • 題目 約翰已經給他的農場安排了一條高速的網路線路,他想把這條線路共用給其他農場。為了用最小的消費,他想鋪設最短的光纖去連接所有的農場。 你將得到一份各農場之間連接費用的列表,你必須找出能連接所有農場並所用光纖最短的方案。每兩個農場間的距離不會超過100000。 輸入 第一行: 農場的個數,N(3<= ...
  • 問題背景: 我要在一個表單里同時一次性提交多名乘客的個人信息到SpringMVC,前端HTML和SpringMVC Controller里該如何處理? 第1種方法:表單提交,以欄位數組接收; 第2種方法:表單提交,以BeanListModel接收; 第3種方法:將Json對象序列化成Json字元串提 ...
  • 一、TCP: TCP是Transmission Control Protocol的簡稱,中文名傳輸控制協議。是一種面向連接的、可靠的、基於位元組流的傳輸層通信協議。TCP通信需要經過創建連接、數據傳輸、終止連接三個步驟。通信開始前,一定要先建立相關的鏈接,才能發送數據。完成數據交換後,雙方必須斷開鏈接 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...