python: DDD+MVC
项目结构:
# encoding: utf-8 # 版权所有 2025 涂聚文有限公司 # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # os : windows 10 # database : mysql 9.0 sql server 2019, poostgreSQL 17.0 Oracle 21c # Datetime : 2025/2/14 22:28 # User : geovindu # Product : PyCharm # Project : pydddmvcdemo # File : school.py # explain : 学习 class SchoolInfo(object): """ 领域层(Domain) 学校表 """ def __init__(self): """ 構造 """ self._SchoolId = None """ ID,主键 """ self._SchoolName = None """ 校名 """ self._SchoolTelNo = None """ 学校电话 """ @property def SchoolId(self): """ ID,主键 """ return self._SchoolId @SchoolId.setter def SchoolId(self, schoolId): """ ID,主键 :param SchoolId: :return: """ self._SchoolId = schoolId @property def SchoolName(self): """ 校名 """ return self._SchoolName @SchoolName.setter def SchoolName(self, schoolName): """ 校名 :param SchoolName: :return: """ self._SchoolName = schoolName @property def SchoolTelNo(self): """ 学校电话 """ return self._SchoolTelNo @SchoolTelNo.setter def SchoolTelNo(self, schoolTelNo): """ 学校电话 :param SchoolTelNo: :return: """ self._SchoolTelNo = schoolTelNo
# encoding: utf-8 # 版权所有 2025 涂聚文有限公司 # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # os : windows 10 # database : mysql 9.0 sql server 2019, poostgreSQL 17.0 Oracle 21c # Datetime : 2025/2/14 22:30 # User : geovindu # Product : PyCharm # Project : pydddmvcdemo # File : school.py # explain : 学习 import sqlite3 from Domain.school import SchoolInfo #from __future__ import annotations from abc import ABC, abstractmethod from Factory.AbstractFactory import AbstractFactory class SchoolRepository(object): """ 基础设施层(Infrastructure) """ dal = AbstractFactory.createSchool def __init__(self): self.__name = "SchoolBll" self.createtable() # 如果不存在,初始化表 def __del__(self): """ :return: """ print(f"{self.__name} ERASE MEMORY") def Close(cls): """ 关闭 :return: """ cls.dal().Close() def createtable(self): """ 建表 """ self.dal().createtable() def selectData(self) -> list: """ :return: """ data = self.dal().selectSql() return data def select(self) -> list[SchoolInfo]: """ :return: """ schools = [] data = self.dal().selectSql() if len(data) > 0: for SchoolId, SchoolName, SchoolTelNo in data[0]: info = SchoolInfo() info.SchoolId = SchoolId info.SchoolName = SchoolName info.SchoolTelNo = SchoolTelNo schools.append(info) return schools def selectSql(cls) -> list[SchoolInfo]: """ 元组数据 :return: list 列表 """ schools = [] data = cls.dal().selectSql() if len(data) > 0: for SchoolId, SchoolName, SchoolTelNo in data[0]: info = SchoolInfo() info.SchoolId = SchoolId info.SchoolName = SchoolName info.SchoolTelNo = SchoolTelNo schools.append(info) return schools def selectSqlCount(cls) -> int: """ 查询数据 总数 :return: """ # print(cls.dal().selectSqlCount()[0][0]) total = cls.dal().selectSqlCount()[0][0] return total def Count(self) -> int: """ 查询数据 总数 :return: """ total = self.dal().selectSqlCount()[0][0] return total def getcount(cls, search_query=""): """ 计算 :param search_query: :return: """ return cls.dal().getcount(search_query) def getschools(cls, page, limit, search_query=""): """ 查询 分页 :param page: :param limit: :param search_query: :return: """ data = cls.dal().getschools(page, limit, search_query) print("data:", data) return data def selectSqlOrder(cls, order: str) -> list[SchoolInfo]: """ 元组数据 :param order: SchoolName desc/asc :return: """ schools = [] data = cls.dal().selectSqlOrder(order) if len(data) > 0: for SchoolId, SchoolName, SchoolTelNo in data[0]: info = SchoolInfo() info.SchoolId = SchoolId info.SchoolName = SchoolName info.SchoolTelNo = SchoolTelNo schools.append(info) return schools def selectSort(cls, field: str, isOrder: bool) -> list[SchoolInfo]: """ :param field SchoolId :param order: desc/asc :return: """ schools = [] data = cls.dal().selectSort(field, isOrder) if len(data) > 0: for SchoolId, SchoolName, SchoolTelNo in data[0]: info = SchoolInfo() info.SchoolId = SchoolId info.SchoolName = SchoolName info.SchoolTelNo = SchoolTelNo schools.append(info) return schools def selectIdSql(cls, SchoolId: str) -> list[SchoolInfo]: """ :param SchoolId:ID :return: """ schools = [] data = cls.dal().selectIdSql(SchoolId) # print(data) if len(data) > 0: for SchoolId, SchoolName, SchoolTelNo in data[0]: info = SchoolInfo() info.SchoolId = SchoolId info.SchoolName = SchoolName info.SchoolTelNo = SchoolTelNo schools.append(info) return schools def addSql(cls, info: SchoolInfo) -> int: """ :param info:实体类 :return: """ return cls.dal().addSql(info) def add(self, info: SchoolInfo) -> int: """ :param info:实体类 :return: """ return self.dal().addSql(info) def editSql(cls, info: SchoolInfo) -> int: """ :param info:实体类 :return: """ # print(info) return cls.dal().editSql(info) def edit(self, info: SchoolInfo) -> int: """ :param info:实体类 :return: """ # print(info) return self.dal().editSql(info) def delSql(cls, SchoolId: str) -> int: """ :param SchoolId: :return: """ return cls.dal().delSql(SchoolId) def delinfo(self, SchoolId: str) -> int: """ :param SchoolId: :return: """ return self.dal().delSql(SchoolId)
# encoding: utf-8 # 版权所有 2025 涂聚文有限公司 # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # os : windows 10 # database : mysql 9.0 sql server 2019, poostgreSQL 17.0 Oracle 21c # Datetime : 2025/2/14 22:41 # User : geovindu # Product : PyCharm # Project : pydddmvcdemo # File : SchoolService.py # explain : 学习 from Domain.school import SchoolInfo from Infrastructure.school import SchoolRepository class SchoolService(object): """ 应用层(Application) """ def __init__(self, repository:SchoolRepository): """ :param repository: """ self.repository = repository def addschool(self,info: SchoolInfo): """ 添加学校 :param info: :return: """ self.repository.addSql(info) def deleteschool(self, school_id): """ 删除学校 :param school_id: :return: """ self.repository.delSql(school_id) def updateschool(self, info: SchoolInfo): """ 更新学校 :param info: :return: """ self.repository.editSql(info) def getschool(self, school_id)-> list[SchoolInfo]: """ 查询单个学校 :param school_id: :return: """ return self.repository.selectIdSql(school_id) def getallschools(self)->[SchoolInfo]: """ 查询所有学校 :return: """ return self.repository.selectSql() def get_all_schools(self, limit, offset, search_query="") -> list[SchoolInfo]: """ 分页查询所有学校 :param limit: :param offset: :param search_query: :return: """ return self.repository.getschools(limit, offset,search_query) def get_total_schools(self, search_query=""): """ 取学校总数 :param search_query: :return: """ return self.repository.getcount(search_query)
# encoding: utf-8 # 版权所有 2025 涂聚文有限公司 # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # os : windows 10 # database : mysql 9.0 sql server 2019, poostgreSQL 17.0 Oracle 21c # Datetime : 2025/2/14 22:50 # User : geovindu # Product : PyCharm # Project : pydddmvcdemo # File : SchoolView.py # explain : 学习 import tkinter as tk from tkinter import ttk, messagebox from Presentation.View.SchoolDialog import SchoolDialog from Presentation.Controller import SchoolController from Domain.school import SchoolInfo class SchoolView(tk.Frame): """ 视图层(View) """ def __init__(self, root, controller: SchoolController): self.controller = controller self.root = root self.root.title("学校管理系统") # 分页大小 self.page_size = 10 # 每页显示 10 条数据 self.current_page = 0 # 当前页码(从 0 开始) self.search_query = "" # 搜索查询参数 self.limit = 10 # 搜索框和搜索按钮 self.search_entry = tk.Entry(root, width=20) self.search_entry.grid(row=0, column=0, padx=5, pady=5) self.search_button = tk.Button(root, text="搜索", command=self.search_schools) self.search_button.grid(row=0, column=1, padx=5, pady=5) # 学校列表 self.tree = ttk.Treeview(root, columns=("ID", "名称", "电话"), show="headings") self.tree.heading("ID", text="学校 ID") self.tree.heading("名称", text="学校名称") self.tree.heading("电话", text="学校电话") self.tree.grid(row=1, column=0, columnspan=4, padx=5, pady=5) # 绑定双击事件 self.tree.bind("<Double-1>", self.on_tree_double_click) # 分页控件 self.prev_button = tk.Button(root, text="上一页", command=self.prev_page) self.prev_button.grid(row=2, column=0, padx=5, pady=5) self.page_label = tk.Label(root, text="第 1 页") self.page_label.grid(row=2, column=1, padx=5, pady=5) self.pagetotal_label = tk.Label(root, text="/共 1 页") self.pagetotal_label.grid(row=2, column=2, padx=15, pady=15) self.next_button = tk.Button(root, text="下一页", command=self.next_page) self.next_button.grid(row=2, column=3, padx=5, pady=5) # 添加学校按钮 self.add_button = tk.Button(root, text="添加学校", command=self.open_add_dialog) self.add_button.grid(row=3, column=0, padx=5, pady=5) # 更新学校按钮 self.update_button = tk.Button(root, text="更新学校", command=self.open_update_dialog) self.update_button.grid(row=3, column=1, padx=5, pady=5) # 删除学校按钮 self.delete_button = tk.Button(root, text="删除学校", command=self.delete_school) self.delete_button.grid(row=3, column=2, padx=5, pady=5) # 初始化学校列表 self.update_school_list() def search_schools(self): """搜索学校""" self.search_query = self.search_entry.get() self.current_page = 0 # 搜索时回到第一页 self.update_school_list() def on_tree_double_click(self, event): """ 处理 Treeview 双击事件 :param event: :return: """ selected_item = self.tree.selection() school=SchoolInfo() if selected_item: val=self.tree.item(selected_item)['values'] print("val:",val) school_id = self.tree.item(selected_item)['values'][0] school.SchoolId =val[0] school.SchoolName=val[1] school.SchoolTelNo=val[2] dialog = SchoolDialog(self.root, "更新学校","Edit", self.controller, school) if dialog.result: school = SchoolInfo() school.SchoolId = dialog.result[0] school.SchoolName = dialog.result[1] school.SchoolTelNo = dialog.result[2] self.controller.update_school(school) self.update_school_list() def open_add_dialog(self): """ 打开添加学校窗口 """ dialog = SchoolDialog(self.root, "添加学校","Add", self.controller) if dialog.result: print(dialog.result) school=SchoolInfo() school.SchoolId=dialog.result[0] school.SchoolName=dialog.result[1] school.SchoolTelNo=dialog.result[2] self.controller.add_school(school) self.update_school_list() def open_update_dialog(self): """ 打开更新学校窗口 """ selected_item = self.tree.selection() if selected_item: school_id = self.tree.item(selected_item, "values")[0] print("school_id",school_id) school = self.controller.get_school(school_id)[0] dialog = SchoolDialog(self.root, "更新学校", "Edit",self.controller, school) print("dialog",dialog.result[1]) if dialog.result: school = SchoolInfo() school.SchoolId = dialog.result[0] school.SchoolName = dialog.result[1] school.SchoolTelNo = dialog.result[2] print("update",school.SchoolName) self.controller.update_school(school) self.update_school_list() else: messagebox.showwarning("警告", "请选择一个学校!") def delete_school(self): """ 删除学校 """ selected_item = self.tree.selection() if selected_item: school_id = self.tree.item(selected_item, "values")[0] self.controller.delete_school(school_id) self.update_school_list() else: messagebox.showwarning("警告", "请选择一个学校!") def update_school_list(self): """ 更新学校列表 """ self.tree.delete(*self.tree.get_children()) # 清空列表 # 计算分页参数 total_schools = self.controller.get_total_schools(self.search_query)[0][0] offset=self.current_page+1 schools = self.controller.get_all_schools(offset, self.limit, self.search_query) # 将数据插入 Treeview for school in schools: self.tree.insert("", "end", values=(school)) # 更新分页标签 self.update_page_label() self.update_page_total() def prev_page(self): """ 上一页 """ if self.current_page >0: self.current_page -= 1 self.update_school_list() def next_page(self): """ 下一页 """ total_schools = self.controller.get_total_schools(self.search_query)[0][0] total_pages = (total_schools + self.page_size - 1) // self.page_size if self.current_page < total_pages - 1: self.current_page += 1 self.update_school_list() def update_page_label(self): """ 更新页码标签 """ total_schools =self.controller.get_total_schools(self.search_query)[0][0] total_pages = (total_schools + self.limit - 1) // self.limit current_page = self.current_page + 1 # 从 1 开始显示 self.page_label.config(text=f"第 {current_page} 页 / 共{total_pages}页") def update_page_total(self): """ 更新总页数标签 """ total_schools = self.controller.get_total_schools(self.search_query)[0][0] total_pages = (total_schools + self.limit - 1) // self.limit #print(total_pages) self.pagetotal_label.config(text=f" 共 {total_schools} /条")
# encoding: utf-8 # 版权所有 2025 涂聚文有限公司 # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # os : windows 10 # database : mysql 9.0 sql server 2019, poostgreSQL 17.0 Oracle 21c # Datetime : 2025/2/14 23:51 # User : geovindu # Product : PyCharm # Project : pydddmvcdemo # File : SchoolDialog.py # explain : 学习 import tkinter as tk from tkinter import messagebox from Presentation.Controller import SchoolController from Domain.school import SchoolInfo class SchoolDialog: """ 要区别,添加,修改的操作 """ def __init__(self, parent, title,action, controller:SchoolController, school=None): """ :param parent: :param title: :param action: :param controller: :param school: """ self.controller = controller self.school = school self.result = None self.action= action self.dialog = tk.Toplevel(parent) self.dialog.title(title) # 学校 ID 输入框 self.school_id_label = tk.Label(self.dialog, text="学校 ID") self.school_id_label.grid(row=0, column=0, padx=5, pady=5) self.school_id_entry = tk.Entry(self.dialog, width=20) self.school_id_entry.grid(row=0, column=1, padx=5, pady=5) # 学校名称输入框 self.school_name_label = tk.Label(self.dialog, text="学校名称") self.school_name_label.grid(row=1, column=0, padx=5, pady=5) self.school_name_entry = tk.Entry(self.dialog, width=20) self.school_name_entry.grid(row=1, column=1, padx=5, pady=5) # 学校电话输入框 self.school_tel_no_label = tk.Label(self.dialog, text="学校电话") self.school_tel_no_label.grid(row=2, column=0, padx=5, pady=5) self.school_tel_no_entry = tk.Entry(self.dialog, width=20) self.school_tel_no_entry.grid(row=2, column=1, padx=5, pady=5) # 确定按钮 self.ok_button = tk.Button(self.dialog, text="确定", command=self.on_ok) self.ok_button.grid(row=3, column=0, padx=5, pady=5) # 取消按钮 self.cancel_button = tk.Button(self.dialog, text="取消", command=self.dialog.destroy) self.cancel_button.grid(row=3, column=1, padx=5, pady=5) print(self.school) if self.action == "Edit": # 如果是更新操作,填充现有数据 if self.school: self.school_id_entry.insert(0, self.school.SchoolId) self.school_name_entry.insert(0, self.school.SchoolName) self.school_tel_no_entry.insert(0, self.school.SchoolTelNo) self.school_id_entry.config(state="disabled") # 禁止修改 ID # 等待窗口关闭 self.dialog.wait_window() def on_ok(self): """ 确定按钮点击事件 """ school_id = self.school_id_entry.get() name = self.school_name_entry.get() tel_no = self.school_tel_no_entry.get() if school_id and name and tel_no: print("name",name) self.result = (school_id, name, tel_no) ''' 也可以修改 if self.action=="Edit": school = SchoolInfo() school.SchoolId = self.result[0] school.SchoolName = self.result[1] school.SchoolTelNo = self.result[2] print("update", school.SchoolName) self.controller.update_school(school) ''' self.dialog.destroy() else: messagebox.showwarning("警告", "所有字段不能为空!")
# encoding: utf-8 # 版权所有 2025 涂聚文有限公司 # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # os : windows 10 # database : mysql 9.0 sql server 2019, poostgreSQL 17.0 Oracle 21c # Datetime : 2025/2/14 22:48 # User : geovindu # Product : PyCharm # Project : pydddmvcdemo # File : SchoolController.py # explain : 学习 from Application.SchoolService import SchoolService from Domain.school import SchoolInfo class SchoolController(object): """ 控制器层(Controller) """ def __init__(self, service:SchoolService): """ :param service: """ self.service = service def add_school(self, info:SchoolInfo): """ :param info: :return: """ self.service.addschool(info) def delete_school(self, school_id): """ :param school_id: :return: """ self.service.deleteschool(school_id) def update_school(self, info:SchoolInfo): """ :param info: :return: """ self.service.updateschool(info) def get_school(self, school_id)-> list[SchoolInfo]: """ :param school_id: :return: """ return self.service.getschool(school_id) def get_all_schools(self, limit, offset=0, search_query=""): """ :param limit: :param offset: :param search_query: :return: """ return self.service.get_all_schools(limit, offset,search_query) def get_total_schools(self, search_query=""): """ :param search_query: :return: """ return self.service.get_total_schools(search_query)
主程序:
# encoding: utf-8 # 版权所有 2025 涂聚文有限公司 # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # os : windows 10 # database : mysql 9.0 sql server 2019, poostgreSQL 17.0 Oracle 21c # Datetime : 2025/2/14 22:28 # User : geovindu # Product : PyCharm # Project : pydddmvcdemo # File : main.py # explain : 学习 import tkinter as tk from Infrastructure.school import SchoolRepository from Application.SchoolService import SchoolService from Presentation.Controller.SchoolController import SchoolController from Presentation.View.SchoolView import SchoolView if __name__ == '__main__': # 创建根窗口 root = tk.Tk() # 初始化 DDD 分层组件 repository = SchoolRepository() service = SchoolService(repository) controller = SchoolController(service) # 初始化视图 view = SchoolView(root, controller) root.iconbitmap('favicon.ico') # 启动主循环 root.mainloop() print('PyCharm,geovindu')
输出:
哲学管理(学)人生, 文学艺术生活, 自动(计算机学)物理(学)工作, 生物(学)化学逆境, 历史(学)测绘(学)时间, 经济(学)数学金钱(理财), 心理(学)医学情绪, 诗词美容情感, 美学建筑(学)家园, 解构建构(分析)整合学习, 智商情商(IQ、EQ)运筹(学)生存.---Geovin Du(涂聚文)