Python操作MySQL实战

文章导读

        本文用于巩固Pymysql操作MySQL与MySQL操作的知识点,实现一个简易的音乐播放器,拟实现的功能包括:用户登录,窗口显示,加载本地音乐,加入和删除播放列表,播放音乐。

点击此处获取参考源码icon-default.png?t=N7T8https://pan.baidu.com/s/1HNLc7tCVBjoBMpnezzm7_g?pwd=vqr4

1、创建数据库和表

概述:本章的操作均在navicat的查询中实现。

1.1、创建数据库

实操:通过navicat创建一个名为db_music的数据库,用于存储本实战中所有的表。

CREATE DATABASE db_music DEFAULT CHARACTER SET="utf8";

运行结果如下:

1.2、创建用户表

实操前准备:通过navicat切换到我们创建的数据库db_music,这里直接关闭之前打开的查询,然后按如下图所示的步骤操作。

实操:在db_music数据库下创建一个名为user_info的用户表,包含的字段如下:id,用户名(uname),密码(password),并将id设置为主键。

CREATE TABLE user_info(
id int PRIMARY KEY,
uname VARCHAR(20),
password VARCHAR(30)
)

运行后的结果为(也可以刷新数据库,查看db_music数据库下的表):

1.3、创建音乐列表

实操:在db_music数据库下创建一个用于保存本地音乐的表,取名为music_info,包含以下字段:id,歌曲名(name),歌手(singer)和存放路径(path),并将id设置为主键自增长。

CREATE TABLE music_info(
id int PRIMARY KEY auto_increment,
name varchar(30),
singer varchar(20),
path varchar(80)
);

运行结果如下:

1.4、创建播放列表

实操:在db_music数据库下创建一个用于播放本地音乐的表,取名为play_info,包含以下字段:歌单唯一标识(id),用于关联用户唯一标识id,通过该字段知道这是谁的播放列表(u_id),用于关联本地音乐的唯一标识id,通过该字段知道播放哪首音乐(m_id),并将id设置为主键自增长,正确的设置u_id和m_id的外键。

CREATE TABLE play_info(
id int PRIMARY KEY auto_increment,
u_id int,
m_id int,
FOREIGN KEY(u_id) REFERENCES user_info(id),
FOREIGN KEY(m_id) REFERENCES music_info(id)
);

运行结果如下:

此时,数据库db_music下就创建了三张表:

2、实现用户登录

2.1、插入数据

概述:为了能实现用户登录,首先得为user_info表中插入用户数据用于验证后续程序的可行性。

INSERT INTO user_info VALUES(1,"muxikeqi","123321");

运行后的user_info表数据如下:

2.2、引入链接数据库的工具类

概述:新建一个名为tools.py的文件,然后将学习Python操作MySQL时写的工具类拷贝过来并加以修改(这里主要是修改链接的数据库),用于简化后续对数据库操作。

import pymysql

class DBUtil:
    """
    工具类用于简化链接和关闭数据库的操作以及对数据的操作
    """

    # 单独保存链接的参数,可以将其保存到特定文件中,直接调用文件获取也可
    config = {
        'host': "localhost",
        'user': "root",
        'passwd': "root",
        'db': "db_music",
        'charset': "utf8",
        'port': 3306
    }

    def __init__(self) -> None:
        """
        构造函数用于获取链接和游标
        """
        # **指字典对象
        self.con = pymysql.connect(**DBUtil.config)
        self.cursor = self.con.cursor()

    def close(self) -> None:
        """
        该函数用于关闭链接和游标(关闭前需要判断是否存在)
        """
        # 存在游标就关闭
        if self.cursor:
            self.cursor.close()
        # 存在链接就关闭
        if self.con:
            self.con.close()

    def dml(self, sql, args):
        """
        本函数用于封装Mysql的DML语句,用于实现数据的增删改
        """
        # 进行DML语句操作时一定要注意报错导致无法正常关闭链接
        try:
            # 执行sql中的DML语句
            self.cursor.execute(sql, args)
            # DML操作一定要通过链接对象提交事务
            self.con.commit()
        except Exception as e:
            print("存在错误,错误信息如下:", e)
            # 回滚前先判断链接还是否存在
            if self.con:
                # 回滚到原状态
                self.con.rollback()
        # 使用try...except...finally...最重要的作用就是保证链接正常关闭
        finally:
            print("即将关闭链接")
            self.close()

    def query_one(self, sql, args):
        """
        本函数用于查询单条数据
        """
        try:
            self.cursor.execute(sql, args)
            re = self.cursor.fetchone()
            return re
        except Exception as e:
            print("存在错误,错误信息如下:", e)
        finally:
            print("即将关闭链接")
            self.close()

    def query_many(self, sql):
        """
        本函数用于查询所有数据
        """
        try:
            self.cursor.execute(sql)
            # 获取结果并返回数据
            return self.cursor.fetchall()

        except Exception as e:
            print("存在错误,错误信息如下:", e)

        finally:
            print("即将关闭链接")
            self.close()


if __name__ == "__main__":
    # 获取链接对象
    db = DBUtil()
    # 准备sql语句及其对应的参数
    sql = "select * from user_info where uname=%s and password=%s;"
    args =["muxikeqi","123321"]
    # 运行sql语句并关闭链接
    re = db.query_one(sql,args)
    print(re)
    pass

2.3、实现用户登录

概述:创建一个名为service.py的文件(与前面引入的tools.py文件放在同一目录),该文件用于写后端逻辑类代码,首先在service.py文件中写一个名为login的函数用于连接数据库并判断用户是否能登录成功。

from tools import DBUtil

class Music:
    def login(self, uname: str, password: str) -> bool:
        """
        :param uname:用户名
        :param password:密码
        :return: 登录成功返回True,登录失败返回False
        """
        # 准备要执行的sql语句
        sql = "select * from user_info where uname=%s and password=%s"
        # 准备sql语句需要的参数
        args = (uname, password)
        # 创建工具对象(实际时获取数据库的链接对象和游标对象)
        db = DBUtil()
        # 利用游标对象调用对应的单条查询方法
        re = db.query_one(sql, args)
        # 由于query_one函数运行成功后是有返回值的,可以通过返回值判断是否查询成功,进而判断是否有该用户
        if re:
            print("登录成功")
            return True
        else:
            print("登录失败")
            return False

# 测试代码
if __name__ == "__main__":
    # 创建Music类的实例对象
    service = Music()
    # 利用实例对象调用实例方法
    re = service.login("muxikeqi", "123321")
    print(re)

运行结果如下:

3、实现窗口(了解)

3.1、实现显示窗口

概述:窗口的实现将采用Tkinter实现,通过菜鸟教程可以查看其用法。

实操:创建一个名为ui.py的文件放在前面创建的.py文件的同级目录,该文件主要写前端页面的代码,文件中用一个名为Ui的类承载显示窗口的内容,为了让程序进入Ui类就能显示窗口所以推荐将显示窗口的内容直接放进构造函数中。

import tkinter
class Ui:
    def __init__(self):
        # 主窗口
        top = tkinter.Tk()
    
        # 创建按钮对象,第一个参数是父容器,text表示显示的内容
        b1 = tkinter.Button(top, text="播放")
        b2 = tkinter.Button(top, text="导入音乐")
        b3 = tkinter.Button(top, text="删除音乐")
        # 设置按钮显示位置(row表示放在哪一行,column表示放在哪一列,pad表示距离边框的内边距,单位为像素)
        b1.grid(row=1,column=1,padx=10,pady=10)
        b2.grid(row=1,column=2,padx=10,pady=10)
        b3.grid(row=1,column=3,padx=10,pady=10)
    
        # 创建播放列表
        lisbox = tkinter.Listbox(top)
        # 设置播放列表位置,columnspan表示垮了多少列
        lisbox.grid(row=2,column=0,columnspan=4,padx=10,pady=10)
    
        # 进入消息循环
        top.mainloop()

if __name__=="__main__":
    ui = Ui()

运行结果如下:

3.2、实现登陆后显示窗口

概述:前面已经实现了用户登录和窗口的显示,如果要实现登陆后显示窗口只需在ui.py文件中做出修改即可。

import tkinter
from service import Music

class Ui:
    def __init__(self):
        # 主窗口
        top = tkinter.Tk()

        # 创建按钮对象,第一个参数是父容器,text表示显示的内容
        b1 = tkinter.Button(top, text="播放")
        b2 = tkinter.Button(top, text="导入音乐")
        b3 = tkinter.Button(top, text="删除音乐")
        # 设置按钮显示位置(row表示放在哪一行,column表示放在哪一列,pad表示距离边框的内边距,单位为像素)
        b1.grid(row=1,column=1,padx=10,pady=10)
        b2.grid(row=1,column=2,padx=10,pady=10)
        b3.grid(row=1,column=3,padx=10,pady=10)

        # 创建播放列表
        lisbox = tkinter.Listbox(top)
        # 设置播放列表位置,columnspan表示垮了多少列
        lisbox.grid(row=2,column=0,columnspan=4,padx=10,pady=10)

        # 进入消息循环
        top.mainloop()

if __name__=="__main__":
    # 获取用户名和密码
    uname = input("请输入用户名:")
    password = input("请输入密码:")
    # 创建Music类的实例对象
    ser = Music()
    # 利用实例对象调用实例方法(由于会返回布尔值,所以直接进行判断)
    if ser.login(uname,password):
        ui = Ui()
    else:
        print("用户名或密码错误!")

运行结果如下:

弹出的窗口如下:

4、实现播放音乐

概述:播放音乐将使用pygame模块实现。

实操前准备1:进入终端通过如下命令下载pygame模块。

pip install pygame

运行结果如下:

实操前准备2:去任意音乐网站下载任意首歌曲放在music项目目录中的任意文件夹中(这里我放在了名为music的文件夹中)

实操:利用pygame模块实现任意一首音乐的播放。

import pygame
import time
# 初始化加载音乐的混合器
pygame.mixer.init()
# 加载音乐(路径可以是相对路径也可以是绝对路径)
pygame.mixer.music.load(f".\music\c.flac")
# 播放音乐
pygame.mixer.music.play()
# 程序进入等待(不要立即关闭程序),单位为秒
time. Sleep(20)

20秒后程序运行结果如下:

5、为UI界面设置导入音乐的事件

概述:首先需要为导入音乐的按钮添加一个点击事件,点击事件用于打开文件夹让用户选择音乐文件。(只需要对ui.py文件做修改即可)

import tkinter
from service import Music
import tkinter.filedialog

class Ui:
    def __init__(self):
        # 主窗口
        top = tkinter.Tk()

        # 创建按钮对象,第一个参数是父容器,text表示显示的内容
        b1 = tkinter.Button(top, text="播放")
        b2 = tkinter.Button(top, text="导入音乐")
        b3 = tkinter.Button(top, text="删除音乐")
        # 设置按钮显示位置(row表示放在哪一行,column表示放在哪一列,pad表示距离边框的内边距,单位为像素)
        b1.grid(row=1,column=1,padx=10,pady=10)
        b2.grid(row=1,column=2,padx=10,pady=10)
        b3.grid(row=1,column=3,padx=10,pady=10)

        # 为导入音乐的按钮添加点击事件,bind方法的第一个参数是事件名称(写法固定,不能修改),第二个参数是点击事件(点击按钮后触发的函数)
        b2.bind("<Button-1>",self.importMusic)

        # 创建播放列表
        lisbox = tkinter.Listbox(top)
        # 设置播放列表位置,columnspan表示垮了多少列
        lisbox.grid(row=2,column=0,columnspan=4,padx=10,pady=10)

        # 进入消息循环
        top.mainloop()

    # 导入音乐的点击事件
    def importMusic(self,event):
        # 弹出选择框(返回的结果是元组)(一定要通过filetypes限制文件类型,否则什么文件都能加入进来)
        filenames = tkinter.filedialog.askopenfilenames(filetypes=[("mp3",".mp3"),("flac",".flac")])
       
if __name__=="__main__":
    # 获取用户名和密码
    uname = input("请输入用户名:")
    password = input("请输入密码:")
    # 创建Music类的实例对象
    ser = Music()
    # 利用实例对象调用实例方法(由于会返回布尔值,所以直接进行判断)
    if ser.login(uname,password):
        ui = Ui()
    else:
        print("用户名或密码错误!")

运行结果如下:
 

点击导入音乐按钮后的效果如下:

6、为后台添加导入音乐的逻辑

概述:本章节将实现前端选择音乐,后端将音乐名和音乐存放在本地的路径导入到db_music数据库下的music_info表的对应字段中。

首先,在service.py文件中的Music类中添加一个名为add_music的实例方法,用于将前端的数据添加到db_music数据库下music_info表中:

    def add_music(self,files:tuple[str]) -> None:
        """
        该函数用于将前台返回的文件路径存储到数据库中
        :param file:音乐文件的路径,默认是多个,元素类型为字符串
        :return: None
        """
        # 编写sql语句
        sql = "insert into music_info(name,path) values(%s,%s)"
        # 遍历数据
        for f in files:
            print(f)
            # 根据路径获取歌曲名
            name = f[f.rfind("/")+1:f.rfind(".")]
            print(name)
            # 创建数据库链接对象
            db = DBUtil()
            # 准备参数
            args=(name,f)
            # 执行插入语句
            db.dml(sql,args)

接下来修改ui.py文件的内容,用于将tkinter.filedialog.askopenfilenames返回的歌曲路径(返回类型是元组,返回的是歌曲在本地的绝对路径)传入前面写的add_music函数中进行处理,而add_music又属于Music类,所以要先创建一个实例对象,再通过实例对象调用add_music方法:

    def importMusic(self,event):
        # 弹出选择框(返回的结果是元组)(一定要通过filetypes限制文件类型,否则什么文件都能加入进来)
        filenames = tkinter.filedialog.askopenfilenames(filetypes=[("mp3",".mp3"),("flac",".flac"),("mgg",".mgg")])
        # 创建服务对象
        ser = Music()
        # 调用增加音乐的功能(将前端的数据发送给后端处理)
        ser.add_music(filenames)

运行后的结果如下:

加入歌曲后db_music数据库下music_info表的数据如下:

完整ui.py文件如下:

import tkinter
from service import Music
import tkinter.filedialog

class Ui:
    def __init__(self):
        # 主窗口
        top = tkinter.Tk()

        # 创建按钮对象,第一个参数是父容器,text表示显示的内容
        b1 = tkinter.Button(top, text="播放")
        b2 = tkinter.Button(top, text="导入音乐")
        b3 = tkinter.Button(top, text="删除音乐")
        # 设置按钮显示位置(row表示放在哪一行,column表示放在哪一列,pad表示距离边框的内边距,单位为像素)
        b1.grid(row=1,column=1,padx=10,pady=10)
        b2.grid(row=1,column=2,padx=10,pady=10)
        b3.grid(row=1,column=3,padx=10,pady=10)

        # 为导入音乐的按钮添加点击事件,bind方法的第一个参数是事件名称,第二个参数是点击事件(点击按钮后触发的函数)
        b2.bind("<Button-1>",self.importMusic)

        # 创建播放列表
        lisbox = tkinter.Listbox(top)
        # 设置播放列表位置,columnspan表示垮了多少列
        lisbox.grid(row=2,column=0,columnspan=4,padx=10,pady=10)

        # 进入消息循环
        top.mainloop()

    # 导入音乐的点击事件
    def importMusic(self,event):
        # 弹出选择框(返回的结果是元组)(一定要通过filetypes限制文件类型,否则什么文件都能加入进来)
        filenames = tkinter.filedialog.askopenfilenames(filetypes=[("mp3",".mp3"),("flac",".flac"),("mgg",".mgg")])
        # 创建服务对象
        ser = Music()
        # 调用增加音乐的功能(将前端的数据发送给后端处理)
        ser.add_music(filenames)

if __name__=="__main__":
    # 获取用户名和密码
    uname = input("请输入用户名:")
    password = input("请输入密码:")
    # 创建Music类的实例对象
    ser = Music()
    # 利用实例对象调用实例方法(由于会返回布尔值,所以直接进行判断)
    if ser.login(uname,password):
        Ui()
    else:
        print("用户名或密码错误!")

完整service.py文件如下:

from tools import DBUtil

class Music:
    def login(self, uname: str, password: str) -> bool:
        """
        :param uname:用户名
        :param password:密码
        :return: 登录成功返回True,登录失败返回False
        """
        # 准备要执行的sql语句
        sql = "select * from user_info where uname=%s and password=%s"
        # 准备sql语句需要的参数
        args = (uname, password)
        # 创建工具对象(实际时获取数据库的链接对象和游标对象)
        db = DBUtil()
        # 利用游标对象调用对应的单条查询方法
        re = db.query_one(sql, args)
        # 由于query_one函数运行成功后是有返回值的,可以通过返回值判断是否查询成功,进而判断是否有该用户
        if re:
            print("登录成功")
            return True
        else:
            print("登录失败")
            return False

    def add_music(self,files:tuple[str]) -> None:
        """
        该函数用于将前台返回的文件路径存储到数据库中
        :param file:音乐文件的路径,默认是多个,元素类型为字符串
        :return: None
        """
        # 编写sql语句
        sql = "insert into music_info(name,path) values(%s,%s)"
        # 遍历数据
        for f in files:
            print(f)
            # 根据路径获取歌曲名
            name = f[f.rfind("/")+1:f.rfind(".")]
            print(name)
            # 创建数据库链接对象
            db = DBUtil()
            # 准备参数
            args=(name,f)
            # 执行插入语句
            db.dml(sql,args)

# 测试代码
if __name__ == "__main__":
    # 创建Music类的实例对象
    service = Music()
    # 利用实例对象调用实例方法
    re = service.login("muxikeqi", "123321")
    print(re)

7、实现音乐列表和用户绑定

概述:实现音乐列表和用户的绑定主要是为play_info表添加数据即可,play_info表包含了数据库id和用户id,契合用户和音乐的对应关系。

7.1、获取用户id

思路:为service.py文件下的Music类添加一个构造方法,构造方法用于放置一个user变量,用于保存用户id,默认为空。结合login函数中变量re是数据库进行查询后的返回的查询结果,通过判断re是否为空来判断用户是否登录。当用户不为空时(用户登录成功),我们将返回的结果re赋值给构造方法中的user变量,此时,user就拿到返回的用户信息,然后获取用户id在user_info表中对应位置的值就拿到了用户id。

    def __init__(self):
        # 用户默认为空
        self. User = None

    def login(self, uname: str, password: str) -> bool:
        """
        :param uname:用户名
        :param password:密码
        :return: 登录成功返回True,登录失败返回False
        """
        # 准备要执行的sql语句
        sql = "select * from user_info where uname=%s and password=%s"
        # 准备sql语句需要的参数
        args = (uname, password)
        # 创建工具对象(实际时获取数据库的链接对象和游标对象)
        db = DBUtil()
        # 利用游标对象调用对应的单条查询方法
        re = db.query_one(sql, args)
        # 由于query_one函数运行成功后是有返回值的,可以通过返回值判断是否查询成功,进而判断是否有该用户
        if re:
            print("登录成功")
            self.user=re
            # 查看内容是否包含u_id对应的内容
            # print(self.user)
            return True
        else:
            print("登录失败")
            return False

7.2、获取音乐id

思路:在service.py文件中的有一个add_music函数,我们可以在修改music_info表的同时为play_info表添加数据,而add_music函数中通过db.dml(sql,args)对music_info表添加了数据,如果我们能让dml方法告诉我们它添加的id为多少那么获取音乐id的问题就解决了,因此这里可以直接将工具类中的dml函数重写一份,添加一个获取添加id的方法并返回,这里我为这个函数取名为dml_back_id。(写完本小节还是存在问题的,需要看下一小节)

工具类重写的dml_back_id函数如下:

 # 重写上面的dml函数,增加返回id的操作
    def dml_back_id(self, sql, args):
        """
        本函数用于封装Mysql的DML语句,用于实现数据的增删改
        """
        # 进行DML语句操作时一定要注意报错导致无法正常关闭链接
        try:
            # 执行sql中的DML语句
            self.cursor.execute(sql, args)
            # 获取添加的id
            id = self.con.insert_id()
            # DML操作一定要通过链接对象提交事务
            self.con.commit()
            # 返回id
            return id
        except Exception as e:
            print("存在错误,错误信息如下:", e)
            # 回滚前先判断链接还是否存在
            if self.con:
                # 回滚到原状态
                self.con.rollback()
        # 使用try...except...finally...最重要的作用就是保证链接正常关闭
        finally:
            print("即将关闭链接")
            self.close()

service.py文件的add_music函数修改如下:

    def add_music(self,files:tuple[str]) -> None:
        """
        该函数用于将前台返回的文件路径存储到数据库中
        :param file:音乐文件的路径,默认是多个,元素类型为字符串
        :return: None
        """
        # 编写sql语句
        sql = "insert into music_info(name,path) values(%s,%s)"
        # 遍历数据
        for f in files:
            print(f)
            # 根据路径获取歌曲名
            name = f[f.rfind("/")+1:f.rfind(".")]
            print(name)
            # 创建数据库链接对象
            db = DBUtil()
            # 准备参数
            args=(name,f)
            # 将音乐信息添加到music_info表中
            m_id = db.dml_back_id(sql,args)
            # 实现音乐与用户绑定
            musicBindId_sql = "insert into play_info(u_id,m_id) values(%s,%s)"
            args=(self.user[0],m_id)
            db.dml(musicBindId_sql,args)

7.3、问题解决

问题1:无法获取到用户id。

原因分析:用户是从前端文件进行登录的,在ui.py文件的测试内容中我们创建了一个实例对象,用于调用service.py文件中的login函数,判断用户能否登录成功,但登录成功后就进入了Ui类的构造方法,构造方法为导入音乐按钮添加了一个名为importMusic的点击事件,在importMusic函数中又创建了一个实例对象,用于调用service.py文件中的add_music方法,我们是通过第二个对象去获取用户id,但用户id保存到了第一个实例对象。

解决办法:将第二个实例对象删除,再用第一个实例对象调用add_music函数即可。

import tkinter
from service import Music
import tkinter.filedialog

class Ui:
    def __init__(self):
        # 主窗口
        top = tkinter.Tk()

        # 创建按钮对象,第一个参数是父容器,text表示显示的内容
        b1 = tkinter.Button(top, text="播放")
        b2 = tkinter.Button(top, text="导入音乐")
        b3 = tkinter.Button(top, text="删除音乐")
        # 设置按钮显示位置(row表示放在哪一行,column表示放在哪一列,pad表示距离边框的内边距,单位为像素)
        b1.grid(row=1,column=1,padx=10,pady=10)
        b2.grid(row=1,column=2,padx=10,pady=10)
        b3.grid(row=1,column=3,padx=10,pady=10)

        # 为导入音乐的按钮添加点击事件,bind方法的第一个参数是事件名称,第二个参数是点击事件(点击按钮后触发的函数)
        b2.bind("<Button-1>",self.importMusic)

        # 创建播放列表
        lisbox = tkinter.Listbox(top)
        # 设置播放列表位置,columnspan表示垮了多少列
        lisbox.grid(row=2,column=0,columnspan=4,padx=10,pady=10)

        # 进入消息循环
        top.mainloop()

    # 导入音乐的点击事件
    def importMusic(self,event):
        # 弹出选择框(返回的结果是元组)(一定要通过filetypes限制文件类型,否则什么文件都能加入进来)
        filenames = tkinter.filedialog.askopenfilenames(filetypes=[("mp3",".mp3"),("flac",".flac"),("mgg",".mgg")])
        # 创建服务对象(这里如果不干掉,绑定用户和音乐时就拿不到u_id,因为创建了两个实例对象)
        # ser = Music()
        # 调用增加音乐的功能(将前端的数据发送给后端处理)
        ser.add_music(filenames)

if __name__=="__main__":
    # 获取用户名和密码
    uname = input("请输入用户名:")
    password = input("请输入密码:")
    # 创建Music类的实例对象
    ser = Music()
    # 利用实例对象调用实例方法(由于会返回布尔值,所以直接进行判断)
    if ser.login(uname,password):
        Ui()
    else:
        print("用户名或密码错误!")

问题2:报错说数据库已经关闭。

问题分析:在获取音乐id时,我们通过重构工具类中dml函数使其返回新加的id,但执行完sql语句并提交事务后就返回了数据,返回数据后就直接运行了finally中关闭数据库的语句。

解决办法:重新链接一下数据库即可。

    def add_music(self,files:tuple[str]) -> None:
        """
        该函数用于将前台返回的文件路径存储到数据库中
        :param file:音乐文件的路径,默认是多个,元素类型为字符串
        :return: None
        """
        # 编写sql语句
        sql = "insert into music_info(name,path) values(%s,%s)"
        # 遍历数据
        for f in files:
            print(f)
            # 根据路径获取歌曲名
            name = f[f.rfind("/")+1:f.rfind(".")]
            print(name)
            # 创建数据库链接对象
            db = DBUtil()
            # 准备参数
            args=(name,f)
            # 将音乐信息添加到music_info表中
            m_id = db.dml_back_id(sql,args)
            # 上一句调用的函数中由于需要执行return语句,所以会直接执行finally语句中关闭数据库的操作,因此需要重新链接数据库
            db = DBUtil()
            # 实现音乐与用户绑定
            musicBindId_sql = "insert into play_info(u_id,m_id) values(%s,%s)"
            args=(self.user[0],m_id)
            db.dml(musicBindId_sql,args)

完整service.py文件内容如下:

from tools import DBUtil

class Music:

    def __init__(self):
        # 用户默认为空
        self.user = None

    def login(self, uname: str, password: str) -> bool:
        """
        :param uname:用户名
        :param password:密码
        :return: 登录成功返回True,登录失败返回False
        """
        # 准备要执行的sql语句
        sql = "select * from user_info where uname=%s and password=%s"
        # 准备sql语句需要的参数
        args = (uname, password)
        # 创建工具对象(实际时获取数据库的链接对象和游标对象)
        db = DBUtil()
        # 利用游标对象调用对应的单条查询方法
        re = db.query_one(sql, args)
        # 由于query_one函数运行成功后是有返回值的,可以通过返回值判断是否查询成功,进而判断是否有该用户
        if re:
            print("登录成功")
            self.user=re
            # 查看内容是否包含u_id对应的内容
            print(self.user)
            print(self.user[0])
            return True
        else:
            print("登录失败")
            return False

    def add_music(self,files:tuple[str]) -> None:
        """
        该函数用于将前台返回的文件路径存储到数据库中
        :param file:音乐文件的路径,默认是多个,元素类型为字符串
        :return: None
        """
        # 编写sql语句
        sql = "insert into music_info(name,path) values(%s,%s)"
        # 遍历数据
        for f in files:
            print(f)
            # 根据路径获取歌曲名
            name = f[f.rfind("/")+1:f.rfind(".")]
            print(name)
            # 创建数据库链接对象
            db = DBUtil()
            # 准备参数
            args=(name,f)
            # 将音乐信息添加到music_info表中
            m_id = db.dml_back_id(sql,args)

            # 上一句调用的函数中由于需要执行return语句,所以会直接执行finally语句中关闭数据库的操作,因此需要重新链接数据库
            db = DBUtil()
            # 实现音乐与用户绑定
            musicBindId_sql = "insert into play_info(u_id,m_id) values(%s,%s)"
            args=(self.user[0],m_id)
            db.dml(musicBindId_sql,args)

# 测试代码
if __name__ == "__main__":
    # 创建Music类的实例对象
    service = Music()
    # 利用实例对象调用实例方法
    re = service.login("muxikeqi", "123321")
    print(re)

完整ui.py文件内容如下:

import tkinter
from service import Music
import tkinter.filedialog

class Ui:
    def __init__(self):
        # 主窗口
        top = tkinter.Tk()

        # 创建按钮对象,第一个参数是父容器,text表示显示的内容
        b1 = tkinter.Button(top, text="播放")
        b2 = tkinter.Button(top, text="导入音乐")
        b3 = tkinter.Button(top, text="删除音乐")
        # 设置按钮显示位置(row表示放在哪一行,column表示放在哪一列,pad表示距离边框的内边距,单位为像素)
        b1.grid(row=1,column=1,padx=10,pady=10)
        b2.grid(row=1,column=2,padx=10,pady=10)
        b3.grid(row=1,column=3,padx=10,pady=10)

        # 为导入音乐的按钮添加点击事件,bind方法的第一个参数是事件名称,第二个参数是点击事件(点击按钮后触发的函数)
        b2.bind("<Button-1>",self.importMusic)

        # 创建播放列表
        lisbox = tkinter.Listbox(top)
        # 设置播放列表位置,columnspan表示垮了多少列
        lisbox.grid(row=2,column=0,columnspan=4,padx=10,pady=10)

        # 进入消息循环
        top.mainloop()

    # 导入音乐的点击事件
    def importMusic(self,event):
        # 弹出选择框(返回的结果是元组)(一定要通过filetypes限制文件类型,否则什么文件都能加入进来)
        filenames = tkinter.filedialog.askopenfilenames(filetypes=[("mp3",".mp3"),("flac",".flac"),("mgg",".mgg")])
        # 创建服务对象(这里如果不干掉,绑定用户和音乐时就拿不到u_id,因为创建了两个实例对象)
        # ser = Music()
        # 调用增加音乐的功能(将前端的数据发送给后端处理)
        ser.add_music(filenames)

if __name__=="__main__":
    # 获取用户名和密码
    uname = input("请输入用户名:")
    password = input("请输入密码:")
    # 创建Music类的实例对象
    ser = Music()
    # 利用实例对象调用实例方法(由于会返回布尔值,所以直接进行判断)
    if ser.login(uname,password):
        ui=Ui()
    else:
        print("用户名或密码错误!")

运行结果如下:

运行后的play_info表数据如下:

8、实现加载播放列表

概述:为了后续顺利的完成功能开发,先通过navicat的查询窗口尝试写出一个查询语句,通过play_info表的u_id找出其对应的音乐名(即music_info表中m_id对应的name)(既然涉及到两个表之间不相关列的查询就可以考虑sql99标准下的左(右)外连接查询)。

SELECT name FROM play_info p LEFT JOIN music_info m ON p.m_id=m.id WHERE u_id=1;

运行结果如下:

接下来为后端的service.py文件添加一个函数用于查询用户对应的歌曲列表。

    def find_user_music(self) -> list[str]:
        """
        本函数用于查询特定用户id对应的音乐列表
        """
        # 准备sql语句(前面已经准备好了)
        sql = "SELECT name FROM play_info p LEFT JOIN music_info m ON p.m_id=m.id WHERE u_id=%s;"
        # 创建工具类对象
        db = DBUtil();
        # 执行sql语句(这里使用和上一章同样的方法获取用户id)
        music_list = db.query_many(sql,self.user[0])
        # 将结果返回
        return  music_list

然后参考菜鸟教程中关于Tkinter的教程,了解添加列表的玩法:

最后,为前端的ui.py文件调用find_user_music函数,只要有歌曲被添加或进入窗口都会显示该用户对应的歌曲列表。

import tkinter
from service import Music
import tkinter.filedialog

class Ui:
    def __init__(self):
        # 主窗口
        top = tkinter.Tk()

        # 创建按钮对象,第一个参数是父容器,text表示显示的内容
        b1 = tkinter.Button(top, text="播放")
        b2 = tkinter.Button(top, text="导入音乐")
        b3 = tkinter.Button(top, text="删除音乐")
        # 设置按钮显示位置(row表示放在哪一行,column表示放在哪一列,pad表示距离边框的内边距,单位为像素)
        b1.grid(row=1,column=1,padx=10,pady=10)
        b2.grid(row=1,column=2,padx=10,pady=10)
        b3.grid(row=1,column=3,padx=10,pady=10)

        # 为导入音乐的按钮添加点击事件,bind方法的第一个参数是事件名称,第二个参数是点击事件(点击按钮后触发的函数)
        b2.bind("<Button-1>",self.importMusic)

        # 创建播放列表(为了让importMusic函数能够使用,所有为变量传入了对象self)
        self.lisbox = tkinter.Listbox(top)
        # 设置播放列表位置,columnspan表示垮了多少列
        self.lisbox.grid(row=2,column=0,columnspan=4,padx=10,pady=10)

        self.music_list()

        # 进入消息循环
        top.mainloop()

    # 导入音乐的点击事件
    def importMusic(self,event):
        # 弹出选择框(返回的结果是元组)(一定要通过filetypes限制文件类型,否则什么文件都能加入进来)
        filenames = tkinter.filedialog.askopenfilenames(filetypes=[("mp3",".mp3"),("flac",".flac"),("mgg",".mgg")])
        # 创建服务对象(这里如果不干掉,绑定用户和音乐时就拿不到u_id,因为创建了两个实例对象)
        # ser = Music()
        # 调用增加音乐的功能(将前端的数据发送给后端处理)
        ser.add_music(filenames)
        # 获取用户的音乐列表
        self.music_list()

    def music_list(self) -> list[str]:
        # 调用获取列表的函数
        m_lis = ser.find_user_music()
        print(m_lis)
        for m in m_lis:
            self.lisbox.insert(0, m[0])

if __name__=="__main__":
    # 获取用户名和密码
    uname = input("请输入用户名:")
    password = input("请输入密码:")
    # 创建Music类的实例对象
    ser = Music()
    # 利用实例对象调用实例方法(由于会返回布尔值,所以直接进行判断)
    if ser.login(uname,password):
        ui=Ui()
    else:
        print("用户名或密码错误!")

运行后的窗口显示如下:

运行结果如下:

9、实现通过列表播放音乐

概述:本章就做两件事,首先确定用户点击的是列表中哪一首歌曲,其次,用户点击播放按钮后能播放对应的歌曲。

9.1、前端获取歌名

①、首先为播放按钮添加点击事件

b1.bind("<ButtonRelease-1>", self.play_music)

②、书写对应的点击事件

    def play_music(self,event):
        # 获取当前列表中选中音乐的索引
        index = self.lisbox.curselection()
        # 根据索引索取音乐的名称
        music_name = self.lisbox.get(index)
        print(music_name)

运行程序后,点击列表中的任意歌曲再点击播放就能顺利的打印歌曲信息,此时,已经正确地拿到了音乐名。

9.2、后端逻辑实现

①、将获取的歌曲名传给后端service.py文件中play_music函数

    def play_music(self,event):
        # 获取当前列表中选中音乐的索引
        index = self.lisbox.curselection()
        # 根据索引索取音乐的名称
        music_name = self.lisbox.get(index)
        # print(music_name)
        # 将音乐名称传递给服务对象
        ser.play_music(music_name)

②、实现play_music函数中的sql语句(这里采用左外连接,关联了music_info表和play_info表,关联的字段是m表的id和p表的m_id,条件同时限制p表中的用户名和m表的歌曲名)

select path from music_info m left join play_info p on m.id=p.m_id where m.name=%s and p.u_id=%s

③、补全play_music函数

    def play_music(self,music_name:str) -> None:
        """
        播放音乐
        :param music_name:音乐名称
        :return: None
        """
        print("进入play_music函数")
        # 编写sql
        sql = "select path from music_info m left join play_info p on m.id=p.m_id where m.name=%s and p.u_id=%s;"
        # 创建工具类(链接数据库)
        db = DBUtil()
        # 运行sql并将返回的结果保存到变量path中
        args=(music_name,self.user[0])
        path = db.query_one(sql,args)[0]
        print(path)
        print(len(path))
        # 调用播放器播放音乐(拷贝play.py文件的代码)
        # 初始化加载音乐的混合器
        pygame.mixer.init()
        # 加载音乐(路径可以是相对路径也可以是绝对路径)
        pygame.mixer.music.load(path)
        # 播放音乐
        pygame.mixer.music.play()

运行结果如下:

注意Pygame不支持播放.mgg格式的音乐文件

9.3、修改bug

问题描述:只要点击了导入音乐,就会将重新获取的列表添加到旧列表的下面。

为ui.py文件中的music_list函数清空原有列表m_lis

    def music_list(self) -> list[str]:
        """
        本函数用于获取音乐列表
        """
        # 调用获取列表的函数
        m_lis = ser.find_user_music()
        # 清空列表
        self.lisbox.delete(0,tkinter.END)
        # 重新加载列表
        for m in m_lis:
            self.lisbox.insert(0, m[0])

10、实现删除音乐

①、为ui.py文件中的删除按钮添加点击事件

b3.bind("<ButtonRelease-1>", self.delete_music)

②、实现点击事件

    def delete_music(self,event):
        """
        本函数用于删除用户指定的音乐
        """
        # 获取当前列表中选中音乐的索引
        index = self.lisbox.curselection()
        # 根据索引索取音乐的名称
        music_name = self.lisbox.get(index)
        # 调用删除功能
        ser.delete_music(music_name);
        # 重新加载播放列表
        self.music_list()

③、实现delete_music函数

    def delete_music(self,music_name:str) -> None:
        # 编写SQL
        sql_query_m_id = "select m.id from music_info m left join play_info p on m.id=p.m_id where m.name=%s and p.u_id=%s;"
        sql_delete_music = "delete from music_info where id=%s"
        sql_delete_play = "delete from play_info where m_id=%s and u_id=%s"
        # 创建工具类(链接数据库)
        db = DBUtil()
        args = (music_name, self.user[0])
        # 运行sql
        m_id = db.query_one(sql_query_m_id, args)[0]
        # 准备参数
        args2 = (m_id,self.user[0])
        DBUtil().dml(sql_delete_play,args2)
        # 注意:有外键约束的列,要先删除有外键关联列的数据,再删除其他数据
        DBUtil().dml(sql_delete_music,m_id)

运行结果如下:

附件:完整文件源码(需要自己创建数据库和表)

完整工具类tools.py文件如下:

import pymysql

class DBUtil:
    """
    工具类用于简化链接和关闭数据库的操作以及对数据的操作
    """

    # 单独保存链接的参数,可以将其保存到特定文件中,直接调用文件获取也可
    config = {
        'host': "localhost",
        'user': "root",
        'passwd': "root",
        'db': "db_music",
        'charset': "utf8",
        'port': 3306
    }

    def __init__(self) -> None:
        """
        构造函数用于获取链接和游标
        """
        # **指字典对象
        self.con = pymysql.connect(**DBUtil.config)
        self.cursor = self.con.cursor()

    def close(self) -> None:
        """
        该函数用于关闭链接和游标(关闭前需要判断是否存在)
        """
        # 存在游标就关闭
        if self.cursor:
            self.cursor.close()
        # 存在链接就关闭
        if self.con:
            self.con.close()

    def dml(self, sql, args):
        """
        本函数用于封装Mysql的DML语句,用于实现数据的增删改
        """
        # 进行DML语句操作时一定要注意报错导致无法正常关闭链接
        try:
            # 执行sql中的DML语句
            self.cursor.execute(sql, args)
            # DML操作一定要通过链接对象提交事务
            self.con.commit()
        except Exception as e:
            print("存在错误,错误信息如下:", e)
            # 回滚前先判断链接还是否存在
            if self.con:
                # 回滚到原状态
                self.con.rollback()
        # 使用try...except...finally...最重要的作用就是保证链接正常关闭
        finally:
            print("即将关闭链接")
            self.close()

    # 重写上面的dml函数,增加返回id的操作
    def dml_back_id(self, sql, args):
        """
        本函数用于封装Mysql的DML语句,用于实现数据的增删改
        """
        # 进行DML语句操作时一定要注意报错导致无法正常关闭链接
        try:
            # 执行sql中的DML语句
            self.cursor.execute(sql, args)
            # 获取添加的id
            id = self.con.insert_id()
            print(id)
            # DML操作一定要通过链接对象提交事务
            self.con.commit()
            # 返回id
            return id
        except Exception as e:
            print("存在错误,错误信息如下:", e)
            # 回滚前先判断链接还是否存在
            if self.con:
                # 回滚到原状态
                self.con.rollback()
        # 使用try...except...finally...最重要的作用就是保证链接正常关闭
        finally:
            print("即将关闭链接")
            self.close()


    def query_one(self, sql, args):
        """
        本函数用于查询单条数据
        """
        try:
            self.cursor.execute(sql, args)
            re = self.cursor.fetchone()
            return re
        except Exception as e:
            print("存在错误,错误信息如下:", e)
        finally:
            print("即将关闭链接")
            self.close()

    def query_many(self, sql, args):
        """
        本函数用于查询所有数据
        """
        try:
            self.cursor.execute(sql,args)
            # 获取结果并返回数据
            return self.cursor.fetchall()

        except Exception as e:
            print("存在错误,错误信息如下:", e)

        finally:
            print("即将关闭链接")
            self.close()

if __name__ == "__main__":
    # # 获取链接对象
    # db = DBUtil()
    # # 准备sql语句及其对应的参数
    # sql = "select * from user_info where uname=%s and password=%s;"
    # args =["muxikeqi","123321"]
    # # 运行sql语句并关闭链接
    # re = db.query_one(sql,args)
    # print(re)
    pass

完整play.py文件如下:

import pygame
import time
# 初始化加载音乐的混合器
pygame.mixer.init()
# 加载音乐(路径可以是相对路径也可以是绝对路径)
pygame.mixer.music.load(f".\music\c.flac")
# 播放音乐
pygame.mixer.music.play()
# 程序进入等待(不要立即关闭程序),单位为秒
time. Sleep(20)

完整ui.py文件内容如下:

# import tkinter
from tkinter import *
from service import Music
import tkinter.filedialog

class Ui:
    def __init__(self):
        # 主窗口
        top = tkinter.Tk()
        # top.withdraw()

        # 创建按钮对象,第一个参数是父容器,text表示显示的内容
        b1 = tkinter.Button(top, text="播放")
        b2 = tkinter.Button(top, text="导入音乐")
        b3 = tkinter.Button(top, text="删除音乐")
        # 设置按钮显示位置(row表示放在哪一行,column表示放在哪一列,pad表示距离边框的内边距,单位为像素)
        b1.grid(row=0,column=1,padx=10,pady=10)
        b2.grid(row=0,column=2,padx=10,pady=10)
        b3.grid(row=0,column=3,padx=10,pady=10)

        # 为导入音乐的按钮添加点击事件,bind方法的第一个参数是事件名称,第二个参数是点击事件(点击按钮后触发的函数)
        b2.bind("<ButtonRelease-1>",self.importMusic)
        # ButtonRelease表示点击并释放了(第一个参数写法固定,不要更改)
        b1.bind("<ButtonRelease-1>", self.play_music)
        b3.bind("<ButtonRelease-1>", self.delete_music)

        # 创建播放列表(为了让importMusic函数能够使用,所有为变量传入了对象self)
        self.lisbox = tkinter.Listbox(top)
        # 设置播放列表位置,columnspan表示垮了多少列
        self.lisbox.grid(row=1,column=0,columnspan=4,padx=5,pady=5)

        self.music_list()

        # 进入消息循环
        top.mainloop()

    # 导入音乐的点击事件
    def importMusic(self,event):
        # 弹出选择框(返回的结果是元组)(一定要通过filetypes限制文件类型,否则什么文件都能加入进来)
        filenames = tkinter.filedialog.askopenfilenames(filetypes=[("mp3",".mp3"),("flac",".flac")])
        # 创建服务对象(这里如果不干掉,绑定用户和音乐时就拿不到u_id,因为创建了两个实例对象)
        # ser = Music()
        # 调用增加音乐的功能(将前端的数据发送给后端处理)
        ser.add_music(filenames)
        # 获取用户的音乐列表
        self.music_list()

    def music_list(self) -> list[str]:
        """
        本函数用于获取音乐列表
        """
        # 调用获取列表的函数
        m_lis = ser.find_user_music()
        # 清空列表
        self.lisbox.delete(0,tkinter.END)
        # 重新加载列表
        for m in m_lis:
            self.lisbox.insert(0, m[0])

    def play_music(self,event):
        # 获取当前列表中选中音乐的索引
        index = self.lisbox.curselection()
        # 根据索引索取音乐的名称
        music_name = self.lisbox.get(index)
        # 将音乐名称传递给服务对象
        ser.play_music(music_name)

    def delete_music(self,event):
        """
        本函数用于删除用户指定的音乐
        """
        # 获取当前列表中选中音乐的索引
        index = self.lisbox.curselection()
        # 根据索引索取音乐的名称
        music_name = self.lisbox.get(index)
        # 调用删除功能
        ser.delete_music(music_name);
        # 重新加载播放列表
        self.music_list()

if __name__=="__main__":
    # 获取用户名和密码
    uname = input("请输入用户名:")
    password = input("请输入密码:")
    # 创建Music类的实例对象
    ser = Music()
    # 利用实例对象调用实例方法(由于会返回布尔值,所以直接进行判断)
    if ser.login(uname,password):
        ui=Ui()
    else:
        print("用户名或密码错误!")

完整service.py文件如下:

from tools import DBUtil
import pygame

class Music:

    def __init__(self):
        # 用户默认为空
        self.user = None

    def login(self, uname: str, password: str) -> bool:
        """
        :param uname:用户名
        :param password:密码
        :return: 登录成功返回True,登录失败返回False
        """
        # 准备要执行的sql语句
        sql = "select * from user_info where uname=%s and password=%s"
        # 准备sql语句需要的参数
        args = (uname, password)
        # 创建工具对象(实际时获取数据库的链接对象和游标对象)
        db = DBUtil()
        # 利用游标对象调用对应的单条查询方法
        re = db.query_one(sql, args)
        # 由于query_one函数运行成功后是有返回值的,可以通过返回值判断是否查询成功,进而判断是否有该用户
        if re:
            print("登录成功")
            self.user=re
            # 查看内容是否包含u_id对应的内容
            # print(self.user)
            # print(self.user[0])
            return True
        else:
            print("登录失败")
            return False

    def add_music(self,files:tuple[str]) -> None:
        """
        该函数用于将前台返回的文件路径存储到数据库中
        :param file:音乐文件的路径,默认是多个,元素类型为字符串
        :return: None
        """
        # 编写sql语句
        sql = "insert into music_info(name,path) values(%s,%s)"
        # 遍历数据
        for f in files:
            # 根据路径获取歌曲名
            name = f[f.rfind("/")+1:f.rfind(".")]
            # 创建数据库链接对象
            db = DBUtil()
            # 准备参数
            args=(name,f)
            # 将音乐信息添加到music_info表中
            m_id = db.dml_back_id(sql,args)

            # 上一句调用的函数中由于需要执行return语句,所以会直接执行finally语句中关闭数据库的操作,因此需要重新链接数据库
            db = DBUtil()
            # 实现音乐与用户绑定
            musicBindId_sql = "insert into play_info(u_id,m_id) values(%s,%s)"
            args=(self.user[0],m_id)
            db.dml(musicBindId_sql,args)

    def find_user_music(self) -> list[str]:
        """
        本函数用于查询特定用户id对应的音乐列表
        """
        # 准备sql语句(前面已经准备好了)
        sql = "SELECT name FROM play_info p LEFT JOIN music_info m ON p.m_id=m.id WHERE u_id=%s;"
        # 创建工具类对象
        db = DBUtil();
        # 执行sql语句(这里使用和上一章同样的方法获取用户id)
        music_list = db.query_many(sql,self.user[0])
        # 将结果返回
        return  music_list

    def play_music(self,music_name:str) -> None:
        """
        播放音乐
        :param music_name:音乐名称
        :return: None
        """
        # 编写sql
        sql = "select path from music_info m left join play_info p on m.id=p.m_id where m.name=%s and p.u_id=%s;"
        # 创建工具类(链接数据库)
        db = DBUtil()
        args=(music_name,self.user[0])
        # 运行sql并将返回的结果保存到变量path中
        path = db.query_one(sql,args)[0]
        # 调用播放器播放音乐(拷贝play.py文件的代码)
        # 初始化加载音乐的混合器
        pygame.mixer.init()
        # 加载音乐(路径可以是相对路径也可以是绝对路径)
        pygame.mixer.music.load(path)
        # 播放音乐
        pygame.mixer.music.play()

    def delete_music(self,music_name:str) -> None:
        # 编写SQL
        sql_query_m_id = "select m.id from music_info m left join play_info p on m.id=p.m_id where m.name=%s and p.u_id=%s;"
        sql_delete_music = "delete from music_info where id=%s"
        sql_delete_play = "delete from play_info where m_id=%s and u_id=%s"
        # 创建工具类(链接数据库)
        db = DBUtil()
        args = (music_name, self.user[0])
        # 运行sql
        m_id = db.query_one(sql_query_m_id, args)[0]
        # 准备参数
        args2 = (m_id,self.user[0])
        DBUtil().dml(sql_delete_play,args2)
        # 注意:有外键约束的列,要先删除有外键关联列的数据,再删除其他数据
        DBUtil().dml(sql_delete_music,m_id)

# 测试代码
if __name__ == "__main__":
    # 创建Music类的实例对象
    service = Music()
    # 利用实例对象调用实例方法
    re = service.login("muxikeqi", "123321")
    print(re)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/638107.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

three.js能实现啥效果?看过来,这里都是它的菜(08)

在Three.js中实现旋转动画的原理是通过修改对象的旋转属性来实现的&#xff0c;通常使用渲染循环&#xff08;render loop&#xff09;来更新对象的旋转状态&#xff0c;从而实现动画效果。 具体的原理包括以下几个步骤&#xff1a; 创建对象&#xff1a;首先创建一个需要旋转…

东软联合福建省大数据集团打造“数据要素×医疗健康”服务新模式

5月23日&#xff0c;东软集团与福建省大数据集团有限公司在福州签订战略合作协议。 据「TMT星球」了解&#xff0c;双方将在健康医疗数据要素价值领域展开合作&#xff0c;通过大数据服务&#xff0c;赋能商业保险公司的产品设计和保险两核&#xff0c;打造“数据要素医疗健康…

Superset二次开发之柱状图自定义初始化时Data Zoom数据缩放值

Superset项目柱状图来自Echarts 首先Echarts实现柱状图数据缩放初始化默认值的效果 核心代码 设置Datazoom 的start 和end myChart.showLoading(); $.get(ROOT_PATH + /data/asset/data/obama_budget_proposal_2012.list.json,function (obama_budget_2012) {myChart.hideLo…

工业4.0 企业级云MES全套源码,支持app、小程序、H5、台后管理端

工业4.0 企业级云MES全套源码&#xff0c;支持app、小程序、H5、台后管理端 采用javaspringboot-vue.jsuniapp开发 随着工业4.0的快速发展&#xff0c;制造执行系统&#xff08;MES&#xff09;成为了智能制造的核心。今天&#xff0c;将为大家介绍一款开源的MES系统——MES管…

【每日一题】52.20个机器学习问题 2 (模型部署、实践流程和应用问题)

在上一篇《20个机器学习问答题》中&#xff0c;问题主要围绕机器学习的基础概念和理论知识。 这次&#xff0c;本篇内容针对机器学习的实践和应用继续提出了20个不同的问题。【点击跳转原文】 在实际应用中&#xff0c;机器学习模型的建立流程是怎样的&#xff1f; 机器学习模…

Python代码注释的艺术与智慧

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言&#xff1a;注释的必要性 二、注释的误区&#xff1a;不是越多越好 过度注释的问题…

【NumPy】关于numpy.transpose()函数,看这一篇文章就够了

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

python实现nacos服务注册和HTTP探活

如果使用nacos-sdk-python&#xff08;注意适用nacos版本&#xff09;&#xff0c;需要按照下面的链接修改源码的bug https://github.com/nacos-group/nacos-sdk-python/issues/135 代码如下&#xff1a; import nacos import threading import socket import requests impo…

群晖搭建网页版Linux Ubuntu系统并实现远程访问

文章目录 1. 下载Docker-Webtop镜像2. 运行Docker-Webtop镜像3. 本地访问网页版Linux系统4. 群晖NAS安装Cpolar工具5. 配置异地访问Linux系统6. 异地远程访问Linux系统7. 固定异地访问的公网地址 docker-webtop是一个基于Docker的Web桌面应用&#xff0c;它允许用户通过浏览器远…

[图解]产品经理创新模式02改善信息流转

1 00:00:02,160 --> 00:00:04,000 第二种改进模式 2 00:00:04,010 --> 00:00:06,340 就是改善信息流转 3 00:00:06,550 --> 00:00:08,000 它是这样的 4 00:00:09,250 --> 00:00:11,290 当电脑系统越来越多的时候 5 00:00:11,300 --> 00:00:12,530 就会出现这…

LeetCode刷题之HOT100之汉明距离

大家晚上好啊&#xff0c;今天几乎啥也没干&#xff0c;上个课就耽误了一下午&#xff0c;晚上来了积极性也不高&#xff0c;先完成今天的题目吧&#xff0c;请看题&#xff1a; 1、题目描述 2、逻辑分析 没有遇到过这种题目&#xff0c;想不出来有什么解法&#xff0c;看题解…

Transormer(1)-结构解读

Transormer块主要由四个部分组成&#xff0c;注意力层、位置感知前馈神经网络、残差连接和层归一化。 1、注意力层(Multi-Head Attention) 使用多头注意力机制整合上下文语义&#xff0c;它使得序列中任意两个单词之间的依赖关系可以直接被建模而不基于传统的循环结构&#…

实战Java虚拟机-实战篇

一、内存调优 1.内存溢出和内存泄漏 内存泄漏&#xff08;memory leak&#xff09;&#xff1a;在Java中如果不再使用一个对象&#xff0c;但是该对象依然在GC ROOT的引用链上&#xff0c;这个对象就不会被垃圾回收器回收&#xff0c;这种情况就称之为内存泄漏。内存泄漏绝大…

Oracle EBS Interface/API(55)- AR收款核销

快速参考 参考点内容功能导航N: AR->收款->收款并发请求None基表AR.AR_RECEIVABLE_APPLICATIONS_ALLAPI参考下面介绍错误信息表None接口FormNone接口RequestNoneDebug ProfileNone详细例子参考如下实例官方文档None数据验证包None标准界面 Path: AR->收款->收款 …

漫谈企业信息化安全 - 勒索软件攻击

一、引言 首先&#xff0c;网络攻击是一个非常广泛的话题&#xff0c;网络攻击从一般分类上包含了恶意软件攻击、钓鱼攻击、拒绝服务攻击&#xff08;DoS/DDoS&#xff09;、中间人攻击、SQL注入、跨站脚本、0-Day攻击、供应链攻击、密码攻击等等&#xff0c;勒索软件攻击只是…

【永洪BI】传参组件

1. 参数 参数也叫做变量。永洪中&#xff0c;支持参数的地方很多&#xff0c;几乎涉及整个永洪产品&#xff0c;用起来非常灵活&#xff0c;而且具有强大的能力&#xff0c;可用于各种需要动态改变值的场景。数据源、数据集、报表、实验都可以定义和使用参数&#xff0c;比如在…

爬虫技术升级:如何结合DrissionPage和Auth代理插件实现数据采集

背景/引言 在大数据时代&#xff0c;网络爬虫技术已经成为数据收集的重要手段之一。爬虫技术可以自动化地从互联网上收集数据&#xff0c;节省大量人力和时间成本。然而&#xff0c;当使用需要身份验证的代理服务器时&#xff0c;许多现有的爬虫框架并不直接支持代理认证。这就…

5.1网安学习第五阶段第一周回顾(个人学习记录使用)

本周重点 ①日志检测与HIDS系统 ②Wazuh的应用 ③Wazuh配合syslog的应用 ④Wazuh配置邮箱预警 ⑤Wazuh与Elastic整合 ⑥Wazuh检测木马与配置 ⑦各类日志分析工具(详见笔记) 本周主要内容 ①日志检测与HIDS系统 一、安全服务工程师岗位职责 网络安全服务工程师的职责主…

【Sync FIFO介绍及基于Verilog的实现】

Sync FIFO介绍及实现 1 Intro2 Achieve2.1 DFD2.2 Intf2.3 Module 本篇博客介绍无论是编码过程中经常用到的逻辑–FIFO&#xff1b;该FIFO是基于单时钟下的同步FIFO&#xff1b; FiFO分类&#xff1a;同步FiFO VS 异步FiFO&#xff1b; 1 Intro FIFO可以自己实现&#xff0c;但…

mysqldump提示Using a password on the command line interface can be insecured的解决办法

mysql数据库备份一句话执行命令 mysqldump --all-databases -h127.0.0.1 -uroot -p123456 > allbackupfile.sql 提示如下提示 [rootyfvyy5b2on3knb8q opt]# mysqldump --all-databases -h127.0.0.1 > allbackupfile.sql mysqldump: Couldnt execute SELECT COLUMN_NA…