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')

  

输出:

 

posted @ 2025-02-15 04:05  ®Geovin Du Dream Park™  阅读(16)  评论(0)    收藏  举报