1.在python脚本中调用django环境
在根文件夹下,创建test.py文件
import os if __name__ == '__main__': os.environ.setdefault("DJANGO_SETTINGS_MODULE",'day76.settings') import django django.setup()
2.单表增删改查
-查询api <1> all(): 查询所有结果 <2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象 <3> get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。 注意:返回的是查找到的对象,不是queryset对象。 <4> exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象 <5> order_by(*field): 对查询结果排序('-id') <6> reverse(): 对查询结果反向排序 <8> count(): 返回数据库中匹配查询(QuerySet)的对象数量。 <9> first(): 返回第一条记录 <10> last(): 返回最后一条记录 <11> exists(): 如果QuerySet包含数据,就返回True,否则返回False <12> values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列 <13> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列 <14> distinct(): 从返回结果中剔除重复纪录
-基于双下划线的模糊查询 Book.objects.filter(price__in=[100,200,300]) Book.objects.filter(price__gt=100) Book.objects.filter(price__lt=100) Book.objects.filter(price__gte=100) Book.objects.filter(price__lte=100) Book.objects.filter(price__range=[100,200]) Book.objects.filter(title__contains="python") Book.objects.filter(title__icontains="python") Book.objects.filter(title__startswith="py") Book.objects.filter(pub_date__year=2012)
import os if __name__ == '__main__': os.environ.setdefault("DJANGO_SETTINGS_MODULE",'day76.settings') import django django.setup() from app01 import models import datetime #一、 增,插入数据的两种方式: #时间可以传字符串,也可以传日期格式 ctime=datetime.datetime.now() # 方式1: # book1=models.Book.objects.create(name='红楼梦',price=25.8,publish='南京出版社',author='曹雪芹',create_date=ctime) # print(book1.name) # 方式2:先实例化产生对象,然后调用save方法,保存 # book2=models.Book(name='西游记',price=65.5,publish='东京出版社',author='吴承恩',create_date='2018-05-05') # book2.save() # print(book2.name) #二、删 # 方式1: # ret=models.Book.objects.filter(name='西游记').delete()#ret是影响的行数,因为找到的对象是queryset,可能不止一个值 # print(ret) # 方式2: # models.Book.objects.filter(name='西游记').first().delete()#找到指定的对象,然后进行删除 # 三、修改 # models.Book.objects.filter(name='西游记').update(price=85)#这个修改的是queryset对象,可能有多个值 # book=models.Book.objects.filter(name='西游记').first()#这个修改的是找到的单个书对象,无法使用update方法 # book.price=50#找到对象,修改它的price值 # book.save()#然后进行保存 # 四、查询 # *******查询是重点******# ''' 1)all() 查询所有结果 2)filter(**kwargs) 包含了与所给筛选条件相匹配的对象 3)get(**kwargs) 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有,都会报错 4)exclude(**kwargs) 它包含了与所给筛选条件不匹配的对象 5)order_by(*field) 对查询结果排序 6)reverse() 对查询结果反向排序 8)count() 返回数据库中匹配查询(QuerySet)的对象数量 9)first() 返回第一条记录 10)last() 返回最后一条记录 11)exists() 如果queryset包含数据,就返回True,否则返回False 12)values(*field) 返回一个valuequeryset一个特殊的queryset,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列 13)values_list(*field) 它与vaule()非常相似,它返回的是一个元组序列,values返回的是一个字典序列 14)distinct() 从返回结果中剔除重复记录 基于双下划线的模糊查询 Book.objects.filter(price__in=[100,200,300]) Book.objects.filter(price__gt=100) Book.objects.filter(price__lt=100) Book.objects.filter(price__gte=100) Book.objects.filter(price__lte=100) Book.objects.filter(price__range=[100,200]) Book.objects.filter(title__contains="python") Book.objects.filter(title__icontains="python") Book.objects.filter(title__startswith="py") Book.objects.filter(pub_date__year=2012) ''' # all # ret=models.Book.objects.all()#查询所有 # print(ret) # ret=models.Book.objects.filter(name='西游记').first()#查询名字为西游记的第一个 # res=models.Book.objects.filter(name='西游记')[1]#查询名字为西游记的第二个,不支持负数 # print(ret,res) # filter可以传多个参数,用逗号分隔,他们之间是and关系 # ret=models.Book.objects.filter(name='西游记',price=50) # print(ret.query)#query是打印相关sql语句 # get # ret=models.Book.objects.get(name='三国演义')#使用get只在值只有一个时才能用,不然报错,返回的是对象,不是query对象。通常用id来查 # print(ret) # ret=models.Book.objects.get(id=1) # print(ret) # exclude # ret=models.Book.objects.exclude(name='西游记')#查询名字不叫西游记的书,结果也是queryset对象 # print(ret) # ret=models.Book.objects.exclude(name='西游记',price=50)#查询除了名字叫西游记且价格为50的以外的所有书 # print(ret) #order_by排序 # ret=models.Book.objects.order_by('price')#按价格升序排,也可以传多个 # print(ret) # ret=models.Book.objects.order_by('-price')#按价格降序排 # print(ret) #reverse倒序 # ret=models.Book.objects.order_by('price').reverse()#反向排序 # print(ret) #count查结果个数,返回数据库中匹配查询queryset的对象数量 # ret=models.Book.objects.all().count() # print(ret) # first和last第一个和最后一个 # ret=models.Book.objects.all().first() # res=models.Book.objects.all().last() # print(ret,res) #exists,返回结果是布尔类型 # ret=models.Book.objects.filter(name='python').exists() # print(ret) #values,里面包含了要查询的字段,如果不传值,则默认打印所有字段,返回的对象,里面有字典形式的数据 # res=models.Book.objects.filter(name='python').values() # ret=models.Book.objects.filter(name='红楼梦').values('name','price') # print(ret,res) #value_list与values非常相似,它返回的是一个元组序列,values返回的是一个字典序列 #distinct去重,只有都不一样才会去重,可以配合values使用 # ret=models.Book.objects.all().values('name').distinct() # print(ret) #基于双下划线的模糊查询 #__gt大于,__lt小于 # ret=models.Book.objects.filter(price__lt=40) # res=models.Book.objects.filter(price__gt=40) # print(ret,res) #__gte大于等于,__lte小于等于 # ret=models.Book.objects.filter(price__gte=85) # print(ret) # ret=models.Book.objects.filter(price__lte=50) # print(ret) #in 在某个选择范围中 # ret=models.Book.objects.filter(price__in=[50,85,60]) # print(ret) #range在某个区间中,是全闭区间(但是好像只有前后封闭的是整数才能取到) # ret=models.Book.objects.filter(price__range=[25,85]) # print(ret) #contains内容包含某个字符 # ret=models.Book.objects.filter(name__contains='p') # print(ret) #icontains忽略大小写 # ret=models.Book.objects.filter(name__icontains='P') # print(ret) #startwith以...开头 # ret=models.Book.objects.filter(name__startswith='p') # print(ret) #endswith以...结尾 # ret=models.Book.objects.filter(name__endswith='on') # print(ret) #pub_date__year查询某年的对象 # ret=models.Book.objects.filter(create_date__year=2015) # print(ret)
3.多表模型创建
OneToOneField要写to哪个表,to_filed=不写的话,默认是与id(一般是自增主键)相对应
ForeignKey要写to哪个表,to_filed=不写的话,默认是与id(一般是自增主键)相对应
创建唯一性约束时,要加上unique=True
sex_num=models.IntegerField(unique=True)
有时会创建联合唯一约束(这种情况多发生在两个字段分别关联外键),创建联合唯一约束有很多局限性,会降低查询性能。创建联合唯一约束的目的是为了不写脏数据
class UpAndDown(models.Model): nid = models.AutoField(primary_key=True) user = models.ForeignKey(to='UserInfo', to_field='nid') article = models.ForeignKey(to='Article', to_field='nid') is_up = models.BooleanField() class Meta: # 写这些,只是为了不写脏数据,联合唯一 unique_together = (('user', 'article'),)
from django.db import models # Create your models here. ''' 使用了OneToOneField和ForeignKey,模型表的字段,后面会自动加上_id ManyToManyField会自动创建第三张表 *****重点 一对一关系:OneToOneField 一对多关系:ForeignKey 多对多关系:ManyToManyField ''' class Publish(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=12) addr = models.CharField(max_length=64) email = models.EmailField(max_length=20) # email,实际上是varchar def __str__(self): return self.name class Author(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=12) sex = models.IntegerField() # 整型 # 可以用foreignkey,但是得设置唯一性约束,会报警告,不建议用 authordetail = models.OneToOneField(to='Authordetail', to_field='id') def __str__(self): return self.name class Authordetail(models.Model): id = models.AutoField(primary_key=True) phone = models.CharField(max_length=12) addr = models.CharField(max_length=64) def __str__(self): return self.id class Book(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=12) price = models.DecimalField(max_digits=5,decimal_places=1) publish=models.ForeignKey(to='Publish',to_field='id')#to表示关联哪张表,to_field表示关联哪个字段 authors=models.ManyToManyField(to='Author')#多对多会自动创建第三张表 def __str__(self): return self.name
4.多表增删改查
update在pycharm没有tab提示
注意多表的add,remove,set的用法
add绑定多对多关系
book.authors.add(1,4)可接对象或数字
book.authors.remove(1,2)可接对象或数字
book.authors.clear()清空被关联对象集合
book.author.set((1,4))先清空后设置,只能接一个参数,可以传列表,元组。
import os if __name__ == '__main__': os.environ.setdefault('DJANGO_SETTINGS_MODULE','day77.settings') import django django.setup() from app01.models import * #一对多新增数据 # 方式1: #外键输入id时,可以输字符串,也可以输数字 # ret=Book.objects.create(name='狼图腾',price=48.8,publish_id='2') # print(ret) # 方式2:存对象 # publish=Publish.objects.filter(name='北京出版社').first() # ret=Book.objects.create(name='花仙子',price=55.8,publish=publish) # print(ret) #一对多修改数据 # 方式1: # book=Book.objects.get(pk=1) # book.publish_id=3 # book.save() # 方式2:#publish既可以传数字,也可以传对象,但是为了使用起来看起来方便,还是publish对对象,publish_id对数字 # publish=Publish.objects.filter(id=3).first() # Book.objects.filter(id=1).update(publish=publish) #多对多关系 #add添加 #为西游记新增lqz作者 # book=Book.objects.filter(name='西游记').first() # book.authors.add(1,2)#可以直接添加数字 # author=Author.objects.filter(id=3).first() # book = Book.objects.filter(name='西游记').first() # book.authors.add(author)#也可以添加对象 #remove删除 # author = Author.objects.filter(id=3).first() # book = Book.objects.filter(name='西游记').first() # # book.authors.remove(1)#可以传数字 # book.authors.remove(author)#可以传对象,不要数字和对象混着用 #clear清除所有 # book = Book.objects.filter(name='西游记').first() # book.authors.clear() #set先清空再添加 # book = Book.objects.filter(name='西游记').first() # book.authors.set([1,3])#必须穿一个可迭代的数据,传列表就完事了。 #基于对象的跨表查询 #1.一对一 #正向查询 author--关联字段在author--authordetail--按字段 #反向 authordetail--关联字段在author--author--按表名小写 #查询作者lqz的手机号 #1)正向查 # ret=Author.objects.filter(name='lqz').first().authordetail.phone # print(ret) # ret=Author.objects.filter(name='lqz').first().authordetail.phone # print(ret) #2)反向查 查询地址为上海的作者名字 # authordetail=Authordetail.objects.filter(addr='上海').first() # author=authordetail.author # print(author.name) # res=Authordetail.objects.filter(author__name='lqz').first().phone # print(res) #2.一对多 # 正向: 正向查询按字段 #正向查询,查询西游记这本书的出版社邮箱 # ret=Book.objects.filter(name='西游记').first().publish.email # print(ret) # 反向: 反向按表名小写_set.all() #反向查询,查询地址是北京的出版社出版的图书 # ret=Book.objects.filter(publish__addr='北京') # print(ret) # publish=Publish.objects.filter(addr='北京').first() # books=publish.book_set.all()#一个出版社可以出版多个图书,是一个出版社对多个图书的关系,所以是publish.book_set.all() # print(books) #多对多 # 正向: 正向查询按字段 # 反向查询: 反向按表名小写_set.all() # ** ** ** 基于对象的查询, 多次查询(子查询) #正向查询西游记这本书所有的作者 # ret=Book.objects.filter(name='西游记').first().authors.all() # print(ret) #反向查询lqz写过的所有的书 # lqz=Author.objects.filter(name='lqz').first() # books=lqz.book_set.all() # print(books) #查询西游记这本书所有作者的手机号,基于对象的查询,多次查询(子查询) # authors=Book.objects.filter(name='西游记').first().authors.all() # for author in authors: # print(author.authordetail.phone) #基于双下划线的查询,连表查询 #一对一 #查询lqz作者的手机号 #以author表作为基表 正向查询,跨表的话按字段 # ret=Author.objects.filter(name='lqz').values('authordetail__phone') # print(ret) #以authordetail作为基表 反向查询,跨表的话,表名按小写 # ret=Authordetail.objects.filter(author__name='lqz').values('phone') # print(ret)
5.基于双下划线的增删改查
#基于双下划线的跨表查询 import os if __name__ == '__main__': os.environ.setdefault('DJANGO_SETTINGS_MODULE','day77.settings') import django django.setup() from app01.models import * #基于双下划线的一对多查询 #查询出版社为北京出版社的所有图书的名字 # ret=Publish.objects.filter(name='北京出版社').values('book__name','book__price') # print(ret) #查询北京出版社出版的价格大于19的书 # ret=Publish.objects.filter(name='北京出版社',book__price__gt=19).values('book__name') # print(ret) #多对多 #查询西游记的所有作者名字 # ret=Book.objects.filter(name='西游记').values('authors__name') # print(ret) #查询图书价格大于30的所有作者的名字 # ret=Book.objects.filter(price__gt=30).values('authors__name') # print(ret) #连续跨表 #查询北京出版社出版过的所有书籍的名字以及作者名字 # ret=Publish.objects.filter(name='北京出版社').values('book__name','book__authors__name') # print(ret)
只有查询到的结果是queryset对象时,才能打印queryset的query,也就是查询的sql语句
books = models.Book.objects.filter(authors__name='lqz') print(books.query)
6.聚合查询
使用聚合函数首先要导入相应模块
from django.db.models import Avg,Count,Max,Min,Sum
aggregate()是queryset的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。
简单记忆方法:聚合要父母agree,所以是aggregate函数
聚合查询查出的结果是字典
from django.db.models import Avg, Count, Max, Min, Sum #聚合查询,在mysql数据库不用做上下比较,从头到尾取完数据可以直接进行统计的用aggregate #使用聚合函数,Avg,Count,Max,Min,Sum等跨表查询可能不会智能提示, #计算所有图书的平均价格 # ret=Book.objects.all().aggregate(Avg('price')) # print(ret) #计算图书的最高价格和最低价格 # ret=Book.objects.all().aggregate(Max('price'),Min('price')) # print(ret)
7.分组查询
简单记忆方法:分组,分成一个一个的,是an,所以是annotate函数
以什么为分组,就以什么为基表开始查。
查询出的结果是queryset对象,里面有一大堆的字典
#分组查询,其实就是要在mysql做那种上下进行比较的筛选,这时候用annotate,也就是分组 #统计每一本书作者个数 # ret=Book.objects.all().annotate(c=Count('authors'))#意思是把所有书的对象筛选出来,然后算有多少个作者 # for r in ret: # print(r.c) # ret=Book.objects.all().annotate(c=Count('authors')).values('name','c')#不循环,直接取值 # print(ret) #统计每一个出版社的最便宜的书(以谁group by 就以谁为基表) # ret=Publish.objects.all().annotate(c=Min('book__price')).values('name','c') # print(ret) #统计每一本以py开头的书籍的作者个数 # ret=Book.objects.filter(name__startswith='py').annotate(c=Count('authors')).values('c') # print(ret.query) #总结 group by 谁,就以谁做基表,filter过滤,annotate去分组,values取值 #总结终极版本 #values在前,表示group by,再后表示取值(其实默认查询都会写values在前一次,group by的是id。) #filter在前,表示过滤(where),在后,表示having(对分组之后的结果再进行过滤) #统计每一本以py开头的书籍的作者个数(和上面的sql语句一样) # ret=Book.objects.all().values('pk').filter(name__startswith='py').annotate(c=Count('authors')).values('name','c') # print(ret.query) #查询每个作者出的书的总价格 # ret=Author.objects.all().values('id').annotate(c=Sum('book__price')).values('name','c') # print(ret) #查询写的书的总价格大于30的所有作者 # ret=Author.objects.all().annotate(c=Sum('book__price')).filter(c__gt=30).values('name','c') # print(ret)
8.F函数
F函数一般用于同一个对象的不同字段,其数据进行对比时,比如一本书的评论数大于阅读数,这时就需要用到F函数进行包裹一下。
#F函数 from django.db.models import F #为了字段=后面的值,不能放字段,所以用F函数包裹一下就可以了 #查询阅读数大于评论数的书 # ret=Book.objects.filter(read_num__gt=F('meat_num')) # print(ret) #把所有书的评论数加1 # Book.objects.all().update(read_num=F('read_num')+1) #把西游记这本书阅读数-5 # Book.objects.filter(name='西游记').update(read_num=F('read_num')-5)
9.Q函数
#Q函数 为了构造与&,或|,非~的关系 from django.db.models import Q #查询作者名字是lqz或egon的书 # book=Book.objects.filter(Q(authors__name='lqz')|Q(authors__name='egon')).distinct() # print(book) #查询作者不是lqz的书 # ret=Book.objects.filter(~Q(authors__name='lqz')) # print(ret)
10.ORM字段参数
null 可以为空
unique 唯一性约束
default 默认值
db_index 为该字段建索引
只给日期型和时间型用
auto_now_add 新增数据时,默认把当前时间存入
auto_now 修改的时候,默认把当前时间存入
related_name 反向操作时,使用的字段名,用于代替原反向查询时的'表名_set'(一般情况下不用)
11.元信息
在models里建表时,可以在表里定义一个Meta类,里面封装了一些数据库的信息,主要字段如下:
db_table ORM在数据库中的表名默认是app_类名,可以通过db_table可以重写表名
index_together 联合索引
unique_together 联合唯一索引
ordering 指定默认按什么字段排序
class Test(models.Model): name=models.CharField(max_length=12) class Meta: db_table='test'
12.choice
前面在建表时,在作者表,有一项是性别,1是男,2是女。在不数据库不怎么变动,这种映射关系不改变的情况下,可以使用choice
class Author(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=32) mychoice=((1,'男'),(2,'女')) sex = models.IntegerField(choices=mychoice) addr = models.CharField(max_length=64) authordetail = models.OneToOneField(to='AuthorDetail', to_field='id', null=True) def __str__(self): return self.name
这时候,当想要在取值时,直接打印出男女性别结果时,可以使用get_sex_display()的方法。注意,是查到的对象调用get_sex_display()方法,不是queryset调用get_sex_display()方法.
if __name__ == '__main__': os.environ.setdefault('DJANGO_SETTINGS_MODULE','ff12.settings') import django django.setup() from app01 import models author=models.Author.objects.filter(pk=3).first() author2=models.Author.objects.filter(pk=1).first() print(author.get_sex_display()) print(author2.get_sex_display())
注意,当取的值,比如sex是3,没有相应男女关系映射时,这时候直接显示的是3。如果取的值有相应男女关系映射时,比如sex是1,则显示“男”。
当然,还有一种方法是做外键关联,另一张表写上“男”“女”。这样在取值时,可以去这张表进行查。只是在这里不太适合,在这里性别选项不会再多出变动,所以可以直接在数据库用choice选项。遇到其他情况,比如说VIP1-VIP10,金牌VIP,钻石VIP等等这种比较复杂的关系映射,甚至还有可能会进行变更的情况,这种情况下建议用外键关联而不是用choice。
13.only
需求:一个表有很多很多个字段,如果只要其中的一两个字段,name,我们只需要取出这一两个字段就可以了,效率会提升
import os if __name__ == '__main__': os.environ.setdefault('DJANGO_SETTINGS_MODULE','ff12.settings') import django django.setup() from app01 import models ret=models.Book.objects.all().only('name') print(ret) print(ret[0]) print(ret.first().price)
这么做的原因是为了优化sql查询,减轻mysql服务器的压力。
defer:除了指定之外的其他字段的所有值。同样查出来的也是存放在queryset中的对象
import os if __name__ == '__main__': os.environ.setdefault('DJANGO_SETTINGS_MODULE','ff12.settings') import django django.setup() from app01 import models ret=models.Book.objects.all().defer('name') print(ret) print(ret[0].price)
14.手动创建第三张表
自动创建第三张表使用manytomany的方法的话,字段无法自己定制,甚至连插数据都找不到表。因此有了自己手动创建第三张表,根据业务需要进行自行定制相应字段等。
class Book(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) pub_date = models.DateTimeField() publish = models.ForeignKey(to='Publish', to_field='id') #to是和哪张表进行关联,through是手动创建的第三张表,through_fields是关联的字段,通过author向book字段进行关联(可以理解为author是自身上看不见的一个字段) author = models.ManyToManyField(to='Author',through='Book2Author',through_fields=('book','author')) def __str__(self): return self.name class Book2Author(models.Model): id=models.AutoField(primary_key=True) book=models.ForeignKey(to='Book',to_field='id') author=models.ForeignKey(to='Author',to_field='id') test=models.CharField(max_length=32) class Author(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=32) mychoice = ((1, '男'), (2, '女')) sex = models.IntegerField(choices=mychoice) addr = models.CharField(max_length=64) authordetail = models.OneToOneField(to='AuthorDetail', to_field='id', null=True) def __str__(self): return self.name
这时,再进行要帮书籍添加作者时,则需要调用第三张表
import os if __name__ == '__main__': os.environ.setdefault('DJANGO_SETTINGS_MODULE','ff12.settings') import django django.setup() from app01 import models book=models.Book.objects.filter(pk=1).first() models.Book2Author.objects.create(test='haha',book_id=1,author_id=3)
15.建表可以选择DateField和DateTimeField
视业务需求而定
DateField可以选择用filter(pub_date='2018-12-12')这种形式去过滤
但是DateTimeField则不行,因为DateTimeField带了时分秒。
所以DateTimeField可以用filter(pub_date__day='28')
前端<input type='date'>传过来的时间带了时分秒?
16删除
级联删除:可以近似的把它理解成一个触发器,主表数据没了,外键关联部分也会跟着一起删除
publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
17.当models配置了choice选项时,显示其文字信息
# 固定用法:get_字段名字_display() user_type_name = request.user.get_user_type_display()