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
    }
}

posted @ 2019-05-29 23:07  learnacode  阅读(191)  评论(0编辑  收藏  举报