• 222


    ORM多表增删改和查询

    0.1 mysql的知识

    多表查询

    ​ 外键 foreignkey

    ​ 一对一 foreignkey+unique

    被关联的表 的数据(先写,才可被关联)不可改,不可删,可以增

    fk_publish 写关联的表 无所谓 常用的放这张表

    publish fk+unique(1对1)
    id name publish_detail_id
    1 20期 1、2不能重复

    不常用的

    publish_detail
    id tel
    1

    多对一

    book fk_publish
    id title publish_id
    1 python 1

    多对多

    ​ 互相建外键,不行,谁先建?✖

    ​ 建第三张表 ✔

    多对多 有外键,不可删23 也可以增加4 可以删除author里的1

    book2authot fk_book fk_author
    id book_id author_id
    1 1 2
    2 1 3
    3
    author
    id name 技术描述
    1 cls 还行

    很多公司不用foreign_key 了,牵一发而动全身,强制约束,导致操作变复杂

    ​ 现在通过逻辑来+,建没有关系的表,inner join查。

    写一段orm语句,写一段原生sql

    select author.技术描述 from (select * from (从硬盘到内存) book inner join author on book.id == author.id) as t1 inner join book2author on t1.id == book2author.id;

    book表,既有多对一,又有多对多,

    我关联别人的,有范围
    别人关联我,我随便增加	改和删不行
    他连别人,所以可以随便删除,但是不可以随便添加
    别人连他,所以可以随便添加,但是不可以随便删除
    

    外键关联施,受需要有相关项

    外键关联受, 必须有,不可改,不可删,可以增

    1 创建模型

    1.1建表

    ad = models.OneToOneField(to='AuthorDetail' ) 
    自动生成ad_id 名字  
    
    class Author():
    	name = models.CharField(max_length=32)
    	age = ..IntegerField()
    	authorDetail = ..OneToOneField(to = 'AuthorDetail')
    class AuthorDetail(): 不常使用的字段,另建一个表,否则数据量大
    	telephone = ..BigInt
    	addr = ...Char
    class Publish():
    	name = Char ml32
    	city = Char
    class Book():
    	title = Char ml32
    	price = Decimal md = 5 , dp = 2
    	auth = Manytomany(to= 'Author')
    	publish = Foreign.key(to = 'Publish')
    

    1.2 多对多的三种创建

    方式1 手动创建 建三个表

    ​ 联合唯一: 同时不重复

      	author = models.ForeignKey(to="Author")
        book = models.ForeignKey(to="Book")
    
        class Meta:
            unique_together = ("author", "book")
    

    方式2 manytomany

    books = models.ManyToManyField(to="Book", related_name="authors")
    

    方式3 manytomany 手动指定

    author = models.ForeignKey(to="Author")
        book = models.ForeignKey(to="Book")
        class Meta:
            unique_together = ("author", "book")
    

    through 指定这个表作为第三张表 指定字段

    decimal为什么精度最高?存的是字符串,所以不会改变

    再存浮点型的时候,小数点,存储机制,所以会变化。。。

    show create table app01_author; 查询key

    UNIQUE KEY ad_id_id (ad_id_id), 指定了后者,名字前者

    alter table app01_author drop index ad_id_id; 删除uninkey

    1.3 插入

    publish = models.ForeignField(to='Publish' )
    自动生成publish_id 名字

    models.Book.objects.filter(id = 8)<QuerySet [<Book: 流浪地球>]>  
    models.Book.objects.filter(id=8)[0]  流浪地球 
    
    方式1 
    publish_obj=Publish.objects.get(id=1) #拿到id为1的出版对象
    book_obj=Book.objects.create(title="金瓶眉",publishDate="2012-12-12",price=100,publish=publish_obj) #出版社对象作为值给publish,其实就是自动将publish字段变成publish_id,然后将publish_obj的id给取出来赋值给publish_id字段,注意你如果不是publish类的对象肯定会报错的 
    方式2 
     book_obj=Book.objects.create(title="金瓶眉",publishDate="2012-12-12",price=100,publish_id=1)	 属性
    

    print(models.Book.objects.filter(id=1)[0]) #三体
    print(models.Book.objects.filter(publish_id=2)[1]) #小小小小的火

    publish_obj = models.Publish.objects.filter(id=1)[0]      		#Publish object
    publish_obj = models.Publish.objects.filter(id=1)
    	 #<QuerySet [<Publish: Publish object>]>
    models.Book.objects.create(title= '人生',price=13,publish= publish_obj )
    models.Book.objects.create(title= '流浪地球',price=111,publish_id= 1 )
    # publish_id = 1 或者 publish = publish对象 filter()[0] 或者 get()
    

    1.4 增(多对多)

    1.3 1 第三张表
    book_obj = models.Book.objects.get(id=2)
    book_obj.authors   (第三张表)
    book_obj.authors.add(1,2)
    

    add里面是作者对象或者是作者的id

    book_obj1.auth. auth连接第三方 就是第三张表了

     #增加: 添加一本书,关联两个作者
            # 1.先把作者录入了 , 然后选择
            # 2. 或者输入作者,去查询
    book_obj = models.Book.objects.create(title='人间词话',price=23,publish_id=1)
    
    wuqishi = models.Author.objects.get(name='伍绮诗')
    liucixin = models.Author.objects.get(name='刘慈欣')
    book_obj.auth.add(wuqishi,liucixin)   #给第三张表add
    				#增的是author对象
    book_obj1.auth.add(*[1,2])		#增的是author id
    

    1.5 删

    一对一更新和删除

    models.Author.objects.filter(id=2) <QuerySet [<Author: xxx>]>

    models.Author.objects.filter(id=2).update(name= 'wang')
    # models.Author.objects.filter(id=2).delete()
    

    多对多删除

        # book_obj.auth.remove(1)     #author的id author对象
        book_obj.authors.remove(1,3)
        book_obj.authors.remove(*[1,3]) 
        # book_obj.auth.clear()             #全删对象
        # book_obj.auth.set([1,2])        # 删除并且赋值
        # data = {'title':'围城','price':12}
        # models.Book.objects.filter(id=6).update(**data)
    

    2 下午

    2. 查

    2.0 原理

    基于对象的: 子查询

    ​ 正向查询:

    ​ 关系属性在哪张表,去关联的表去查询

    ​ 往onetoone的里面去找,就是正向查询 ,否则就是反向查询

    基本写法

    对象= models.类.objects.filter()[0] /get()

    正向查询:

    ​ 用属性(.all()多 .属性 少) 对象.关联的属性.属性或者all()

    反向查询:

    	用表名(_set : 多)  (.属性 :少)	对象.前者的表名_ _ set.all() 或属性
    

    如果没写 __ str __ 的情况下 ,写__ __ dict __显示文字

    多对多的增

    add里面是作者对象或者是作者的id

     book_1 = models.Book.objects.filter(title='人间词话')[0]
     book_1.auth.add(1,2)
    

    2.11 一对一

    正		:找作者伍绮诗的addr
    author_obj = models.Author.objects.filter(name='伍绮诗')[0]
    print(author_obj.authorDetail.addr)     #美国
    反		:找书本人间词话的出版社
    book_obj3 = models.Book.objects.filter(title='人间词话')[0]
    print(book_obj3.publish.city)       #北京
    

    2.12 一对多

    正 			:找书本人间词话的出版社
    book_obj3 = models.Book.objects.filter(title='人间词话')[0]
    print(book_obj3.publish.city)    #北京 前三个都是属性 后三个all
    反			:找出版社 新华书店 出版的图书   多  
    publish1 = models.Publish.objects.filter(name='人民邮电')[0]
    print(publish1.book_set.all())  ##<QuerySet [<Book: 无声告白 
    

    2.13 多对多

    正			: 查询book 正能量被几个作者 写出来	多
    book_obj4 = models.Book.objects.filter(title='正能量')[0]
    print(book_obj4,book_obj4.auth.all())       #正能量 <QuerySet
    反			: 查询 作者伍绮诗 写的所有书籍		多
    author_obj2 = models.Author.objects.filter(name='伍绮诗')[0]
    print(author_obj2.book_set.all())    
    

    orm 类与对象 与mysql的映射封装,但是有些复杂的写不出来,mysql可以写出来 ---超哥

    orm没有级联更新

    解决办法:

    基于上下划线的

    两种方式:

    models.Book.objects.filter(id=2)) 
    	# <QuerySet [<Book: python>]>
    	
    models.Book.objects.filter(id=2).values('publishs__city')      #用属性	 <QuerySet [{'publish__city': '沙河'}]>
    
    models.Publish.objects.filter(book__id = 2 ).values('city')
      	#<QuerySet [{'city': '沙河'}]>
    
    

    效率问题

    翻译成一句,所以效率快
    不连表的,翻译成两句,效率慢
    

    ER图 Entity Relationship Diagram

    only full group by 设置了 没法读取无效率的操作,前后对应

    五道题有可能就是这样的错误,做不出来 硬题做不出来,简单的题做出来

    sql语句没问题

    原生sql

    select name,max(price) from app01_book INNER JOIN app01_publish on app01_book.publishs_id=app01_publish.id GROUP BY name ;
    

    orm

    print(models.Book.objects.values('publishs_id').annotate(a=Max('price')).values('publishs__name','a'))# value里显示的
    按照publish-id 分组,按
    

    anno

    前面values 写分组依据,后面annotate写统计结果

    select avg(*) from name group by publish_id

    写 orm的话

    models.publish.object.values('publish_id').annotate('m=Avg('')')

    models.publish.object.values('publish_id').annotate('m=Avg('')').values()

    替换前面

    链表操作

    因为连表所以正反都可以  
    print(models.Publish.objects.values('name').annotate(m=Max('bp1__price')))
        #<QuerySet [{'name': '20期出版社', 'm': Decimal('58.00')}, {'name': '人民邮电', 'm': Decimal('61.00')}, {'name': '译林', 'm': Decimal('146.30')}]>
        print(models.Book.objects.values('publishs__name').annotate(m= Max('price')))
        #<QuerySet [{'publishs__name': '20期出版社', 'm': Decimal('63.00')}, {'publishs__name': '人民邮电', 'm': Decimal('66.00')}, {'publishs__name': '译林', 'm': Decimal('151.30')}]>
    
    

    今日内容

    基于双下划线的跨表查询(连表,正向反向链表的时候)

    聚合查询

    ​ aggregate(Avg('xxx')) ---{}

    分组查询

    ​ annotate(a=Max('xxx'))

    F与Q查询

    ​ F针对的是单表里面某些字段的批量操作

    Q Q(xxx) | Q(ssss) &Q (xss) ,

    filter(Q(xxx)|Q(xxxx),title='xxxx') 组合和 非Qtitle必须放后面

    filter(Q(Q(xxx)|Q(xxxx))|Q(xxxx),title='xxxx') # 嵌套

    忘了聚合了,同桌说的。不会。

    print(models.Author.objects.values('name').annotate(c=Max('book__price')).aggregate(Avg('c')))  #{'c__avg': 206.333333}
    
    from django.shortcuts import render,HttpResponse
    from Af_Pr import models
    from django.db.models import Avg,Max,Min,Count,Sum
    from django.db.models import F,Q
    
    
    def query(request):
        # book_obj = models.Book.objects.filter(id=1)[0]
        # book_obj.authors.add(1,2)
        book_obj1 = models.Book.objects.filter(id=3)[0]
        book_obj1.authors.add(2)
    
    #链表操作 用属性
        # print(models.Book.objects.filter(id=2),models.Book.objects.filter(id=2).values())   #<QuerySet [<Book: 小王子>]> <QuerySet [{'id': 2, 'title': '小王子', 'price': Decimal('44.00'), 'zan': 32, 'comment': 22, 'publishs_id': 2}]>
        # print(models.Book.objects.filter(id=2).values('title'))     #<QuerySet [{'title': '小王子'}]>
        # print(models.Book.objects.filter(id=2).values_list('title'))    #<QuerySet [('小王子',)]>
        # author_obj = models.Author.objects.filter(name='李继宏')[0]
        # print(models.Author.objects.filter(name='李继宏'),models.Author.objects.filter(name='李继宏')[0])   #<QuerySet [<Author: 李继宏   李继宏
        # print(models.Book.objects.filter(id=2)[0].authors.remove(author_obj))   # 可以根据这个作者名字删除,不是作者对象
        # print(models.Book.objects.filter(id=2).values('title').filter(id=2))    #<QuerySet [{'title': '小王子'}]>
        # print(models.Book.objects.values())     #<QuerySet [{'id': 1, 'title': '飞鸟集', 'price': Decimal('23.00'), 'zan': 33, 'comment': 45, 'publishs_id': 1}, {'id': 2, 'title': '小王子', 'price': Decimal('44.00'), 'zan': 32, 'comment': 22, 'publishs_id': 2}, {'id': 3, 'title': '边城', 'price': Decimal('12.00'), 'zan': 3, 'comment': 222, 'publishs_id': 3}]>
        # print(models.Book.objects.values('title'))      #<QuerySet [{'title': '飞鸟集'}, {'title': '小王子'}, {'title': '边城'}]>
    
        # print(models.Book.objects.values('title').annotate(Avg('')))
    
        # obj = models.Book.objects.filter(authors__name='李继宏').values('title', 'authors__book__authors')
        # print(obj)    # 查看的是作者写的那本书的所有作者    #<QuerySet [{'title': '飞鸟集', 'authors__book__authors': 1}, {'title': '飞鸟集', 'authors__book__authors': 2}, {'title': '飞鸟集', 'authors__book__authors': 2}, {'title': '边城', 'authors__book__authors': 1}, {'title': '边城', 'authors__book__authors': 2}, {'title': '边城', 'authors__book__authors': 2}]>
        # print(models.Book.objects.filter(authors__name='李继宏').values('title','authors'))    #<QuerySet [{'title': '飞鸟集', 'authors': 2}, {'title': '边城', 'authors': 2}]>
        # print(models.Book.objects.filter(authors__name='李继宏'))  # <QuerySet [<Book: 飞鸟集>, <Book: 边城>]>
    
    # 下午
        # 一对多查询 正向查询(用属性)    查询 出版社 译林出版过的所有书籍的名字与价格
        print(models.Book.objects.filter(publishs__name='译林').values_list('title','price'))    # <QuerySet [('飞鸟集', Decimal('23.00'))]>
        #反向查询
        print(models.Publish.objects.filter(name='译林').values_list('bp1__title','bp1__price'))
        #查询 书籍的出版社的名字
        print(models.Book.objects.filter(title='小王子').values_list('publishs__name'))    #<QuerySet [('人民邮电',)]>
        #多对多查询
        #正向  查询作者 李继宏 写作的所有书籍的名字
        print(models.Author.objects.filter(name='泰戈尔').values_list('book__title'))  #<QuerySet [('飞鸟集',), ('小王子',)]>
        # 反向  查询书籍 飞鸟集 的所有作者的电话
        print(models.Book.objects.filter(title='飞鸟集').values_list('authors__ad_id__telephone')) #<QuerySet [('123',), ('333',)]>
    
        # 连续跨表
        # 正向查询 出版社 译林的所有书籍的名字以及作者的名字
        # values_list 格式都是 :  #<QuerySet [('飞鸟集', '泰戈尔'), ('飞鸟集', '李继宏')]>
        print(models.Publish.objects.filter(name='译林').values('bp1__title','bp1__authors__name'))   #<QuerySet [{'bp1__title': '飞鸟集', 'bp1__authors__name': '泰戈尔'}, {'bp1__title': '飞鸟集', 'bp1__authors__name': '李继宏'}]>
        # 反向查询
        print(models.Book.objects.filter(publishs__name='译林').values('title','authors__name')) #    <QuerySet [{'title': '飞鸟集', 'authors__name': '泰戈尔'}, {'title': '飞鸟集', 'authors__name': '李继宏'}]>
    
        # 练习 :手机号以151 开头的作者 出版过的所有书籍名称 以及出版社名称
        print(models.AuthorDetail.objects.filter(telephone__startswith=123).values('author__book__title','author__book__publishs__name'))   #<QuerySet [{'author__book__title': '飞鸟集', 'author__book__publishs__name': '译林'}, {'author__book__title': '边城', 'author__book__publishs__name': '新华书店'}]>
        print(models.Author.objects.filter(ad_id__telephone__startswith=123).values('book__title','book__publishs__name'))
    
        # related_name      publishs = ForeignKey(to='Publish' related_name='bp1')
    
    
        # 聚合查询  #计算所有图书的平均价格
        # aggregate调用
        # models.Book.objects.aggregate(Avg('price')  也可以
        print(models.Book.objects.all().aggregate(Avg('price')))    #{'price__avg': 26.333333}
        print(models.Book.objects.aggregate(average_price=Avg('price')))    #{'average_price': 26.333333}
        print(models.Book.objects.aggregate(Avg('price'),Max('price'),Min('price')))    #{'price__avg': 26.333333, 'price__max': Decimal('44.00'), 'price__min': Decimal('12.00')}
    
    
        #  单表分组查询           value 分组条件    annotate  结果
        print(models.Book.objects.values('title').annotate(c= Count('price')))  #<QuerySet [{'title': '飞鸟集', 'c': 1}, {'title': '小王子', 'c': 1}, {'title': '边城', 'c': 1}]>
        # print(models.Book.objects.values('title').annotate(c= 'authors__name'))
        # 查询 每一个部门名称以及对应的员工数
        print(models.Author.objects.values('name').annotate(c = Count('book__title')))  #<QuerySet [{'name': '泰戈尔', 'c': 2}, {'name': '李继宏', 'c': 2}, {'name': '安东尼', 'c': 0}]>
        print(models.Author.objects.values('name').annotate(c=Count( 'book__title')).values('name'))         #<QuerySet [{'name': '泰戈尔'}, {'name': '李继宏'}, {'name': '安东尼'}]>
        print(models.Author.objects.values('name','age').annotate(c=Count('book__title')))  #<QuerySet [{'name': '泰戈尔', 'age': 78, 'c': 2}, {'name': '李继宏', 'age': 39, 'c': 2}, {'name': '安东尼', 'age': 56, 'c': 0}]>
    
    
        # 查询练习  1 统计每一个出版社最便宜的书
        print(models.Publish.objects.values('name','bp1__title').annotate(c=Min('bp1__price')))
        #<QuerySet [{'name': '译林', 'bp1__title': '飞鸟集', 'c': Decimal('23.00')}, {'name': '人民邮电', 'bp1__title': '小王子', 'c': Decimal('44.00')}, {'name': '新华书店', 'bp1__title': '边城', 'c': Decimal('12.00')}]>
    
        #2 练习:统计每一本书的作者个数
        print(models.Book.objects.values('title').annotate(c = Count('authors__id')))   #<QuerySet [{'title': '飞鸟集', 'c': 2}, {'title': '小王子', 'c': 1}, {'title': '边城', 'c': 1}]>
        #(3) 统计每一本以py开头的书籍的作者个数:
        print(models.Book.objects.filter(title__startswith='小').values('title').annotate(c = Count('authors__id'))) #<QuerySet [{'title': '小王子', 'c': 1}]>
    
        #  (4) 统计不止一个作者的图书:
        print(models.Book.objects.values('title').annotate(c=Count('authors__id')).filter(c__gt=0).values('title','c'))
            #<QuerySet [{'title': '飞鸟集', 'c': 2}, {'title': '小王子', 'c': 1}, {'title': '边城', 'c': 1}]>
        #(5) 根据一本图书作者数量的多少对查询集 QuerySet进行排序:
        print(models.Book.objects.values('title').annotate(c= Count('authors__id')).order_by('-c'))    #<QuerySet [{'title': '边城', 'c': 3}, {'title': '飞鸟集', 'c': 2}, {'title': '小王子', 'c': 1}]>
    
        #  (6) 查询各个作者出的书的总价格:
        print(models.Author.objects.values('name').annotate(Sum('book__price')))
                #<QuerySet [{'name': '泰戈尔', 'book__price__sum': Decimal('79.00')}, {'name': '李继宏', 'book__price__sum': Decimal('35.00')}, {'name': '安东尼', 'book__price__sum': Decimal('12.00')}]>
    
     #F和Q查询
    #   F查询
        ## 查询评论数大于收藏数的书籍
        print(models.Book.objects.filter(comment__lt= F('zan')))    #<QuerySet [<Book: 小王子>]>
        #查询评论数大于收藏数2倍的书籍
        print(models.Book.objects.filter(comment__gt=F('zan')*2))   #<QuerySet [<Book: 边城>]>
        # 把所有的书籍价格 增加30
        # models.Book.objects.all().update(price=F('price')+30)
    
    #Q 查询  &与 |或  ~非
    
        print(models.Book.objects.filter(Q(authors__name__startswith="李") | Q(authors__name__startswith="泰")).values('title'))
        a = models.Book.objects.filter(Q(authors__name__startswith="李") | Q(authors__name__startswith="泰")).values('title')
        # print(a.annotate(c = Max('price')))
    
        print(models.Book.objects.filter(Q(authors__name='泰戈尔') | Q(title='飞鸟集'), price__gt = 220 ))
    
        # 综合练习题
        #1 查询每个作者的姓名以及出版的书的最高价格
        print(models.Author.objects.values('name').annotate(c = Max('book__price')))    #<QuerySet [{'name': '泰戈尔', 'c': Decimal('224.00')}, {'name': '李继宏', 'c': Decimal('203.00')}, {'name': '安东尼', 'c': Decimal('192.00')}]>
    
    
        # 2 查询作者id大于2作者的姓名以及出版的书的最高价格
        print(models.Author.objects.filter(id__gt=2).values('name').annotate(c = Max('book__price')))   #<QuerySet [{'name': '安东尼', 'c': Decimal('192.00')}]>
    
        # 3 查询作者id大于2或者作者年龄大于等于20岁的女作者的姓名以及出版的书的最高价格
        print(models.Author.objects.filter(Q(id__gt=2) | Q(age__gte=30),name__startswith='李').values('name').annotate(c = Max('book__price')))
                                                                                                  #<QuerySet [{'name': '李继宏', 'c': Decimal('203.00')}]>
        #4 查询每个作者出版的书的最高价格 的平均值
        print(models.Author.objects.values('name'))     #<QuerySet [{'name': '泰戈尔'}, {'name': '李继宏'}, {'name': '安东尼'}]>
        a = models.Author.objects.values('name').annotate(c = Max('book__price'))   #<QuerySet [{'name': '泰戈尔', 'c': Decimal('224.00')}, {'name': '李继宏', 'c': Decimal('203.00')}, {'name': '安东尼', 'c': Decimal('192.00')}]>
        print(models.Author.objects.values('name').annotate(c=Max('book__price')).aggregate(Avg('c')))  #{'c__avg': 206.333333}
    
        # 5 每个作者出版的所有书的价格以及最高价格的那本书的名称 (通过orm玩起来就是个死题,需要用原生sql)
        # print(models.Author.objects.values('name').annotate(c= Max('book__price')).values_list('name','book__title','c'))
        # print(models.Book.objects.values('authors__ad_id_id').annotate(m = Max('price')).values('authors__name,title'))
        # print(models.Book.objects.values_list('authors__name','price').order_by('authors__id') )
        # print(models.Book.objects.values_list('authors__name','price').order_by( '-price').filter(Q(price=224)|Q()).values('title'))
        # print(models.Book.objects.filter())
        # print(models.Book.objects.filter(Q(authors__id=1)|Q(authors__id=2)|Q(authors__id=3)).values_list('authors__name','price'))
        # print(models.Book.objects.filter(Q(authors__id=1)|Q(authors__id=2)|Q(authors__id=3)).values_list('authors__name','price'))
    
        print(models.Book.objects.annotate(c= Max('price')).values_list('authors__name','title'))
        return HttpResponse('ok')
    
    # def order(request):
    #     for i in range(3300):
    #         print(i)
    #         return render(request,'order.html',locals())
    

    5 每个作者的书的最高价格的名称

    中间的select 不能是* ,提示 not id 不懂 三联表 以价格进行排序 以名字分组 GROUP BY b.name 把每一个第一个读出来

    print(models.Author.objects.order_by('book__price').annotate(m= Max('book__price')).values_list('book__title','m','name'))
    
    # <QuerySet [('边城', Decimal('56.00'), '钱钟书'), ('边城', Decimal('56.00'), '刘慈欣'), ('边城', Decimal('12.00'), '安东尼'), ('飞鸟集', Decimal('34.00'), '泰戈尔'), ('飞鸟集', Decimal('32.00'), '李继宏')]>
    
    无法处理,必须进行分组处理,group里的第一个title不符合
    
    select * from (select name,title,price from af_pr_author INNER JOIN af_pr_book_authors on af_pr_author.id=
    af_pr_book_authors.author_id INNER JOIN af_pr_book on af_pr_book.id=
    af_pr_book_authors.book_id ORDER BY af_pr_book.price desc) b  GROUP BY b.name  ;
    
    刘慈欣	平凡的世界	56
    安东尼	边城	12
    李继宏	飞鸟集	32
    泰戈尔	小王子	34
    钱钟书	平凡的世界	56
    
    row 原生函数

    像下面这样执行原生SQL语句

     ret =models.Publish.objects.raw('select * from af_pr_book;') 
     <RawQuerySet: select * from af_pr_book;> <class 'django.db.models.query.RawQuerySet'>    
    返回的是RawQuerySet 实例
    
     for i in ret:
            print(i.title)     #飞鸟集 小王子  边城 围城 三体 人
    
    直接执行自定义SQL
    from django.db import connection, connections
    cursor = connection.cursor()  # cursor = connections['default'].cursor()
    cursor.execute("""SELECT * from af_pr_author where id = %s""", [1])
    ret = cursor.fetchone()
    print(ret)      #(1, '泰戈尔', 78, 3)
    
    ret = models.Student.objects.raw('select id, tname as hehe from app02_teacher')
        for i in ret:
            print(i.id, i.hehe)
    raw()方法自动将查询字段映射到模型字段
    d = {'tname': 'haha'}
        ret = models.Student.objects.raw('select * from app02_teacher', translations=d)
        for i in ret:
            print(i.id, i.sname, i.haha)
    原生SQL还可以使用参数
    d = {'tname': 'haha'}
        ret = models.Student.objects.raw('select * from app02_teacher where id > %s', translations=d, params=[1,])
        for i in ret:
            print(i.id, i.sname, i.haha)
    
    Python脚本中调用Django环境

    (django外部脚本使用models)

    import os
    
    if __name__ == '__main__':
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
        import django
        django.setup()
    
        from app01 import models  #引入也要写在上面三句之后
    
        books = models.Book.objects.all()
        print(books)
    

    day61

    聚合返回的是字典

    models.A
    

    分组

    查询作者 出版过的书的平均价格
    models.Author.objects.values('name').annotate(Avg('bp1__price'))
    models.Book.objects.values('authors__name').annotate(Abg('price'))
    
    

    F

    models.Book.objects.filter(commet__lt=F('zan'))
    models.Book.objects.all().filter(F('year')+10)
    

    Q

    查看2019年的点赞数小于100的,或者评论小于100的书籍名称和价格
    models.Book.objects.filter(Q(zan__lt)=100|Q(comment__lt=100),date__year=2019)
    

    作业:

    1查询每个作者的姓名以及出版的书的最高价格
    models.Author.objects.values('name').annotate(m=Max('book__price'))
    models.Book.objects.values('author__name').annotate(m=Max('price'))
    2 查询作者id大于2作者的姓名以及出版的书的最高价格
    models.Author.objects.filter(id__gt=2).values('name').annotate(m=Max('book__price'))
    3 查询作者id大于2或者作者年龄大于等于20岁的女作者的姓名以及出版的书的最高价格
    models.Author.objects.filter(Q(sex='女')&Q(Q(id__gt=2)|Q(age__gte=20))).values('name').annotate(m=Max('book__price'))
    4查询每个作者出版的书的最高价格 的平均值
    models.Author.objects.annotate(m = Max('book__price')).aggregate(Avg('a'))
    5 每个作者出版的所有书的价格以及最高价格的那本书的名称 (通过orm玩起来就是个死题,需要用原生sql)
    models.Author.objects.values('name').annotate(m = Max('book__price'))
    models.Author.objects.values('name').annotate(m=)
    

    day62今日内容

    锁,事务
    
    ajax 
    
    cookie 和 session
    

    配置环境

    不是内置的py文件,

    外部脚本如何操作 Django

    if __name__ == '__main__':
        
        import os					# 配置Django的环境
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ormmysqlmanytables.settings")
        import django
    
        django.setup()	# 启动Django
    
        from Af_Pr import models  # 引入也要写在上面三句之后
    
        books = models.Book.objects.all()	
        print(books)
    

    template(内部过滤器) 已经配置了 找文件里基本都是用的反射

    今日的内容

    查询: 多个维度的查询 模糊匹配啊 各个字段  多条件搜索 也可以做
    

    任何的框架都必须有事务

    锁(mysql)

    myisam情况下

    表级锁:

    MySQL 两种:

    表共享读锁,阻塞写,不阻塞读

    表独占写锁,相反

    如何加表锁

    myisam

    在查的时候,会自动加读锁,

    在执行更新操作(update,delete,insert) ,自动加表写锁

     显示加锁:
          共享读锁:lock table tableName read;
          独占写锁:lock table tableName write;

    ​ 同时加多锁:lock table t1 write,t2 read;
          批量解锁:unlock tables;

    3.MyISAM表锁优化建议

    1查看表级锁的使用情况

    mysql> show status like 'table%';
    

     Table_locks_immediate:产生表级锁定的次数;
    Table_locks_waited:出现表级锁定争用而发生等待的次数;此值越高则说明存在着越严重的表级锁争用情况。此外,MyISAM的读写锁调度是写优先,这也是MyISAM不适合做写为主表的存储引擎。因为写锁后,其他线程不能做任何操作,大量的更新会使查询很难得到锁,从而造成永久阻塞。

    2缩短锁定时间

      如何让锁定时间尽可能的短呢?唯一的办法就是让我们的Query执行时间尽可能的短。
    a)尽两减少大的复杂Query,将复杂Query分拆成几个小的Query分布进行;
    b)尽可能的建立足够高效的索引,让数据检索更迅速;
    c)尽量让MyISAM存储引擎的表只存放必要的信息,控制字段类型;
    d)利用合适的机会优化MyISAM表数据文件 、

    3分离能并行的操作

    读写相互阻塞的表锁

    MyISAM的存储引擎还有一个非常有用的特性,那就是ConcurrentInsert(并发插入)的特性。
      MyISAM存储引擎有一个控制是否打开Concurrent Insert功能的参数选项:concurrent_insert,可以设置为0,1或者2。三个值的具体说明如下:
        concurrent_insert=2,无论MyISAM表中有没有空洞,都允许在表尾并发插入记录;
        concurrent_insert=1,如果MyISAM表中没有空洞(即表的中间没有被删除的行),MyISAM允许在一个进程读表的同时,另一个进程从表尾插入记录。这也是MySQL的默认设置;
        concurrent_insert=0,不允许并发插入。
      可以利用MyISAM存储引擎的并发插入特性,来解决应用中对同一表查询和插入的锁争用。例如,将concurrent_insert系统变量设为2,总是允许并发插入;同时,通过定期在系统空闲时段执行OPTIMIZE TABLE语句来整理空间碎片,收回因删除记录而产生的中间空洞。
    

    4 合理利用读写优先级

    默认写优先,

    但是可以设置优先级读SET LOW_PRIORITY_UPDATES=1

    或者读操作多了,阻塞多了,自动降低写操作的优先级

    Innodb

    InnoDB默认采用行锁,在未使用索引字段查询时升级为表锁。

    MySQL认为全表扫描效率更高,它就不会使用索引,这种情况下InnoDB将使用表锁,而不是行锁。因此,在分析锁冲突时,别忘了检查SQL的执行计划,以确认是否真正使用了索引。关于执行计划

    全表更新。事务需要更新大部分或全部数据,且表又比较大。若使用行锁,会导致事务执行效率低,从而可能造成其他事务长时间锁等待和更多的锁冲突。

    多表级联。事务涉及多个表,比较复杂的关联查询,很可能引起死锁,造成大量事务回滚。这种情况若能一次性锁定事务涉及的表,从而可以避免死锁、减少数据库因事务回滚带来的开销。

    三 行级锁定

    1.InnoDB锁定模式及实现机制

    可以说InnoDB的锁定模式实际上可以分为四种:共享锁(S),排他锁(X),意向共享锁(IS)和意向排他锁(IX),

    如果一个事务请求的锁模式与当前的锁兼容,InnoDB就将请求的锁授予该事务;反之,如果两者不兼容,该事务就要等待锁释放。

    2.InnoDB行锁实现方式

    InnoDB行锁是通过给索引上的索引项加锁来实现的,只有通过索引条件检索数据,InnoDB才使用行级锁

    (1)在不通过索引条件查询的时候,InnoDB确实使用的是表锁,而不是行锁。
    (2)由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。
    (3)当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论是使用主键索引、唯一索引或普通索引,InnoDB都会使用行锁来对数据加锁。
    (4)即便在条件中使用了索引字段,但是否使用索引来检索数据是由MySQL通过判断不同执行计划的代价来决定的,如果MySQL认为全表扫描效率更高,比如对一些很小的表,它就不会使用索引,这种情况下InnoDB将使用表锁,而不是行锁。因此,在分析锁冲突时,别忘了检查SQL的执行计划,以确认是否真正使用了索引。
    

    3.间隙锁(Next-Key锁)

    4.死锁

    5.什么时候使用表锁

    对于InnoDB表,在绝大部分情况下都应该使用行级锁,因为事务和行锁往往是我们之所以选择InnoDB表的理由】

    但在个别特殊事务中,也可以考虑使用表级锁:

    事务需要更新大部分或全部数据,表又比较大

    事务涉及多个表,比较复杂,很可能引起死锁,造成大量事务回滚。

    6.InnoDB行锁优化建议

      (1)要想合理利用InnoDB的行级锁定,做到扬长避短,我们必须做好以下工作:

          a)尽可能让所有的数据检索都通过索引来完成,从而避免InnoDB因为无法通过索引键加锁而升级为表级锁定;
          b)合理设计索引,让InnoDB在索引键上面加锁的时候尽可能准确,尽可能的缩小锁定范围,避免造成不必要的锁定而影响其他Query的执行;
          c)尽可能减少基于范围的数据检索过滤条件,避免因为间隙锁带来的负面影响而锁定了不该锁定的记录;
          d)尽量控制事务的大小,减少锁定的资源量和锁定时间长度;
          e)在业务环境允许的情况下,尽量使用较低级别的事务隔离,以减少MySQL因为实现事务隔离级别所带来的附加成本。
    

      (2)由于InnoDB的行级锁定和事务性,所以肯定会产生死锁,下面是一些比较常用的减少死锁产生概率的小建议:

          a)类似业务模块中,尽可能按照相同的访问顺序来访问,防止产生死锁;
          b)在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;
          c)对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率。
    

        (3)可以通过检查InnoDB_row_lock状态变量来分析系统上的行锁的争夺情况:

    四 查看死锁,解除锁

     结合上面对表锁和行锁的分析情况,解除正在死锁的状态有两种方法:

        第一种:

       1.查询是否锁表
    
            show OPEN TABLES where In_use > 0;
    
          2.查询进程(如果您有SUPER权限,您可以看到所有线程。否则,您只能看到您自己的线程)
    
            show processlist
    
          3.杀死进程id(就是上面命令的id列)
    
            kill id
    

      第二种:

     1.查看下在锁的事务 
    
            SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
    
          2.杀死进程id(就是上面命令的trx_mysql_thread_id列)
    
            kill 线程ID
    
      例子:
    
        查出死锁进程:SHOW PROCESSLIST
        杀掉进程          KILL 420821;
    
      其它关于查看死锁的命令:
    
        1:查看当前的事务
          SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
    
        2:查看当前锁定的事务
    
          SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
    
      3:查看当前等锁的事务
          SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
    

    超哥博客:https://www.cnblogs.com/clschao/articles/10463743.html

    事务

    原子性 : 要么全成功,要么全失败

    一致性 事务开始到结束的时间段内,数据都必须保持一致状态。

    持久性 :事务完成后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。

    隔离性 数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的"独立"环境执行

    1 全局开启setting里的

    databases里

    ​ 任何一个请求来了,都会被捆绑成一个事务

    ​ ‘ ATOMIC_REQUESTS ’ :True, #全局开启事务,绑定的是http请求响应整个过程

    ​ 一个sql语句就是一个事务

    ​ 'AUTOCOMMIT' : False , # 全局取消自动提交 , 慎用 默认自动提交

             "ATOMIC_REQUESTS": True, #全局开启事务,绑定的是http请求响应整个过程
            "AUTOCOMMIT":False, #全局取消自动提交,慎用
        },
     'other':{
        'ENGINE': 'django.db.backends.mysql', 
                ......
      } #还可以
    

    @transaction.non_atomic_requests(using='other') # 针对另外的数据库的事务限制

    other 指定另外的数据库

    事务里面有锁,sql语句+一个互斥锁= 排他锁,

    ​ 共享锁 = 可以改,不能看 (写锁) 排他是读锁吗

    ​ 事务 commit 别的可以用

    ​ 全局的用上下文的

    2 局部开启

    ​ 1 装饰器

    from django.db import transaction

    @transaction.atomic

    def viewfunc(request):

    2 上下文

    with transaction.atomic():

    ​ do_more_stuff()

    3 嵌套

    from django.db import transaction

    @transaction.atomic

    def viewfunc(request):

    with transaction.atomic():

    ​ do_more_stuff()

    Django

    select_for_update() # 查询 .filter(a='ss') # 给这条查询语句加锁了 互斥锁

    Ajax(为了用户体验)

    不换页面,保留数据

    异步的javascript 和 XML (提交数据的,效率高)请求 (偷偷摸摸的,各种其他操作不影响这个请求 异步 局部刷新)

    All 看所有的请求

    XHR 看Ajax请求 x http request

    ​ 以前的json

    现在流行的是json

    从圈变成x是sh刷新页面

    页面

    a
    
    src 
    
    输入网页			 --手动控制的网页
    
    form
    
    ajax               
    

    今日内容回顾

    事务
    全局	settings配置
    局部
    	视图函数装饰器的形式
    		@transaction.atomic
    		def view()...
    		
    	上下文的:
    		with transaction.atomic():
    			sql...
    			
    mysql 手动加锁
    select_for_update()
    select * from t1 for update
    models.T1.objects.select_for_update().filter(id=1)
     				# 手动加了,别人访问都不了	叫排查锁(互斥锁)
    共享锁 
    
    

    ajax

    异步发请求
    局部刷新
    jquery版的:
    $.ajax({
    	url:'目标地址',			模板渲染
    	type:'get',
    	success: function(response)	# ()里的内容:后端传过来的内容
    	{console.log(response)}各种dom操作
    })
    
    
    

    login.html

    {% csrf_token %}
    用户名:<input type="text" name="username" id="username">
    <input type="button" id="sub" value="提交">
    {#<span class="error"></span>#}
    {#<input type="text" id="d1">#}
    <div class="a1" > </div>
    <div class="a2" > </div>
    <div class="a3" > </div>
    <div class="a4" > </div>
    
    <script>
            var username = $('#username').val();
            var csrc_data = $('[name=csrfmiddlewaretoken]').val();
    
                    {#print(response)#}
       $('#sub').click(function () {
            $.ajax({
                url: '{% url "index" %}',
                type: 'post',
                data : {
                    uname:username,
                    csrfmiddlewaretoken:csrc_data,
                },
                success: function (response)
                {
                {#  alert(response);#}
                {# $('#d1').val( response );#}
                {#console.log(response);#}
                {#$('.tex').text(response);#}
                    {% for i in a  %}
                     $( '.{{ i }}').text(response);
                    {% endfor %}
                if(response==='a'){
                    alert('ok') }
                else{
                    $('.a4').text(data['uname'] ) }
                }
             }
                )
       })
    </script>
    

    view.py

    def login(request):
        a = ['a1','a2','a3']
        return render(request, 'login.html',locals())
    def index(request):
        username = request.POST.get('uname')
        print(username) #123
        status ='a'
        return HttpResponse(status)
    

    urls.py

        url(r'^login/',views.login,name='login'),
        url(r'^index/', views.index,name='index') ,
    
    DATABASES = {
        'default':{
            'ENGINE':'django.db.backends.mysql',
            'NAME':'day62',
            'USER':'root',
            'PASSWORD':'123',
            'HOST':'127.0.0.1' ,
            'PORT':3306
        }
    }
    
    
  • 相关阅读:
    [puppet]如何设置全局exec path
    noVNC配置小结
    [CloudOps]解决Windows系列镜像在Openstack上蓝屏
    解决 /usr/bin/env: php: No such file or directory
    构建一个多区域的公有云平台:Stacklab
    ssh自动添加hostkey到know_hosts
    A few thoughts about Open Source Software
    简单翻译:Understanding Linux Network Internals 2.2. net_device Structure
    近期小结
    [Music]《our love will always last》
  • 原文地址:https://www.cnblogs.com/Doner/p/10946945.html
Copyright © 2020-2023  润新知