框架第六课---ORM执行SQL语句,神奇的双下划线查询,ORM外键字段的创建,外键字段数据的增删改查,多表查询(基于对象的跨表查询、基于双下划线的跨表查询)
昨日内容回顾
- 模板语法之标签
1.if判断
2.for循环
3.with语法
ps:针对容器类型的数据获取内部数据值统一采用句点符
- 自定义相关功能
'''
1.在应用下创建一个templatetags目录
2.在上述目录下创建任意名称的py文件
3.在上述py文件内先编写两行固定的代码
from django import template
register = template.Library()
html文件上需要提前加载才可以使用
{% load py文件名 %}
过滤器
标签
inclusion_tag
'''
1.过滤器(数据|过滤器名:参数)
@register.filter(name='过滤器名称')
def func(a, b):return a + b
2.标签
@register.simple_tag(name='标签名')
def index(*args):return 123
3.inclusion_tag
@register.inclustion_tag(file_name='html文件名',name='名称')
def foo(*args):return locals()
- 模板的继承与导入
1.模板的继承
模板上划定将来可以修改的区域
block 区域名称
子板上通过申明区域名称修改内容
{% extends '模板名称' %}
block 区域名称
block.super
ps:模板中至少应该有三个区域(css区域、内容区域、js区域)
2.模板的导入
{% include '局部html文件' %}
- ORM常用关键字
1.django自带的sqlite3特性
2.数据库迁移命令
3.模型层测试环境的搭建
4.如何查看ORM底层的SQL语句
queryset对象.query
配置文件固定日志输出
-------------------------------------------------
4.常用关键字
filter() 筛选数据 括号内支持填写多个默认and关系 queryset[对象,]
get() 筛选数据 括号内支持填写多个默认and关系 对象 易报错
first() 获取结果集的第一个
last() 获取结果集的最后一个
all() 获取所有数据 queryset[对象,]
create() 插入数据 返回值是当前被插入的数据对象
update() 批量更新数据
delete() 批量删除数据
values() 获取指定字段对应的数据值 queryset [{},{},{}]
values_list() 获取指定字段对应的数据值 queryset [(),(),()]
count() 统计结果集数据个数
distinct() 一定要是一模一样的数据(数据对象如果含有主键肯定不一样)
order_by() 排序(默认是升序 可以改降序)
exclude() 取反操作
reverse() 数据集结果的颠倒(必须有序)
exists() 判断数据集是否有结果 返回布尔值
-----------------------------------------
filter补充
book_obj = models.Book.objects.filter(pk=1).first()
filter() 括号里面可以放一个具体的条件(表里面的字段名=具体的数据)比如pk=1
也可以(模型层里面的类里面的字段名=对象),比如
book_obj = models.Book.objects.filter(publish=publish_obj)
意思就是就是查询属于该出版社对象的书对象!!!
注意表里面的字段名与模型层类里面的字段名有区别的!!!
外键字段表里面会自动在模型层里面的字段名的基础上再加一个_id
所以如果filter括号里面的条件是一个具体的数据,那么等号前面一定只能写表里面的字段名!!!
如果条件是一个对象,那么等号前面一定只能写模型层里面类里面的字段名!!!
.
.
.
今日内容概要
- ORM执行SQL语句
- 神奇的双下划线查询
- ORM外键字段的创建
- 外键字段数据的增删改查
- 多表查询(基于对象的跨表查询、基于双下划线的跨表查询)
今日内容详细
ORM执行SQL语句
有时候ORM的操作效率可能偏低 我们是可以自己编写SQL的
----------------------------------------
方式1:
res = models.User.objects.raw('sql语句')
res = models.User.objects.raw('select * from app01_user;')
print(list(res))
用这个方法的时候select name from app01_user; 这样会报错!!
必须select后面的字段名必须要跟主键才行
select id,name from app01_user;
-----------------------------------------
-----------------------------------------
方式2:(类似于用pymysql模块连接数据库,查数据库)
from django.db import connection
cursor = connection.cursor()
cursor.execute('select name from app01_user;')
print(cursor.fetchall())
----------------------------------------
.
.
.
神奇的双下划线查询
'''
只要还是queryset对象,就可以无限制的点queryset对象的方法!!!
queryset.filter().values().filter().values_list().filter()...
'''
查询年龄大于18的用户数据
ORM不支持>号 age__gt=28 就是年龄大于28的意思
# res = models.User.objects.filter(age__gt=28)
# res = models.User.objects.filter(age__gt=28).values('name','age')
# print(res)
-----------------------------------------
查询年龄小于38的用户数据
# res = models.User.objects.filter(age__lt=38)
# print(res)
-----------------------------------------
大于等于__gte 小于等于__lte equal 等于
# res = models.User.objects.filter(age__gte=18)
# res = models.User.objects.filter(age__lte=38)
-----------------------------------------
-----------------------------------------
查询年龄是18或者28或者38的数据 __in=() 成员运算
# res = models.User.objects.filter(age__in=(18, 28, 38))
# print(res)
-----------------------------------------
-----------------------------------------
查询年龄在28到58范围之内的数据 包含28与58 between 28 and 58
# res = models.User.objects.filter(age__range=(28, 58))
# print(res)
-----------------------------------------
-----------------------------------------
查询名字中含有字母j的数据 像sql的like模糊查询
# res = models.User.objects.filter(name__contains='j') 有大小写区分
# res = models.User.objects.filter(name__icontains='j') # 不区分大小写
-----------------------------------------
查询注册年份是2022年的数据 __year=2022
res = models.User.objects.filter(register_time__year=2022)
print(res)
-----------------------------------------
'''针对django框架的时区问题 是需要配置文件中修改的 后续bbs讲解'''
.
.
.
.
ORM外键字段的创建
'''
复习MySQL外键关系的判断:关系的判断可以采用换位思考原则
一对多
外键字段建在多的一方!!!
----------------------------------------
多对多
外键字段统一建在第三张关系表!!!
-----------------------------------------
一对一
建在任何一方都可以 但是建议建在查询频率较高的表中!!!
------------------------------------------
'''
.
1.创建基础表(书籍表、出版社表、作者表、作者详情)
------------------------------------------
判断书籍表与出版社表的关系:一本书不能对应多个出版社,一个出版社可以对应多本书,
所以是一对多的关系,所以外键建在多的一方,书表里面!!
------
判断书籍表与作者表的关系:一本书可以对应多个作者,一个作者可以对应多个书,所以是多对多的关系,
在sql里面多对多需要单独建一个第三张表,但是在ORM里面,外键字段可以直接建在某张查询频率较高的表中。ORM内部会自动帮你创建第三张关系表。书表的查询频率较高,所以多对多的外键建在书表比较合适!!
------
作者表语作者详情表的关系:一对一的关系,所以外键建在作者表里面
.
.
.
2.确定外键关系:
一对多 ORM与MySQL一致 外键字段建在多的一方
多对多 ORM比MySQL有更多变化
1.外键字段可以直接建在某张表中(查询频率较高的)
内部会自动帮你创建第三张关系表
2.自己创建第三张关系表并创建外键字段
详情后续讲解
一对一 ORM与MySQL一致 外键字段建在查询较高的一方!!!
------------------------------------------
.
3.ORM创建
针对一对多和一对一同步到表中之后会自动加_id的后缀!!!!!
一对多外键:
publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)
一对一外键:
author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)
---------------------------------------------
针对多对多 不会在表中有展示!!! 而是创建第三张表!!!
authors = models.ManyToManyField(to='Author')
------------------------------------------
.
.
.
.
外键字段相关操作 巨重要巨重要!!!!!!!!!!!
--------------------------------------------
第一种:
针对一对多 插入数据可以直接填写表中的实际字段
models.Book.objects.create(title='三国演义', price=888.88, publish_id=1)
models.Book.objects.create(title='人性的弱点', price=777.55, publish_id=1)
---------------------------------------------
第二种:
针对一对多 插入数据也可以填写表中的类中字段名
publish_obj = models.Publish.objects.filter(pk=1).first()
models.Book.objects.create(title='水浒传', price=555.66, publish=publish_obj)
给当前这张表里面,添加数据,用这个方法是用的最多的!!!
------------------------------------------
'''一对一与一对多 一致'''
------------------------------------------
.
.
.
.
.
针对一对多 插入数据可以直接填写表中的实际字段
# 针对一对多 插入数据可以直接填写表中的实际字段
book_obj = models.Book.objects.create(title='水浒传', price=888.11, publish_id=1)
# 直接添加数据需要指定表中的字段,外键字段会自动加_id所以在添加的时候字段名字为publish_id=1
print(book_obj)
book_obj = models.Book.objects.create(title='三国演义', price=666.88, publish_id=1)
print(book_obj)
book_obj = models.Book.objects.create(title='斗罗大陆', price=8888.88, publish_id=2)
print(book_obj)
book_obj = models.Book.objects.create(title='斗破苍穹', price=6666.66, publish_id=3)
print(book_obj)
book_obj = models.Book.objects.create(title='三体', price=555.89, publish_id=4)
print(book_obj)
# 针对一对多 插入数据也可以填写表中的类中字段名
publish_obj = models.Publsh.objects.filter(pk=1).first()
models.Book.objects.create(title='金瓶', price=99999.99, publish=publish_obj)
## 使用对象进行数据插入要使用类中的字段名进行添加
.
.
.
.
.
.
针对一对一与一对多一致,既可以传数字也可以传对象
models.Author.objects.create(name='jason', age=18, authorDetail_id=1)
# 直接添加数据需要指定表中的字段,外键字段会自动加_id所以在添加的时候字段名字为authorDetail_id=1
models.Author.objects.create(name='tom', age=28, authorDetail_id=2)
models.Author.objects.create(name='张三', age=58, authorDetail_id=4)
authordetail_obj = models.AuthorDetail.objects.filter(pk=3).first()
models.Author.objects.create(name='kunkun', age=38, authorDetail=authordetail_obj)
## 使用对象进行数据插入要使用类中的字段名authorDetail进行添加
## 一对一数据修改
author_qeury.update(name=name,age=age)
aud = author_qeury.first().authorDetail
aud.addr=addr
aud.phone=phone
aud.email=email
aud.save()
.
.
.
.
.
.
注意!!!!!
注意当往表里面插入数据的时候,尤其是外键字段要注意,模型类生成的表里面外键字段会自动加个后缀_id
所以如果等于号前面是表中的实际字段,那等于号后面就要写一个具体的数数据!!!
如果等于号前面是模型表中的字段名(也就是没自动加_id前的样子),那等于号后面就要写一个对应的对象!!!
注意针对一对多与一对一的外键里面的级联删除on_delete=models.CASCADE 是有区别的
当两表一对一关联的时候,删除两表的其中的任意一条数据,都会对应的删除关联表里面的对应数据
当两表一对多关联的时候,删除多的那张表里面的一条数据,问题不大,
但是一旦删除了一的那张表里面的数据,
对应的多的表里面的所有关联数据全部都自动删掉了,有点危险!!!
比如书表与出版社表,建立级联删除后,删除出版社里面的一条数据,
书表里面所有关联该出版社的书数据全部自动被删了!!!!!!!
.
.
.
.
.
.
.
针对多对多关系绑定:
既可以传数字也可以传对象
注意:当对象点虚拟的外键字段名的时候,比如书籍对象点虚拟外键字段authors 时:
如果如果后面跟的是 add set remove clear 则是操作第三张虚拟关系表!!!
当你使用其他方式 比如 all filter 等的时候则是操作的是 对应的作者表Author!!!
注意区别:只有对象点字段名后跟的是add set remove clear 才会跳到对应的那张虚拟表去!!
对象点一个一对多或者一对一的外键字段时,直接拿到的是该对象对应的关联表里的对象了,
所以可以继续点关联表里面的字段
但是对象点一个多对多的外键字段时,并不能拿到对应关联表里面的对象,
还要点.all() 才能拿到QuerySet对象
该QuerySet里面包含该对象对应的关联表里面所有的对象,
所以点完all()后,还是不能直接点关联表里面的字段名!!!!!!
--------------------------------
# 增加数据
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.add(1)
book_obj.authors.add(4,3)
book_obj = models.Book.objects.filter(pk=2).first()
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.add(author_obj1, author_obj2)
# 修改数据
book_obj = models.Book.objects.filter(pk=4).first()
book_obj.authors.set((1, 3))
book_obj = models.Book.objects.filter(pk=4).first()
author_obj = models.Author.objects.filter(pk=3).first()
book_obj.authors.set([author_obj, ])
# 删除数据
book_obj = models.Book.objects.filter(pk=3).first()
# book_obj.authors.remove(3)
# 与下面同理
author_obj = models.Author.objects.filter(pk=3).first()
book_obj.authors.remove(author_obj)
# 清空当前数据对象的关系
bokk_obj.authors.clear()
add()/remove() 多个位置参数(数字,对象)
set() 可迭代对象(元组 列表)数字 对象
clear() 清空当前数据对象的关系
.
.
.
.
.
.
.
.
多对多关系,给第三张表里面添加数据关系add( )
add括号里面可以直接写要绑定表里面的主键数据
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.add(1) # 在第三张关系表中给当前书籍绑定id为1作者
book_obj.authors.add(2, 3)
# 在第三张关系表中,给当前这书绑定id为2,id为3 的作者
add括号里面也可以直接写要绑定表里面的数据对象!!!
book_obj = models.Book.objects.filter(pk=3).first()
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=2).first()
book_obj.authors.add(author_obj1)
# add()括号里面写要绑定表里面的数据对象,也能自动根据数据对象拿到主键值!!!
book_obj.authors.add(author_obj1, author_obj2)
针对多对多关系绑定,先找到虚拟外键在那张表,从那个表开始
这里我的多对多的外键字段名authors 在模型表里设计成了author了,
所以后面都点的书籍对象author外键字段了
.
.
add括号里面也可以直接写要绑定表里面的数据对象!!!
add()括号里面写要绑定表里面的数据对象,也能自动根据数据对象拿到主键值!!!
.
主键为1书对象与作者的原来关系1对2,5,6,7变为 :
主键为1书对象绑定了一个主键为1的作者对象和一个主键为5的作者对象
.
.
.
.
.
.
.
.
多对多关系,给第三张表里面数据关系修改set(( ))
# 可以在set括号里面填写关联表里面的主键值:
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.set((1, 3)) # 修改关系
book_obj.authors.set([2, ]) # 修改关系
-----------------------
# 也可以在set括号里面填写关联表里面的数据对象:
book_obj = models.Book.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=2).first()
book_obj.authors.set((author_obj1,)) # 修改关系 b-1对a-1
book_obj.authors.set((author_obj1, author_obj2))
# 主键为1书对象与作者的原来关系变为 :
# book_id为1 绑定了author_id 1与2
------------------------------------------
------------------------------------------
# 多对多的第三张表里面数据关系删除:
book_obj.authors.remove(2) # 当前这本书与主键为2的作者关系删掉
book_obj.authors.remove(1, 3)
book_obj.authors.remove(author_obj1,)
book_obj.authors.remove(author_obj1,author_obj2)
book_obj.authors.clear()
# 当前这本书与所有的作者关系删掉,
# 也就是第三张表里面清掉该书的id与其他作者的对应关系
add()\remove() 多个位置参数(数字 对象)
set() 可迭代对象(元组 列表) 数字 对象
clear() 清空当前数据对象的关系
-----------------------------------------------
.
.
.
.
.
.
.
.
.
.
ORM跨表查询
"""
复习MySQL跨表查询的思路
子查询
分步操作:将一条SQL语句用括号括起来当做另外一条SQL语句的条件
连表操作
先整合多张表之后基于单表查询即可
inner join 内连接
left join 左连接
right join 右连接
"""
------------------------------------------------
正反向查询的概念(重要!!!)
正向查询:由外键字段所在的表数据查询关联的表数据 正向查询
谁手上有外键字段,查别人就是正向查询!!!
反向查询:没有外键字段的表数据查询关联的表数据 反向查询
谁手上没有外键字段,查别人就是反向查询!!!
ps:正反向的核心就看外键字段在不在当前数据所在的表中
--------------------------------------------------
ORM跨表查询的口诀(极其重要!!!)
正向查询按外键字段名
反向查询按表名小写加_set
.
.
.
ORM的跨表查询分两种,
一种是基于对象的跨表查询,通过点的方式
正向查询按外键字段名
反向查询按表名小写加_set
---------------------------------------------------
一种是基于连表的跨表查询,通过__杠杠的方式
正向查询按外键字段名
反向查询按表名小写(没有_set!!!) 别搞混了!!!
.
.
.
.
基于对象的正向跨表查询(等价于sql里面的子查询!!)
对象无论是正向点外键字段还是反向点表名小写拿到的都是关联的表里面的对应的对象
对应的对象还可以继续正反向点拿到它相关联的表里面对应的对象
只要对象就可以点!!!
正向查询按外键字段名:
1.查询主键为1的书籍对应的出版社名称 正向查询
# 先根据条件获取数据对象
book_obj = models.Book.objects.filter(pk=1).first()
# 再判断正反向的概念 由书查出版社
# 外键字段在书所在的表中 所以是正向查询
print(book_obj.publish.name)
book_obj.publish 的结果是书对象对应的出版社对象!!!!
书籍对象一点(一对多)外键字段就已经拿到了对应的出版社对象了!!!
----------------------------------------------
.
2.查询主键为4的书籍对应的作者姓名 正向查询
# 先根据条件获取数据对象
book_obj = models.Book.objects.filter(pk=4).first()
# 再判断正反向的概念 由书查作者
# 外键字段在书所在的表中 所以是正向查询
print(book_obj.authors) # app01.Author.None
print(book_obj.authors.all()) # QuerySet[作者对象1,作者对象2]
print(book_obj.authors.all().values('name'))
注意书籍对象点(多对多)外键字段还不够,还要点all() 才能拿到一个包含书对应的作者对象的Queryset,想要拿到每一个书对应的作者对象还要对这个Queryset进行for循环!!!
-------------------------------------------------
3.查询jason的电话号码 正向查询
author_obj = models.Author.objects.filter(name='jason').first()
print(author_obj.author_detail.phone)
-------------------------------------------------
.
.
.
.
.
基于对象的反向跨表查询(等价于sql里面的子查询!!)
反向查询按表名小写:
4.查询北方出版社出版过的书籍 # 反向查询
publish_obj = models.Publish.objects.filter(name='北方出版社').first()
print(publish_obj.book) # 反向查询直接点表名小写,会报错!!!
print(publish_obj.book_set) # app01.Book.None
print(publish_obj.book_set.all()) # Queryset[书对象1,书对象2,]
# 当结果可能是多个的情况下,反向查询,比如由一找多就要在多的表名后面加_set
--------------------------------------------------
5.查询jason写过的书籍 # 反向查询
author_obj = models.Author.objects.filter(name='jason').first()
print(author_obj.book_set) # app01.Book.None
print(author_obj.book_set.all()) # Queryset[书对象1,书对象2,]
# 当结果可能是多个的情况下,反向查询,由一找多就要在多的表名后面加_set
--------------------------------------------------
6.查询电话号码是110的作者姓名 # 反向查询
author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first()
print(author_detail_obj.author)
print(author_detail_obj.author.name)
# 当结果可能是一个的情况下,比如详情表与作者表是一对一的关系,
# 由一找一就不要在要查的表名后面加_set !!!
--------------------------------------------------
.
.
.
.
.
.
.
.
上面的基于对象的跨表查询,是先要拿到对象,然后通过对象去正反向查询,拿关联表里面的对象
下面的基于双下划线的跨表查询,拿到的是对象对应的具体的字段里的具体数据,拿不到对象了
基于双下划线的跨表查询(等价于sql里面的连表操作),只能用在values与filter括号里面。
--------------------------------------------------
values括号里面,如果写了外键字段,就表示要正向连表了,
外键字段后面通过__正向关连表里的字段名,就能拿到对应的关联表里面的字段数据了
values括号里面,如果写了小写的表名,就表示要反向连表了,
小写表名后面通过__反向关连表里的字段名,就能拿到对应的反向表里的字段数据了!!!
--------------------------------------------------
'''基于双下划线的跨表查询'''
1.查询主键为1的书籍对应的出版社名称 # 正向查询
res = models.Book.objects.filter(pk=1).values('publish__name','title')
print(res) # 结果是个queryset列表里面套了一个字典,对应value里面的字段信息
res = models.Book.objects.filter(pk=1).values('publish__name','title').first()
print(res) # 就直接是个字典了
values()括号里面就是要写字段名,可以写自己表里面的字段名,也可以写关联表里面的字段名!!
通过在书表里面的外键字段publish,拿关联表里面的对于name字段的数据
# 而且要注意最后字典里面的键是'publish__name' values里面写啥,字典里键就是啥!!!
--------------------------------------------------
2.查询主键为4的书籍对应的作者姓名 # 正向查询
res = models.Book.objects.filter(pk=4).values('title','authors__name')
print(res)
--------------------------------------------------
3.查询jason的电话号码 # 正向查询
res = models.Author.objects.filter(name='jason').values('author_detail__phone')
print(res)
--------------------------------------------------
.
主键为4的书籍对应的作者有多个,所以queryset列表里面,有多个字典
.
.
.
.
.
.
.
反向查询表名小写:Book表面小写为book
4.查询北方出版社出版过的书籍名称和价格 # 反向查询
res = models.Publish.objects.filter(name='北方出版社').values
('book__title','book__price','name')
print(res)
--------------------------------------------------
5.查询jason写过的书籍名称 # 反向查询
res = models.Author.objects.filter(name='jason').values
('book__title', 'name')
print(res)
--------------------------------------------------
6.查询电话号码是110的作者姓名 # 反向查询
res = models.AuthorDetail.objects.filter(phone=110).values('phone', 'author__name')
print(res)
--------------------------------------------------
.
.
.
.
.
.
进阶操作
需求不能用models先点第一个要查的表名!!!
1.查询主键为1的书籍对应的出版社名称
res = models.Publish.objects.filter(book__pk=1).values('name')
查询出版了主键为1的书籍的出版社
print(res)
-----------------------------------------------
2.查询主键为4的书籍对应的作者姓名
res = models.Author.objects.filter(book__pk=4).values('name','book__title')
print(res)
-----------------------------------------------
3.查询jason的电话号码
res = models.AuthorDetail.objects.filter(author__name='jason').values('phone')
print(res)
-----------------------------------------------
4.查询北方出版社出版过的书籍名称和价格
res = models.Book.objects.filter(publish__name='北方出版社').values('title','price')
print(res)
-----------------------------------------------
5.查询jason写过的书籍名称
res = models.Book.objects.filter(authors__name='jason').values('title')
print(res)
-----------------------------------------------
6.查询电话号码是110的作者姓名
res = models.Author.objects.filter(author_detail__phone=110).values('name')
print(res)
-----------------------------------------------
.
补充,连续性的跨表!!!
查询主键为4的书籍对应的作者的电话号码 三种方法
正用:(通过外键字段与双下方法从Book表跨到作者表,再跨到作者详情表拿到里面的phone字段)
res = models.Book.objects.filter(pk=4).values('authors__author_detail__phone')
print(res)
---------------------------------------------
反用:(通过表名小写与双下方法从作者详情表,跨到作者表,再跨到Book表拿里面的pk字段)
res = models.AuthorDetail.objects.filter(author__book__pk=4).values('phone')
print(res)
---------------------------------------------
从中间开始:
从作者表开始,先通过filter里面表名小写与双下方法跨到Book表拿里面的pk字段,筛选一下
再通过values里面外键字段与双下方法从作者表跨到作者详情表拿到里面的phone字段
res = models.Author.objects.filter(book__pk=4).values('author_detail__phone')
print(res)
"""
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY