玩转Flask

目录

标准 Flask 项目结构

powershell 复制代码
myflask/
├── app.py       # 主程序
├── static/      # 静态文件(css/js/img)
└── templates/   # 网页模板
powershell 复制代码
# 创建项目文件夹
mkdir myflask
cd myflask

# 创建核心文件
touch app.py
mkdir static templates

# 写入基础代码
echo "from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    return 'Hello Flask 项目!'

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)" > app.py

运行

powershell 复制代码
# 运行(默认端口5000)
python app.py

# 指定端口
python app.py --port=8000

# 后台运行
nohup python app.py &

访问

powershell 复制代码
http://127.0.0.1:5000

代码介绍

python 复制代码
from flask import Flask

# 创建Flask对象,传入__name__
# 作用:确定项目根路径,确定 templates 和 static 路径
app = Flask(__name__)

# 创建一个根路由,当访问 http://127.0.0.1:5000 时会访问这个路由
@app.route('/')
def index():
	# 视图函数:view function
    return 'Hello Flask 项目!'

# 如果当前文件作为项目入口文件,那么__name__ = __main__
# 打开debug模式,自定义host和port
if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)

配置管理

通过app.config来配置

python 复制代码
from flask import Flask
app = Flask(__name__)

app.config["SECRET_KEY"] = "fsagsag"

随着项目功能越来越复杂,配置项也越来越多,如果全部通过app.config,那么代码将非常冗余,这时候我们可以通过配置文件的形式来配置,比如写一个config.py,然后添加一些配置项:

python 复制代码
# config.py

SECRET_KEY = "XXXX"
SQLALHEMY_DATABASE_URI = "sqlite3://sqlite3.db"```
python 复制代码
# app.py
from flask import Flask
import config

app = Flask(__name__)

app.config.from_object(config)

定义url

无参url

无参url的定义非常简单,只需要通过@app.route即可定义,比如以下定义一个个人中心的无参url

python 复制代码
@app.route("/profile")
def profile():
    return "这是个人中心"

有参url

url上传递参数,有两种形式,我们拿到获取博客详情为例:

  • 定义为/blog/<blog_id>,那么访问的时候就是/blog/123就可以将参数blog_id=123传递给视图函数。这种形式叫做path传参
  • 定义为/blog,那么访问的时候就是/blog/?blog_id=123,也可以将参数blog_id=123传给视图函数。这种形式叫做query string传参

path传参

python 复制代码
# blog_id为str类型
@app.route("/blog/<blog_id>")
def blog_detail(blog_id):
    print(type(blog_id))
    return f"获取到的博客id为:{blog_id}"


# 将str类型转为int类型
@app.route("/blog/<int:blog_id_int>")
def blog_detail_int(blog_id_int):
    print(type(blog_id_int))
    return f"获取到的博客id为:{blog_id_int}"

# 当访问http://127.0.0.1:5000/blog/234时,会优先调用blog_detail_int视图函数
# 当没有写类型转换时,会自上而下优先调用第一个视图函数

除了int外,还有其他类型

  • string:字符串类型,默认类型
  • int:整形
  • float:浮点类型
  • path:路径。类型string,但是中间即使添加了/,也会将其当成一个整体
  • uuidUUID类型
  • any:选择其中的任何一个。例如 @app.route("/blog/list/<any(python, flask, django):category>"),那么参数category就只能是python,flask和django中的一个,否则就会出现404错误

query string传参

query string传参在参数定义时与无参数url一样,然后在视图函数中通过request.args.get("参数名")来获取参数。示例代码如下:

python 复制代码
from flask import Flask, request

# 一个参数
@app.route("/blog")
def blog_detail():
    blog_id = request.args.get("blog_id")
    print(type(blog_id))       # 默认是str类型
    return f"获取到的博客id为:{blog_id}"
# 访问 http://127.0.0.1:5000/blog?blog_id=123


# 多个参数使用&符号连接
@app.route("/blog/list")
def blog_detail_list():
    page = request.args.get("page")
    size = request.args.get("size")
    print(type(page), type(size))      # 默认是str类型
    return f"获取到的博客page为:{page},size为:{size}"
# 访问 http://127.0.0.1:5000/blog/list?page=12&size=40


# 设置默认值并传换类型
@app.route("/blog/list")
def blog_detail_list_default():
    page = request.args.get("page", 1, type=int)
    size = request.args.get("size", 12, type=int)
    print(type(page), type(size))
    return f"获取到的博客page为:{page},size为:{size}"

# 访问 http://127.0.0.1:5000/blog/list

method请求方法

在定义url的时候,不同的操作应该使用不同的方法。比如从服务器获取数据就是get请求,提交数据到服务器用post请求,修改服务器数据用put请求,从服务器上删除数据用delete请求。示例代码如下:

python 复制代码
@app.route("/blog/add", methods=['POST'])
def blog_add():
    return "使用post方法添加博客"

# 使用postman测试

除了@app.route装饰器,我们还可以使用一些快捷路由来限制请求方法。

快捷路由装饰器 描述
app.get("/login") 等价于app.route("/login", methods='GET')
app.post("/login") 等价于app.route("/login", methods='POST')
app.put("/login") 等价于app.route("/login", methods='PUT')
app.delete("/login") 等价于app.route("/login", methods='DELETE')
app.patch("/login") 等价于app.route("/login", methods='PATCH')

重定向

  • 永久重定向,301
  • 临时重定向,302

flask中,重定向通过flask.redirect(location, code=302)函数实现的。location表示需要重定向到哪个uricode表示状态码,默认是302临时重定向

python 复制代码
from flask import Flask, request, redirect


@app.route('/login')
def login():
    return "登录页面"

@app.route("/profile")
def profile():
    name = request.args.get('name')

    if not name:
        # 如果没有name,说明没有登录,重定向到登录页面
        return redirect('/login')
    else:
        return name
# 访问 http://127.0.0.1:5000/profile?name=huazi 
# 访问 http://127.0.0.1:5000/profile

Jinja2模版

flask中,渲染html通常会交给模板引擎来做,而flask中默认配套的模板引擎是Jinja2Jinja2的作者也是Flask的作者,Jinja2可以独立于Flask使用,比如被Django使用。Jinja2是一个高效,可扩展的模板引擎。

flask项目中,有一个templates文件夹,如果没有修改模板查找路径,默认会在这个文件夹下寻找模板文件。模板文件可以是任意纯文本格式的文件,比如txt,html,xml等,但是为了让项目更规范,也为了与前端开发者更无缝的协作,通常我们使用html文件来写模板代码。

基本使用

python 复制代码
from flask import Flask, request, redirect, render_template


@app.route('/')
def index():
    # 会在项目根路径下的templates下寻找index.html文件
    return render_template("index.html")

index.html模板代码如下:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>简易页面</title>
</head>
<body>
    <h1>欢迎访问页面</h1>
    <p>这是一段基础HTML代码</p>
</body>
</html>

渲染变量

html文件中,有些数据是需要从数据库中动态加载的,比如博客列表,不可能新增一篇博客就要修改html的代码,正确的做法是每次用户访问这个博客列表url时,在视图函数中就读取最新的博客数据,然后把最新的博客数据传递到模版中。这时候就涉及到在模板中怎么使用变量,比如下面渲染模板的时候,我们就会传入一个hobby参数,示例代码如下:

python 复制代码
@app.route("/variable")
def variable():
    hobby = "游戏"
    return render_template("variable.html", hobby=hobby)

variable.html如下:

python 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>变量使用</title>
</head>
<body>
    <h1>我的兴趣爱好是:{{ hobby }}</h1>
</body>
</html>

访问:http://127.0.0.1:5000/variable

也可以使用对象.属性 或者 字典.key的语法来访问对应的值。比如下面代码传给模板文件有一个user对象和一个person对象。示例代码如下:

python 复制代码
class User:
    def __init__(self, username, email):
        self.username = username
        self.email = email
        

@app.route("/variable")
def variable():
    hobby = "游戏"
    person = {
        "name": "张三",
        "age": 18
    }
    user = User("李四", "xx@qq.com")
    
    context = {
        "hobby": hobby,
        "person": person,
        "user": user
    }
    # return render_template("variable.html", hobby=hobby, person=person, user=user)
    return render_template("variable.html", **context)

控制语句

Jinja2模板中没有continuebreak语句,读者需要注意

if语句

模板中,也存在if语句python中的if语句非常的类似,可以使用>, <, >=, <=, ==, !=来判断,也可以通过and,or,not来进行逻辑操作。

python 复制代码
@app.route("/if")
def if_statement():
    age = 18
    return render_template("if.html", age=age)

这里我们定义了一个age变量,并且把这个age传给一个叫做if.html的模板。在if.html模板中,我们根据age的大小,来判断是否成年。if.html的代码如下:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>if语句</title>
</head>
<body>
    {% if age > 18 %}
        <div>您已经成年了</div>
    {% elif age < 18 %}
        <div>您未成年</div>
    {% else %}
        <div>您刚成年</div>
    {% endif %}
</body>
</html>

上诉代码中,if结束后必须根一个endif语句,另外在模板中的缩紧并不是必须的,只是为了代码阅读性更强

for语句

Jinja2中的for循环python中的for循环也是非常类似的,只是比python中的for循环多一个endfor代码块

python 复制代码
@app.route("/for")
def for_statement():
    books = [
        {"name": "三国演义", "author": "罗贯中", "price": 100},
        {"name": "水浒传", "author": "施耐庵", "price": 99},
        {"name": "红楼梦", "author": "曹雪芹", "price": 101},
        {"name": "西游记", "author": "吴承恩", "price": 102}
    ]
    return render_template("for.html",books=books)
html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>for语句</title>
</head>
<body>
    <table>
        <thead>
            <tr>
                <th>书名</th>
                <th>作者</th>
                <th>价格</th>
            </tr>
        </thead>
        <tbody>
            {% for book in books %}
            <tr>
                <td>{{ book.name }}</td>
                <td>{{ book.author }}</td>
                <td>{{ book.price }}</td>
            </tr>
            {% endfor %}
        </tbody>
    </table>
</body>
</html>

模版继承

一个网站中,大部分网页的模块是重复的,比如顶部的导航栏,底部的备案信息。如果在每个页面中都重复的去写这些代码,会让项目变得臃肿,提高后期维护成本。

比较好的做法是,通过模板继承,把一些重复性的代码写在父模板中,子模板继承父模板后,再分别实现自己页面的代码。我们首先来看一个父模板base.html的例子。

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}{% endblock %} | 华子</title>
    {% block head %}{% endblock %}
</head>
<body>
<nav>
    <ul>
        <li><a href="#">首页</a></li>
        <li><a href="#">发布</a></li>
    </ul>
</nav>

<main>
    {% block main %}{% endblock %}
</main>

<footer>
    Copyright 2008 by <a href="#">you</a>
</footer>
</body>
</html>

以上父模板中,编写好网页的整体结构,并且把所有子模板都需要用到的样式文件base.css也提前引用好,然后针对子模板需要重写的地方,则定义成block。比如以上定义的title,head,body,footer这几个block,子模板仔继承了父模板后,重写对应block的代码,即可完成子模板的渲染。这里我们用继承base.html的方式,实现一个list.html文件和detail.html,代码如下:

  • list.html
html 复制代码
{% extends "base/base.html" %}
{% block title %}列表页{% endblock %}

{% block head %}
    <style>
        body{
            background: antiquewhite;
        }
    </style>
{% endblock %}

{% block main %}
    <h1>这是华子列表页</h1>
{% endblock %}
  • detail.html
html 复制代码
{% extends "base/base.html" %}
{% block title %}详情页{% endblock %}

{% block head %}
    <style>
        body{
            background: cadetblue;
        }
    </style>
{% endblock %}

{% block main %}
    <h1>这是文章详情页</h1>
{% endblock %}

首先,我们通过 extends 语法,加载父模板,因为 base.htmllist.html、detail.html 是不在同一级目录,所以直接写 "base/base.html"。这里需要注意的是,extends 必须出现在子模板所有代码的最前面。接下来分别实现了 title、head、content 这三个 block,实现的 block 中的代码,将会被自动填充到父模板指定的位置,并且最终会生成一个完整 HTML 结构的 list.html、detail.html 文件。

python 复制代码
@app.route("/list")
def article_list():
    return render_template("base/list.html")

@app.route("/detail")
def article_detail():
    return render_template("base/detail.html")

加载静态文件

一个网页中,除了 HTML 代码以外,还需要 CSS、JavaScript 和图片文件才能更加美观和实用。静态文件默认是存放到当前项目的 static 文件夹中。在模板文件中,可以通过 url_for 加载静态文件,示例代码如下:

  • static.html
html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <!-- <link rel="stylesheet" href="/static/css/mystatic.css"> -->
    <link rel="stylesheet" href="{{ url_for('static', filename='css/mystatic.css') }}">
    <title>静态文件加载</title>
</head>
<body>
    <h1 class="title">静态文件加载</h1>
</body>
</html>
  • mystatic.css
html 复制代码
.title{
    background: red;
}
python 复制代码
@app.route("/static")
def template_static():
    return render_template("static.html")

python操作mysql驱动

Flask 想要操作数据库,必须要先安装 Python 操作 MySQL 的驱动。在 Python 中,目前有以下 MySQL 驱动包。

  • mysqlclient:是目前为止执行速度最快的驱动,请通过命令 pip install mysqlclient 安装,而不要在 PyCharm 中安装,否则很容易出错。
  • pymysql:纯 Python 实现的一个驱动。因为是纯 Python 编写的,因此执行效率不如 mysqlclient。也正因为是纯 Python 写的,因此可以和 Python 代码无缝衔接。
  • mysql-connector-python:MySQL 官方推出的纯 Python 连接 MySQL 的驱动,执行效率比 pymysql 还慢。

这里我们用 mysqlclient 作为驱动程序。

shell 复制代码
pip install mysqlclient

flask-SQLAIchemy

Flask 中,我们很少会使用驱动程序(比如 mysqlclient)直接写原生 SQL 语句去操作数据库,更多的是通过 SQLAlchemy 提供的 ORM 技术,类似于操作普通 Python对象一样实现数据库的增删改查操作,而 Flask-SQLAlchemy 是对 SQLAlchemy 的一个封装,使得在 Flask 中使用 SQLAlchemy 更加方便。 Flask-SQLAlchemy 是需要单独安装,因为 Flask-SQLAlchemy 依赖 SQLAlchemy,所以只要安装了 Flask-SQLAlchemySQLAlchemy 会自动安装。安装命令如下。

shell 复制代码
pip install flask-sqlalchemy

SQLAlchemy 类似于 Jinja2,是可以独立于 Flask 而被使用的,完全可以在任何 Python 程序中被使用。SQLAlchemy 的功能非常强大,本课件不可能全部都讲到。读者如果有兴趣,可以在学完本章后阅读 SQLAlchemy 的官方文档,链接为:https://www.sqlalchemy.org/

flask-SQLAIchemy基本使用

连接mysql

使用 Flask-SQLAlchemy 操作数据库之前,要先创建一个由 Flask-SQLAlchemy 提供的 SQLAlchemy 类的对象。在创建这个类的时候,要传入当前的 app。然后还需要在 app.config 中设置 SQLALCHEMY_DATABASE_URI,来配置数据库的连接,示例代码如下。

python 复制代码
from flask import Flask, request, redirect, render_template
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import text


app = Flask(__name__)

HOSTNAME = "127.0.0.1"
PORT = 3306
USERNAME = "root"
PASSWORD = "123456"
DATABASE = "db2"

# 如果驱动程序是mysqlclient,那么以下前缀就是:mysql+mysqldb
# 如果驱动程序是pymysql,那么以下前缀就是:mysql+pymysql
app.config['SQLALCHEMY_DATABASE_URI'] = f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False


db = SQLAlchemy(app)

with app.app_context():
    # 测试是否连接成功
    with db.engine.connect() as conn:
        rs = conn.execute(text("select 1"))
        print("测试结果:", rs.fetchone()[0])。 # 测试结果为1表示连接成功

ORM模型

ORM介绍

ORM(Object Relationship Mapping),对象关系映射,是一种可以用Python面向对象的方式来操作关系型数据库的技术。具有可以映射到数据库表能力的Python类我们称之为ORM模型,一个ORM模型与数据库中一个表相对应,ORM模型中的每个类属性分别对应表的每个字段,ORM模型的每个实例对象对应表中每条记录。ORM技术提供了面向对象与SQL交互的桥梁,让开发者用面向对象的方式操作数据库,使用ORM模型具有以下优势。

  • 开发效率高:几乎不需要写原生SQL语句,使用纯Python的方式操作数据库,大大的提高了开发效率。
  • 安全性高:ORM模型底层代码对一些常见的安全问题,比如SQL注入做了防护,比直接使用SQL语句更加安全。
  • 灵活性强:Flask-SQLAlchemy底层支持SQLite、MySQL、Oracle、PostgreSQL等关系型数据库,但针对不同的数据库,ORM模型代码几乎一模一样,只需修改少量代码,即可完成底层数据库的更换。

定义ORM模型

以下我们用Flask-SQLALchemy来创建一个User模型,示例代码如下:

python 复制代码
from flask import Flask, request, redirect, render_template
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import text
import config
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy import MetaData, Integer, String

app = Flask(__name__)


app.config.from_object(config)

# 定义命名约束的Base类
class Base(DeclarativeBase):
    metadata = MetaData(naming_convention={
        # ix: index,索引。
        "ix": 'ix_%(column_0_label)s',
        # un: unique,唯一约束
        "uq": "uq_%(table_name)s_%(column_0_name)s",
        # ck: Check,检查约束
        "ck": "ck_%(table_name)s_%(constraint_name)s",
        # fk: Foreign Key,外键约束
        "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
        # pk: Primary Key,主键约束
        "pk": "pk_%(table_name)s"
    })

db = SQLAlchemy(app=app, model_class=Base)

class User(db.Model):
    __tablename__ = "user"
    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    username: Mapped[str] = mapped_column(String(50), nullable=False)
    password: Mapped[str] = mapped_column(String(200))

with app.app_context():
    db.create_all()
python 复制代码
HOSTNAME = "127.0.0.1"
PORT = 3306
USERNAME = "root"
PASSWORD = "123456"
DATABASE = "db2"

# 如果驱动程序是mysqlclient,那么以下前缀就是:mysql+mysqldb
# 如果驱动程序是pymysql,那么以下前缀就是:mysql+pymysql
SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"
SQLALCHEMY_TRACK_MODIFICATIONS = False

上述代码中,字典 naming_convention 是一个固定的写法,主要是用来给表约束做一些命名约定的,使得后期 alembic 在生成迁移脚本时,生成的约束名不是随机的,而是有命名规范的。

User 模型中,我们使用 Mapped[类型名] 语法来让开发者和 IDE 识别该属性的类型,为开发提供便捷性;另外,凡是使用了 mapped_column 创建的属性都将被映射到表中成为字段,并且该字段有什么配置,都可以在 mapped_column 中添加相关参数,比如字段类型(Integer)、是否可以为空(String(50))、是否为主键(primary_key=True)、是否自增(autoincrement=True)等。

之后,我们调用 db.create_all() 方法,就会将该模型迁移到数据库中生成一张表,这种方式在字段发生改变时无法自动同步到数据库中,所以仅作为一种临时解决方案,后续会使用 flask-migrate 来实现迁移。

常用字段类型和mapped_column参数

字段类型

上述 User 模型中,我们使用了 db.Integerdb.String,除了这两种数据类型外,还有以下数据类型:

类型 描述
Integer 整形。范围与数据库一致。
SmallInteger 小整形。范围与数据库一致。
BigInteger 长整形。范围与数据库一致。
Decimal 定点类型。可以指定总长度和小数点后位数。
Boolean 布尔类型。
Date 日期类型。存储Python中的datetime.date对象。
DateTime 日期时间类型。存储Python中的datetime.datetime对象。
Time 时间类型。存储Python中的datetime.time对象。
Interval 时间间隔。存储Python中的datetime.timedelta对象。
String 字符串类型。使用时需要指定长度。
Text 文本类型。常用于字符串长度不可控的情况。
Enum 枚举类型。
PickleType 存储经过Pickle后的对象。
LargeBinary 存储二进制数据。
JSON 存储JSON类型的数据。

还有很多其他的数据类型,读者可以在PyCharm中导入 from sqlalchemy import String,然后按 Ctrl+鼠标左键 进入项目源代码中查看到更多的类型。

mapped_column参数

另外,mapped_column 方法有以下常用参数:

参数 描述
name 字段在数据库表中的名称。如果没有设置,则使用此属性名作为字段名称。
type_ 字段类型。
autoincrement 自动增长。
default 默认值。
index 如果设置为True,则将此字段设置为索引。
nullable 是否为空。
onupdate 在修改对象的时候,会自动使用这个属性指定的值。
primary_key 主键。
unique 如果设置为True,则此字段的值必须唯一。
comment 在创建表时的注释。

模型迁移

Flask-Migrate介绍

到目前为止,我们定义好模型后,是通过 db.create_all() 的形式将 ORM 模型映射到数据库中的,这种方式非常局限,他只能识别到新增了模型后映射到数据库中,对于模型中字段的修改,类型的修改,他无法识别到。因此在实际开发中,都不会使用 db.create_all 来做 ORM 模型迁移,而是借助到一个第三方插件 Flask-Migrate 来实现。Flask-Migrate 是基于 alembic 实现的,alembic 是专门用来做给 SQLAlchemy 的 ORM 模型做迁移的。要使用 Flask-Migrate,我们首先需要通过 pip 安装。

bash 复制代码
pip install flask-migrate

alembic会随着flask-migrate安装而安装。在完成flask-migrate安装后,来讲解一下如何使用。

1、创建迁移对象

使用 Flask-Migrate 实现模型迁移,需要通过类 Migrate 来实现。示例代码

python 复制代码
from flask import Flask, request, redirect, render_template
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import text
import config
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy import MetaData, Integer, String
from flask_migrate import Migrate

app = Flask(__name__)


app.config.from_object(config)
........
db = SQLAlchemy(app=app, model_class=Base)
migrate = Migrate(app, db)

上述代码中,我们使用了 flask_migrate 中的 Migrate 类,使用该类创建对象时传入了 appdb

2、初始化迁移环境

在创建完迁移对象后,我们需要初始化一下迁移环境。方法是在当前项目的根路径下执行命令创建迁移环境。

相关推荐
cup1121 小时前
[开源] Meta Assistant / 告别命令行,我为一堆 Python 脚本做了一个 Windows 任务栏的“家”
windows·python·工具·nuitka·脚本运行
晨曦中的暮雨21 小时前
Golang速通(Javaer版)
java·开发语言·后端·golang
小小编程路21 小时前
Python 还有容器类型互转、进制转换、字符编码转换
开发语言·windows·python
qeen871 天前
【C++】类与对象之类的默认成员函数(二)
android·c语言·开发语言·c++·笔记·学习
CRMEB系统商城1 天前
CRMEB多商户系统(Java)v2.3公测版发布
java·开发语言·人工智能·小程序·开源·php
Samooyou1 天前
RAG项目案例--02在线检索&过滤流水线
人工智能·python·ai·全文检索·检索
动能小子ohhh1 天前
DocForge平台的设计与开发--文件上传接口的实现
开发语言·人工智能·python·langchain·ocr·fastapi
满天星83035771 天前
【Qt】信号和槽(二) (自定义信号和槽)
开发语言·数据库·qt
ab_dg_dp1 天前
Android 17+ 提取 AIDL 生成 Java 文件的实用脚本
android·java·python
超哥--1 天前
B站视频内容智能分析系统(三):B站视频自动采集
java·开发语言·音视频·ai编程