orm常用的字段
AutoField 这个字段是代表我键的这个字段是自增的,而且里面必须要填priamry_key=True这个参数 CharField 这个就等于数据库里面的varchar()但它里面必须要填max_length这个参数来标识字符长度 IntegerField 是一个整数类型,范围在2147483648 to 2147483647。(一般不用它来存手机号(位数也不够),直接用字符串存,) DateField日期字段,里面有可以放参数,其中auto_now代表的是只要操作数据,其时间也会跟着变,auto_now_add代表的是只有创建的时候,才会创建时间,后面怎么改记录,时间都不会变,一般都是auto_now_add DecimalField()可以控制小数的,max_digits表示总共几位,decimal_places=表示小数占几位
字段中的参数
null 表示这个字段可以为空
unique 如果设置为true就跟数据库中一样,表示唯一
db_index 为true表示为该字段设置索引
default 设置默认值
DateField和DateTimeField
auto_now 表示数据修改,我的时间也会跟着修改
auto_now_add 表示只有数据在创建的时候,我的时间也会跟着创建,但后面数据怎么修改,我都不会变
关系字段ForeignKey
to 设置要关联的表
to_field 设置要建立的外键字段,不填,默认是和关联的表的主键建立外键字段
on_delete 表示当删除表中的数据的时候,其和关联的表的行为
on_constranit 是否在数据库中创建外键约束,默认是true
一对一
OnetoOneField
多对多
ManyToManyField
单表的增删改查
1.单表操作 create_time = models.DateField() 关键性的参数 1.auto_now:每次操作数据 都会自动刷新当前操作的时间 2.auto_now_add:在创建数据的时候 会自动将创建时间记录下来 后续的修改不会影响该字段
在django中我们可以自定义一个测试文件,在里面写测试脚本,不需要再视图操作模型表那么麻烦了
这样就可以直接运行你的test.py文件来运行测试
必知必会13条
all()查询出所有
filter(**kwargs):包含了所有与筛选条件匹配的对象,就是一个列表里面套对象,没有就是一个空
get是只获取一个也是对象本身,如果没有则会报错
exclude(**kwargs):取反,它包含了所有与筛选条件不匹配的内容
values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
order_by(*field): 对查询结果排序
reverse(): 对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)。
distinct(): 从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。)
first()表示返回匹配懂啊的第一个记录
last表示返回匹配到的最后一个记录
count(): 返回数据库中匹配查询(QuerySet)的对象数量。
exists(): 如果QuerySet包含数据,就返回True,否则返回False
总结:
返回queryset对象的有:
all()
filter()
exclude()
order_by()
reverse()
distinct()
特殊的queryset
value返回是一个字典序列
value_list返回是一个元祖序列
返回具体对象
get()
first()
last()
布尔值
exists()
返回数字的方法有
count()
Django打印sql语句有2种方式
一种是有约束的,就是queryset对象可以通过query这个方法查看相对应的sql语句
第二种是无限制的,只要你执行了表的语句,都会打印相应的sql语句,就是在settings中配置一下,具体如下:
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
神奇的双下划线用法:
原本我们查找是这样的 models.User.objects.filer(age=10) 现在我要求大于20的怎么弄呢,不能>,当有这种特殊的需求的时候,就要用到双下划线了 __gt 大于 __lt 小于 __gte 大于等于 __lte 小于等于 __in 代表在不在里面,一个集合 __range 是什么到什么的关系,也就是一个闭区间 模糊查询,也就是判断包含不包含 __contains 这个识别大写小写 __icontains 这个忽略大小写 —startswith这个判断以什么开头 __endswith 这个是以什么结尾 __year 按年查询
多表查询
一对多字段的增删改查
增: publish_id传数字 models.Book.objects.create(title='三国演义',price=189.99,publish_id=1) publish直接传出版社对象 publish_obj = models.Publish.objects.filter(pk=2).first() models.Book.objects.create(title='红楼梦',price=999.99,publish=publish_obj) 改 传数字的 models.Book.objects.filter(pk=1).update(publish_id=3) 传对象的 publish_obj = models.Publish.objects.filter(pk=2).first() models.Book.objects.filter(pk=1).update(publish=publish_obj) 删除 models.Publish.objects.filter(pk=2).delete() # 默认都是级联更新 级联删除
多对多增删改查
前提都是将要给增删改查的对象先找出来,然后再对象点那个虚拟字段后面跟方法来完成增删改查。 增 book_obj = models.Book.objects.filter(pk=1).first() print(book_obj.authors) # 对象点击多对多虚拟字段 会直接跨到多对多的第三张表 book_obj.authors.add(1) book_obj.authors.add(2,3) 支持多个传参 还支持弄对象 author_obj = models.Author.objects.filter(pk=1).first() author_obj1 = models.Author.objects.filter(pk=2).first() author_obj2 = models.Author.objects.filter(pk=3).first() book_obj.authors.add(author_obj) book_obj.authors.add(author_obj1,author_obj2) 小结: add() 是给书籍添加作者 括号内既可以传数字也可以传对象 并且支持一次性传多个 逗号隔开即可 改 book_obj = models.Book.objects.filter(pk=1).first() book_obj.authors.set([2,]) book_obj.authors.set([2,3]) author_obj = models.Author.objects.filter(pk=1).first() author_obj1 = models.Author.objects.filter(pk=2).first() author_obj2 = models.Author.objects.filter(pk=3).first() book_obj.authors.set([author_obj,]) book_obj.authors.set([author_obj, author_obj1, author_obj2]) 小结: set() 括号内必须是一个可迭代对象,可迭代对象里面可以是数字,也可以是对象,但记着不要混合用 删除 book_obj = models.Book.objects.filter(pk=1).first() book_obj.authors.remove(3) book_obj.authors.remove(1,2) author_obj = models.Author.objects.filter(pk=1).first() author_obj1 = models.Author.objects.filter(pk=2).first() author_obj2 = models.Author.objects.filter(pk=3).first() book_obj.authors.remove(author_obj) book_obj.authors.remove(author_obj1,author_obj2) 小结: remove()即支持数字,也支持对象,也可以传多个 将关系全部清空用clear()即可 book_obj.authors.clear()不用传参
跨表查询(重点!!!)
正向查询和反向查询(重点!!!)
正向与方向的概念解释 一对一 正向:author---关联字段在author表里--->authordetail 按字段 反向:authordetail---关联字段在author表里--->author 按表名小写 查询jason作者的手机号 正向查询 查询地址是 :山东 的作者名字 反向查询 一对多 正向:book---关联字段在book表里--->publish 按字段 反向:publish---关联字段在book表里--->book 按表名小写_set.all() 因为一个出版社对应着多个图书 多对多 正向:book---关联字段在book表里--->author 按字段 反向:author---关联字段在book表里--->book 按表名小写_set.all() 因为一个作者对应着多个图书
基于双下划线的跨表查询(连表查询,就不再2行代码了,而是一行了)
# 一对一 -连表查询 -一对一双下划线查询 -正向:按字段,跨表可以在filter,也可以在values中 -反向:按表名小写,跨表可以在filter,也可以在values中 # 查询jason作者的手机号 正向查询 跨表的话,按字段 # ret=Author.objects.filter(name='jason').values('authordetail__phone') # 以authordetail作为基表 反向查询,按表名小写 跨表的话,用表名小写 # ret=AuthorDetail.objects.filter(author__name='jason').values('phone') # 查询jason这个作者的性别和手机号 # 正向 # ret=Author.objects.filter(name='jason').values('sex','authordetail__phone') # 查询手机号是13888888的作者性别 # ret=Author.objects.filter(authordetail__phone='13888888').values('sex') # ret=AuthorDetail.objects.filter(phone='13888888').values('author__sex') """ 总结 其实你在查询的时候先把orm查询语句写出来,再看用到的条件是否在当前表内,在就直接获取,不在就按照正向按字段反向按表名来查即可 比如: 1.查询出版社为北方出版社的所有图书的名字和价格 res1 = Publish.objects.filter(name='').values('book__name','book__price') res2 = Book.objects.filter(publish__name='').values('name','price') 2.查询北方出版社出版的价格大于19的书 res1 = Publish.objects.filter(name='',book__price__gt=19).values('book__name','book__price) """
聚合查询
aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。 键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。 用到的内置函数: from django.db.models import Avg, Sum, Max, Min, Count 示例: >>> from django.db.models import Avg, Sum, Max, Min, Count >>> models.Book.objects.all().aggregate(Avg("price")) {'price__avg': 13.233333} 还可以为聚合函数指定一个名称 >>> models.Book.objects.aggregate(average_price=Avg('price')) {'average_price': 13.233333}
分组查询
from django.db.models import Avg res = models.Book.objects.annotate(别名=聚合函数).values(别名,其他内容) values是获取某个表中的某个字段
F与Q查询
F查询就是通过数据库获取某个字段对应的值
from django.db.models import F models.Book.objects.filter(priice=F(price)
Q查询就是修改查询的条件的。
from django.db.models import Q res = models.Book.objects.filter(title='三国演义',price=444.44) # filter只支持and关系 res1 = models.Book.objects.filter(Q(title='三国演义'),Q(price=444)) 如果用逗号 那么还是and关系 res2 = models.Book.objects.filter(Q(title='三国演义')|Q(price=444)) res3 = models.Book.objects.filter(~Q(title='三国演义')|Q(price=444))
高级Q用法
q = Q() q.connector = 'or' # 修改查询条件的关系 默认是and q.children.append(('title__contains','三国演义')) # 往列表中添加筛选条件 q.children.append(('price__gt',444)) # 往列表中添加筛选条件 res = models.Book.objects.filter(q) # filter支持你直接传q对象 但是默认还是and关系 print(res)
自定义Char字段
class MyChar(models.Field): def __init__(self,max_length,*args,**kwargs): self.max_length = max_length super().__init( max_length=max_length,*args,**kwargs ) def db_type(self, connection): return 'char(%s)'%self.max_length
查询优化
only 和 defer
这2个都是查出来是一个列表套对象,但不一样的是,only如果获取的是括号内指定的字段,会直接获取,如果获取的不是指定的字段,那么会频繁的访问数据库。而defer则正好相反,如果获取的是指定的字段,那么会频繁的访问数据库,如果不是指定的字段则是会直接获取。
select_related 和 prefect_related
都是做连表操作的。
括号内都只能放外键字段,并且可以连续用__连外键字段,并且只支持一对多核一对一。
不同处:select_related这个是直接连表,而prefect_related则是现将这个外键字段对应的id值拿到,然后再用这个id值去另外关联的表中找到一一对应的值。
注意:orm中的语句操作,全部都是惰性查询,就是只有在真正需要这个数据的时候,才会去访问数据库,减少数据库的压力
事务
from django.db import transaction with transaction.atomic(): """数据库操作 在该代码块中书写的操作 同属于一个事务 """ models.Book.objects.create() models.Publish.objects.create() # 添加书籍和出版社 就是同一个事务 要么一起成功要么一起失败 print('出了 代码块 事务就结束')