Django入门到放弃之ORM多表操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | 1 图书表:book,作者表:author,作者详情表:authordetail,出版社表:publish,(第三张中间表) 2 作者跟作者详情:是一对一,关联字段写在哪一方都可以 3 图书跟出版社:是一对多,一对多关系一旦确立,关联字段写在多的一方 4 图书和作者:是多对多,多对多的关系需要建立第三张表(可以自动生成) 5 models.py中把关系建立出来 from django.db import models ### django: 1.11.1 2.0.7 # Create your models here. class Publish(models.Model): id = models.AutoField(primary_key = True ) name = models.CharField(max_length = 32 ) addr = models.CharField(max_length = 64 ) phone = models.CharField(max_length = 64 ) email = models.EmailField() class Book(models.Model): id = models.AutoField(primary_key = True ) name = models.CharField(max_length = 32 ) price = models.DecimalField(max_digits = 6 , decimal_places = 2 ) publish_date = models.DateTimeField(auto_now_add = True ) # to='Publish'跟Publish表做关联(ForeignKey,一对多) # to_field='id'跟哪个字段做关联 # publish=models.CharField(max_length=32) # publish=models.ForeignKey(to='Publish',to_field='id') # publish = models.ForeignKey(to='Publish') # 不写,默认跟主键做关联 publish = models.ForeignKey(to = Publish) # 不写,默认跟主键做关联 # 自动创建出第三张表(这句话会自动创建第三章表) # authors在数据库中不存在该字段,没有to_field # 默认情况:第三张表有id字段,当前Book表的id和Author表的id字段 authors = models.ManyToManyField(to = 'Author' ) #db_constraint=False 如果使用两个表之间存在关联,首先db_constraint=False 把关联切断,但保留链表查询的功能,其次要设置null=True, blank=True,注意on_delete=models.SET_NULL 一定要置空,这样删了不会影响其他关联的表 class Author(models.Model): id = models.AutoField(primary_key = True ) name = models.CharField(max_length = 32 ) age = models.SmallIntegerField() # 一对一的本质是 ForeignKey+unique author_detail = models.OneToOneField(to = 'AuthorDetail' ,to_field = 'id' ) # author_detail=models.ForeignKey(to='AuthorDetail',to_field='id',unique=True) class AuthorDetail(models.Model): id = models.AutoField(primary_key = True ) sex = models.SmallIntegerField() addr = models.CharField(max_length = 64 ) phone = models.BigIntegerField() 6 同步到mysql数据库 - 配置文件 - pymysql.install_as_mysqldb() - 公司可以用过的mysqlclient - 两条命令 7 2.x 版本的django - 外键字段必须加 参数:on_delete - 1.x 版本不需要,默认就是级联删除 - 假设, 删除出版社,该出版社出版的所有图书也都删除,on_delete = models.CASCADE 删除出版社,该出版社出版的图书不删除,设置为空on_delete = models.SET_NULL,null = True 删除出版社,该出版社出版的图书不删除,设置为默认on_delete = models.SET_DEFAULT,default = 0 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #1.1 一对一增加 # new_author_detail = models.AuthorDetail.objects.create( # birthday='1979-08-08', # telephone='138383838', # addr='黑龙江哈尔滨' # ) # obj = models.AuthorDetail.objects.filter(addr='山西临汾').first() #方式1 # models.Author.objects.create( # name='王涛', # age='40', # authorDetail=new_author_detail, # ) # 方式2 常用 # models.Author.objects.create( # name='王涛', # age='40', # authorDetail_id=obj.id, # ) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #方式1 # obj = models.Publish.objects.get(id=2) # models.Book.objects.create( # title = '李帅的床头故事', # publishDate='2019-07-22', # price=3, # # publishs=models.Publish.objects.get(id=1), # publishs=obj, # # ) # 方式2 常用 # models.Book.objects.create( # title='李帅的床头故事2', # publishDate='2019-07-21', # price=3.5, # # publishs=models.Publish.objects.get(id=1), # publishs_id=obj.id # # ) # 总结: 1 email可以不传email,本质就是varchar(admin中会判断) 2 新增图书: - publish = publish - publish_id = publish. id 3 写在表模型中的publish字段,到数据库中会变成publish_id(ForeignKey) 4 查到book对象以后 - book.publish 对象 - book.publish_id id 号,数字 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 1 自动创建的表,表模型就拿不到,book.authors代指表模型 # 多对多,作者和书 # 给西游记这本书新增两个作者lqz和egon # 去到西游记这本书 # book=models.Book.objects.get(name='西游记') # 代指中间表book.authors # lqz=models.Author.objects.get(id=2) # egon=models.Author.objects.get(id=3) # book.authors.add(2,3) # 新增作者,通过id新增 # # book.authors.add(lqz,egon) # 新增作者,通过对象新增 # book.authors.add(2,egon) # 新增作者,通过对象新增 # 西游记删除一个作者 # book = models.Book.objects.get(name='西游记') # book.authors.remove(2) # egon = models.Author.objects.get(id=3) # book.authors.remove(egon) # clear 清空所有作者 book = models.Book.objects.get(name = '西游记' ) # book.authors.add(2, 3) # book.authors.clear() # set 先清空,再add,前提是不存在的作者 book.authors. set ([ 4 , ]) # add ,remove,set clear |
1 2 3 | # 一对一 表一外键关联到表二,表一删除,不影响表2,表2删除会影响表1 # models.AuthorDetail.objects.get(id=2).delete() # models.Author.objects.get(id=3).delete() |
1 2 3 | # 一对多 # models.Publish.objects.get(id=1).delete() # models.Book.objects.get(nid=1).delete() |
1 2 3 4 5 6 7 | # book_obj = models.Book.objects.get(nid=6) # book_obj.authors.remove(6) # book_obj.authors.remove(*[5,6]) # book_obj.authors.clear() # book_obj.authors.add(*[1,]) # book_obj.authors.set('1') # book_obj.authors.set(['5','6']) #删除然后更新 |
1 | add ,remove, set clear |
1 2 3 4 5 6 7 | # 一对一 # models.Author.objects.filter(id=5).update( # name='崔老师', # age=16, # # authorDetail=models.AuthorDetail.objects.get(id=5), # authorDetail_id=4, # ) |
1 2 3 4 5 6 7 8 9 | # models.Book.objects.filter(pk=4).update( # title='B哥的往事2', # # publishs=models.Publish.objects.get(id=3), # publishs_id=3, # ) models.Publish.objects. filter (pk = 2 ).update( id = 4 , # 没有级联更新,报错!! ) |
关系属性(字段)写在哪个类(表)里面,从当前类(表)的数据去查询它关联类(表)的数据叫做正向查询,反之叫做反向查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | ''' 正向查询:Authorobj.authorDetail,对象.关联属性名称 Author----------------------------------->AuthorDetail <----------------------------------- 反向查询:AuthorDetailobj.author ,对象.小写类名 ''' # 跨表查询有两种方式 - 基于对象的跨表查询:子查询 - 基于双下划线的跨表查询:关联查询,连表查询 # 基于对象的跨表查询 - 查询主键为 1 的书籍的出版社所在的城市 # 基于对象的跨表查询(子查询) # 一对多 # 查询主键为1的书籍的出版社所在的城市 # book=models.Book.objects.get(id=1) # 第一次查询 # # book=models.Book.objects.filter(id=1).first() # publish=book.publish # 内部又执行了一次查询,根据publish_id查询publish # print(publish.addr) # 北京出版社出版的所有书籍 # publish=models.Publish.objects.get(name='北京出版社') # 第一次查询了出版社 # books=publish.book_set.all() # 表名小写_set # 第二次,根据出版社id,查询所有书 # print(books) # 正向查询:book表内有publish字段 直接对象.字段名 # 反向查询:publish表内没有book字段,出版社对象.Book小写_set.all() ### 一对一 # 查询所有住址在山东的作者的姓名 # 反向查询:author_detail没有author字段,author_detail.表明小写 # author_detail=models.AuthorDetail.objects.filter(addr__contains='山东').first() # # 反向 # print(author_detail.author.name) # 查询egon作者的地址 # 正向 # author=models.Author.objects.get(name='egon') # print(author.author_detail.addr) # 多对多关系查询 #金x梅所有作者的名字以及手机号 # book=models.Book.objects.get(name='金x梅') # # 正向 # authors=book.authors.all() # for author in authors: # print(author.name) # print(author.author_detail.phone) # 反向 查询egon出过的所有书籍的名字 # egon=models.Author.objects.get(name='egon') # books=egon.book_set.all() # for book in books: # print(book.name) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | # 连表查询 # 基于对象的跨表查询,先查对象,通过对象再去查另一个对象(正向:字段名,反向:表名小写/表名小写_set.all()) # 地址为山东的作者写的所有书 # author_detail=models.AuthorDetail.objects.get(addr='山东') # author=author_detail.author # books=author.book_set.all() # print(books[0].name) # (作业)地址为山东的作者写的所有书的出版社名字 ### 基于双下划线的跨表查之 一对多 # 正向:字段名 # 反向:表名小写 # filter,values,values_list(写 __ 跨表) # 练习: 查询北京出版社出版过的所有书籍的名字与价格(一对多) # SELECT `app01_book`.`name`, `app01_book`.`price` FROM `app01_publish` LEFT OUTER JOIN `app01_book` ON (`app01_publish`.`id` = `app01_book`.`publish_id`) WHERE `app01_publish`.`name` = '北京出版社' ; # res=models.Publish.objects.filter(name='北京出版社').values('book__name','book__price') # print(res) #SELECT `app01_book`.`name`, `app01_book`.`price` FROM `app01_book` INNER JOIN `app01_publish` ON (`app01_book`.`publish_id` = `app01_publish`.`id`) WHERE `app01_publish`.`name` = '北京出版社'; # res=models.Book.objects.filter(publish__name='北京出版社').values('name','price') # print(res) ## 多对多 # 练习: 查询egon出过的所有书籍的名字,价格(多对多) #反向 # res=models.Author.objects.filter(name='egon').values('book__name','book__price') # print(res) # 正向 # res=models.Book.objects.filter(authors__name='egon').values('name','price') # print(res) #查询egon的手机号 # res=models.Author.objects.filter(name='egon').values('author_detail__phone') # print(res) # res=models.AuthorDetail.objects.filter(author__name='egon').values('phone') # print(res) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # 连续跨表 #查询北京出版社出版过的所有书籍的名字以及作者的姓名 # res=models.Publish.objects.filter(name='北京出版社').values('book__name','book__authors__name') # print(res) # res=models.Book.objects.filter(publish__name='北京出版社').values('name','authors__name') # print(res) # res=models.Author.objects.filter(book__publish__name='北京出版社').values('book__name','name') # print(res) # 手机号以189开头的作者出版过的所有 书籍名称 以及 出版社名称 # res=models.AuthorDetail.objects.filter(phone__startswith='189').values('author__book__name','author__book__publish__name') # print(res) # SELECT `app01_book`.`name`, `app01_publish`.`name` FROM `app01_author` INNER JOIN `app01_authordetail` ON (`app01_author`.`author_detail_id` = `app01_authordetail`.`id`) LEFT OUTER JOIN `app01_book_authors` ON (`app01_author`.`id` = `app01_book_authors`.`author_id`) LEFT OUTER JOIN `app01_book` ON (`app01_book_authors`.`book_id` = `app01_book`.`id`) LEFT OUTER JOIN `app01_publish` ON (`app01_book`.`publish_id` = `app01_publish`.`id`) WHERE `app01_authordetail`.`phone` LIKE '189%' ; res = models.Author.objects. filter (author_detail__phone__startswith = '189' ).values( 'book__name' , 'book__publish__name' ) print (res) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | ###########1 聚合查询(聚合函数:最大,最小,和,平均,总个数) from django.db.models import Avg, Max , Min ,Count, Sum #1 计算所有图书的平均价格 # aggregate结束,已经不是queryset对象了 # book=models.Book.objects.all().aggregate(Avg('price')) # 起别名 # book=models.Book.objects.all().aggregate(avg=Avg('price')) #2 计算总图书数 # book = models.Book.objects.all().aggregate(count=Count('id')) # 3 计算最低价格的图书 # book = models.Book.objects.all().aggregate(min=Min('price')) # 4 计算最大价格图书 # book = models.Book.objects.all().aggregate(max=Max('price')) # print(book) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | # annotate() 内写聚合函数 # values在前表示group by的字段 # values在后表示取某几个字段 # filter在前表示where # filter在后表示having ####2 分组查询 ''' 查询每一个部门名称以及对应的员工数 book: id name price publish 1 金品 11.2 1 2 西游 14.2 2 3 东游 16.2 2 4 北邮 19.2 3 ''' # 示例一:查询每一个出版社id,以及出书平均价格 # select publish_id,avg(price) from app01_book group by publish_id; # annotate # from django.db.models import Avg, Count, Max, Min # ret=models.Book.objects.values('publish_id').annotate(avg=Avg('price')).values('publish_id','avg') # print(ret) # 查询出版社id大于1的出版社id,以及出书平均价格 #select publish_id,avg(price) from app01_book where publish_id>1 group by publish_id; # ret=models.Book.objects.values('publish_id').filter(publish_id__gt=1).annotate(avg=Avg('price')).values('publish_id','avg') # print(ret) # 查询出版社id大于1的出版社id,以及出书平均价格大于30的 # select publish_id,avg(price)as aaa from app01_book where publish_id>1 group by publish_id HAVING aaa>30; # ret = models.Book.objects.values('publish_id').filter(publish_id__gt=1).annotate(avg=Avg('price')).filter(avg__gt=30).values( # 'publish_id', 'avg') # print(ret) ## 查询每一个出版社出版的书籍个数 # pk 代指主键 # ret=models.Book.objects.get(pk=1) # print(ret.name) # ret=models.Publish.objects.values('pk').annotate(count=Count('book__id')).values('name','count') # print(ret) # 如果没有指定group by的字段,默认就用基表(Publish)主键字段作为group by的字段 # ret=models.Publish.objects.annotate(count=Count('book__id')).values('name','count') # print(ret) # 另一种方式实现 # ret=models.Book.objects.values('publish').annotate(count=Count('id')).values('publish__name','count') # print(ret) #查询每个作者的名字,以及出版过书籍的最高价格(建议使用分组的表作为基表) # 如果不用分组的表作为基表,数据不完整可能会出现问题 # ret=models.Author.objects.values('pk').annotate(max=Max('book__price')).values('name','max') # ret = models.Author.objects.annotate(max=Max('book__price')).values('name', 'max') # ret= models.Book.objects.values('authors__id').annotate(max=Max('price')).values('authors__name','max') # print(ret) #查询每一个书籍的名称,以及对应的作者个数 # ret=models.Book.objects.values('pk').annotate(count=Count('authors__id')).values('name','count') # ret=models.Book.objects.annotate(count=Count('authors__id')).values('name','count') # ret=models.Author.objects.values('book__id').annotate(count=Count('id')).values('book__name','count') # # print(ret) #统计不止一个作者的图书 # ret=models.Book.objects.values('pk').annotate(count=Count('authors__id')).filter(count__gt=1).values('name','count') # ret = models.Author.objects.values('book__id').annotate(count=Count('id')).filter(count__gt=1).values('book__name', 'count') # print(ret) # 统计价格数大于10元,作者的图书 ret = models.Book.objects.values( 'pk' ). filter (price__gt = 10 ).annotate(count = Count( 'authors__id' )).values( 'name' , 'count' ) print (ret) #统计价格数大于10元,作者个数大于1的图书 ret = models.Book.objects.values( 'pk' ). filter (price__gt = 10 ).annotate(count = Count( 'authors__id' )). filter (count__gt = 1 ).values( 'name' , 'count' ) print (ret) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | # F查询:取出数据库的某个字段的值 # 把read_num都加1 from django.db.models import F ret = models.Book.objects. all ().update(read_num = F( 'read_num' ) + 1 ) print (ret) #查询评论数大于阅读数的书籍 ret = models.Book.objects. all (). filter (commit_num__gt = F( 'read_num' )) for i in ret: print (i.name) ## 查询评论数大于阅读数2倍的书籍 ret = models.Book.objects. filter (commit_num__gt = F( 'read_num' ) * 2 ) print (ret) # Q查询:制造 与或非的条件 Q() & | ~ 与或非 # Q查询:制造 与或非的条件 # 查询名字叫egon或者价格大于100的书 from django.db.models import Q # ret=models.Book.objects.filter(Q(name='egon') | Q(price__gt=100)) # 查询名字叫egon并且价格大于100的书 # ret=models.Book.objects.filter(Q(name='egon') & Q(price__gt=100)) # ret=models.Book.objects.filter(name='egon',price__gt=100) # 查询名字不为egon的书 # ret = models.Book.objects.filter(~Q(name='egon')) # print(ret) # Q可以嵌套 ret = models.Book.objects. filter ((Q(name = 'egon' ) & Q(price__lt = 100 )) | Q(id__lt = 3 )) print (ret) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | # 原生sql(有些sql用orm写不出来) # 两种方案 # 第一种:用的比较少 # from django.db import connection # # cursor = connection.cursor() # # cursor.execute("""SELECT * from app01_book where id = %s""", [1]) # # # row = cursor.fetchone() # row = cursor.fetchall() # print(row) # 第二种,用的多 # books=models.Book.objects.raw('select * from app01_book where id >3') # print(books)#RawQuerySet对象 # for book in books: # print(book.name) # books=models.Book.objects.raw('select * from app01_publish') # for book in books: # print(book.__dict__) # print(book.name) # print(book.addr) # print(book.email) # print(book.price) # authors = models.Author.objects.raw('SELECT app01_author.id,app01_author. NAME,app01_authordetail.sex FROM app01_author JOIN app01_authordetail ON app01_author.author_detail_id = app01_authordetail.id WHERE app01_authordetail.sex = 1') # # for author in authors: # print(author.name) # print(author.__dict__) |
1 2 3 4 5 6 7 8 9 10 11 | # defer和only(查询优化相关) # only保持是book对象,但是只能使用only指定的字段 # books = models.Book.objects.all().only('name') # print(books[0].name) # print(books[0].price) # 能出来, # books = models.Book.objects.all().only('name') # # print(books[0].__dict__) books = models.Book.objects. all ().defer( 'name' , 'price' ) print (books[ 0 ].__dict__) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | # 事物:ACID,事物的隔离级别(搜),锁, 行级锁,表级锁 # djanog orm中使用事物:原子性操作,要么都成功,要么都失败 # 新增一个作者详情,新增一个作者 # 事物的三个粒度 # 1 局部使用 from django.db import transaction with transaction.atomic(): # 都在事物中,要么都成功,要么都失败 author_detail = models.AuthorDetail.objects.create(addr = 'xxx' ,phone = '123' ,sex = 1 ) # raise Exception('抛了异常') author = models.Author.objects.create(name = 'llqz' ,age = 19 ,author_detail = author_detail) # 2 视图函数装饰器,这一个视图函数都在一个事物中 # @transaction.atomic # def index(request): # return HttpResponse('ok') # 3 整个http请求,在事物中,在setting.py中配置 ''' DATABASES = { 'default': { ... 'PORT': 3306, 'ATOMIC_REQUEST': True, } } 'ATOMIC_REQUEST': True, 设置为True统一个http请求对应的所有sql都放在一个事务中执行(要么所有都成功,要么所有都失败)。 ''' |
1 2 3 4 5 6 7 8 9 10 11 | class Book(models.Model): title = models.CharField(max_length = 32 ) price = models.DecimalField(max_digits = 8 ,decimal_places = 2 ) authors = models.ManyToManyField(to = 'Author' ) #与Author表自动创建多对多关联关系 class Author(models.Model): name = models.CharField(max_length = 32 ) 优点:可以使用ORM提供的快捷方法: add() clear() set () remove() all () 缺点:第三张表自动创建,无法扩展第三张表的字段 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class Book(models.Model): title = models.CharField(max_length = 32 ) price = models.DecimalField(max_digits = 8 ,decimal_places = 2 ) class Author(models.Model): name = models.CharField(max_length = 32 ) class Book2Author(models.Model): book = models.ForeignKey(to = 'Book' ) author = models.ForeignKey(to = 'Author' ) create_time = models.DateField(auto_now_add = True ) 优点:可以自己扩展第三章关系表的字段 缺点:不能使用ORM提供的快捷方法(查询麻烦,需要跨三张表) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | class Book(models.Model): title = models.CharField(max_length = 32 ) price = models.DecimalField(max_digits = 8 ,decimal_places = 2 ) # 当前在哪个表中,元组中的第一个参数就是 表名_id或表对象 authors = models.ManyToManyField(to = 'Author' ,through = 'Book2Author' ,through_fields = ( 'book' , 'author' )) # through 告诉django orm 书籍表和作者表的多对多关系是通过Book2Author来记录的 # through_fields 告诉django orm记录关系时用过Book2Author表中的book字段和author字段来记录的 # through_fields 中的第一个字段必须为当前表的字段,参考Author表中ManyToManyField的写法,两个表只需要写一个 """ 多对多字段的 add set remove clear不支持 """ class Author(models.Model): name = models.CharField(max_length = 32 ) # books = models.ManyToManyField(to='Book', through='Book2Author', through_fields=('author', 'book')) #手动创建的第三张表 class Book2Author(models.Model): book = models.ForeignKey(to = 'Book' ) author = models.ForeignKey(to = 'Author' ) create_time = models.DateField(auto_now_add = True ) # setting 中 指定扩写Book表 AUTH_USER_MODEL = 'blog.Book' 优点: 可以使用ORM提供的查询快捷方法,clear() all () 可以使用也可以使用 不用自己创建第三张表了,也可以任意扩展字段 缺点:多对多字段的add() remove() set () 无法使用 |
1 2 3 4 5 6 7 8 9 10 | 设置数据库持久连接 合理创建索引 提示:索引会占用磁盘空间,创建不必要的索引只会形成浪费。主键、外键、唯一键已经建立索引 1. 频繁出现在where条件子句的字段 get() filter () 2. 经常被用来分组(group by)或排序(order by)的字段 3. 用于联接的列(主健 / 外健)上建立索引 4. 在经常存取的多个列上建立复合索引,但要注意复合索引的建立顺序要按照使用的频度来确定 减少SQL语句执行的次数(select_related prefetch_related) 仅获取需要的字段 使用批量创建、更新、删除,不随意对结果排序 |
"一劳永逸" 的话,有是有的,而 "一劳永逸" 的事却极少
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
2020-08-27 Linux 五种IO模型