ORM常用字段及方式
创建小型数据库
模型层
ORM常用字段
AutoField
int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。
IntegerField
一个整数类型,范围在 -2147483648 to 2147483647。(一般不用它来存手机号(位数也不够),直接用字符串存,)
CharField
字符类型,必须提供max_length参数, max_length表示字符长度。
DateField
日期字段,日期格式 YYYY-MM-DD,相当于Python中的datetime.date()实例。
DateTimeField
日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例。
class User(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
register_time = models.DateField()
- 字段的参数
null
用于表示某个字段可以为空。
unique
如果设置为unique=True 则该字段在此表中必须是唯一的 。
db_index
如果db_index=True 则代表着为此字段设置索引。
default
为该字段设置默认值。
2.DateField和DateTimeField
auto_now_add
配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。
auto_now
配置上auto_now=True,每次更新数据记录的时候会更新该字段。
关系字段
ForeignKey
外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 '一对多'中'多'的一方。
ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。
字段参数
to
设置要关联的表
to_field
设置要关联的表的字段
on_delete
当删除关联表中的数据时,当前表与其关联的行的行为。
models.CASCADE
删除关联数据,与之关联也删除
db_constraint
是否在数据库中创建外键约束,默认为True。
OneToOneField
一对一字段。
通常一对一字段用来扩展已有字段。(通俗的说就是一个人的所有信息不是放在一张表里面的,简单的信息一张表,隐私的信息另一张表,之间通过一对一外键关联)
字段参数
to
设置要关联的表。
to_field
设置要关联的字段。
on_delete
当删除关联表中的数据时,当前表与其关联的行的行为。(参考下面的例子)
ef func():
return 10 class MyModel(models.Model):
user = models.ForeignKey(
to="User",
to_field="id",
on_delete=models.SET(func)
)
返回QuerySet对象的方法有
all() filter() exclude() order_by() reverse() distinct() 特殊的QuerySet
values() 返回一个可迭代的字典序列 values_list() 返回一个可迭代的元祖序列 返回具体对象的
get() first() last() 返回布尔值的方法有:
exists() 返回数字的方法有
count()
操作小总结
单表查询操作演示表
# 单表查询表
class User(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
register_time = models.DateField() def __str__(self):
return '对象的名字:%s'%self.name
# 新增数据
# 基于create创建
# user_obj = models.User.objects.create(name='tank',age=73,register_time='2019-2-14')
# print(user_obj.register_time)
# 基于对象的绑定方法创建
# user_obj = models.User(name='kevin',age=30,register_time='2019-1-1')
# user_obj.save()
# from datetime import datetime
# ctime = datetime.now()
# models.User.objects.create(name='egon', age=18, register_time=ctime) # 修改数据
# 基于对象
# user_obj = models.User.objects.filter(name='jason').first()
# user_obj.age = 17
# user_obj.save()
# 基于queryset
# models.User.objects.filter(name='kevin').update(age=66) # 删除数据
# 基于queryset
# models.User.objects.filter(name='egon').delete()
# 基于对象
# user_obj = models.User.objects.filter(name='owen').first()
# user_obj.delete() # 查询数据
# < 1 > all(): 查询所有结果 # < 2 > filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
# res = models.User.objects.filter(name='jason',age=17)
# filter内可以放多个限制条件但是需要注意的是多个条件之间是and关系
# print(res) # < 3 > get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。(源码就去搂一眼~诠释为何只能是一个对象)
# 不推荐使用 # < 4 > exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
# res = models.User.objects.exclude(name='jason')
# print(res)
# < 5 > order_by(*field): 对查询结果排序('-id') / ('price')
# res = models.User.objects.order_by('age') # 默认是升序
# res = models.User.objects.order_by('-age') # 可以在排序的字段前面加一个减号就是降序
# res = models.User.objects.order_by('name')
# res = models.User.objects.order_by('-name')
# print(res) # < 6 > reverse(): 对查询结果反向排序 >> > 前面要先有排序才能反向
# res = models.User.objects.order_by('age').reverse()
# print(res) # < 7 > count(): 返回数据库中匹配查询(QuerySet) 的对象数量。
# res = models.User.objects.count()
# res = models.User.objects.all().count()
# print(res) # < 8 > first(): 返回第一条记录
# res = models.User.objects.all().first()
# res = models.User.objects.all()[0] # 不支持负数的索引取值
# print(res) # < 9 > last(): 返回最后一条记录
# res = models.User.objects.all().last()
# print(res) # < 10 > exists(): 如果QuerySet包含数据,就返回True,否则返回False
# res = models.User.objects.all().exists()
# res1 = models.User.objects.filter(name='jason',age=3).exists()
# print(res,res1) # < 11 > values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
# model的实例化对象,而是一个可迭代的字典序列
# res = models.User.objects.values('name') # 列表套字典
# res = models.User.objects.values('name','age') # 列表套字典
# print(res) # < 12 > values_list(*field): 它与values()
# 非常相似,它返回的是一个元组序列,values返回的是一个字典序列
# res = models.User.objects.values_list('name','age') # 列表套元祖
# print(res) # < 13 > distinct(): 从返回结果中剔除重复纪录 去重的对象必须是完全相同的数据才能去重
# res = models.User.objects.values('name','age').distinct()
# print(res) # 神奇的双下划线查询 # 查询年轻大于44岁的用户
# res = models.User.objects.filter(age__gt=44)
# print(res)
# 查询年轻小于44岁的用户
# res = models.User.objects.filter(age__lt=44)
# print(res)
# 查询年轻大于等于44岁的用户
# res = models.User.objects.filter(age__gte=44)
# print(res)
# 查询年轻小于等于44岁的用户
# res = models.User.objects.filter(age__lte=44)
# print(res) # 查询年龄是44或者22或者73的用户
# res = models.User.objects.filter(age__in=[44,22,73])
# print(res) # 查询年龄在22到44范围内
# res = models.User.objects.filter(age__range=[22,44])
# print(res) # 用的是mysql数据库
# 查询年份
# res = models.Book.objects.filter(publish_date__year=2019)
# print(res) # 查询名字中包含字母n的用户 sqlite数据库演示不出来大小写的情况!!!
# res = models.Author.objects.filter(name__contains='n')
# res = models.Author.objects.filter(name__icontains='n')
# print(res)
# res = models.User.objects.filter(name__icontains='e') # 无视大小写
# print(res) # 查询名字以j开头的用户
# res = models.User.objects.filter(name__startswith='j')
# print(res)
# 查询名字以n结尾的用户
# res = models.User.objects.filter(name__endswith='n')
# print(res) # 查询注册是在2017年的用户
# res = models.User.objects.filter(register_time__year=2017) # sqlite对日期格式不太精准
# print(res)
单表查询操作演示表2
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_place=2)
publish = models.CharField(max_length=32)
author = models.CharField(max_length=32)
create_time = models.DateField(null=True)
# 配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。
# 配置上auto_now=True,每次更新数据记录的时候会更新该字段。
新增数据 # 第一种:有返回值,并且就是当前被创建的数据对象
modles.Book.objects.create(name='',price='',publish='',author='',create_time='2019-5-1')
# 第二种:先实例化产生对象,然后调用save方法保存
book_obj = models.Book(name='',price='',publish='',author='',create_time='2019-5-1')
book_obj.save()
# 2.验证时间格式字段即可以传字符串也可以传时间对象
import datetime
ctime = datetime.datetime.now()
book = models.Book.objects.create(name='',price='',author='',create_time=ctime) 删除数据 """删除数据"""
# 1.删除书名为xxx的这本书 queryset方法
res = models.Book.objects.filter(name='').delete()
print(res)
# 2.删除书名为xxx的这本书 queryset方法
res = models.Book.objects.filter(name='').first()
res.delete() 修改数据 # 1.queryset修改
models.Book.objects.filter(name='').update(price='')
# 2.对象修改
book = models.Book.objects.filter(name='').first()
book.price = 66.66
book.save() # 对象只有保存方法 这样也能实现修改需求 查询数据 <1> all(): 查询所有结果
<2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
<3> get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。(源码就去搂一眼~诠释为何只能是一个对象)
<4> exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
<5> order_by(*field): 对查询结果排序('-id')/('price') <6> reverse(): 对查询结果反向排序 >>>前面要先有排序才能反向
<7> count(): 返回数据库中匹配查询(QuerySet)的对象数量。
<8> first(): 返回第一条记录
<9> last(): 返回最后一条记录
<10> exists(): 如果QuerySet包含数据,就返回True,否则返回False
<11> values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列
<12> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
<13> distinct(): 从返回结果中剔除重复纪录
# *******************
# 必须完全一样才可以去重(意味着带了id就没有意义了)
# res = models.Book.objects.all().values('name').distinct() 先查一个重复的值再去重 基于双下划线的查询 # 价格 大于 小于 大于等于 小于等于
filter(price__gt='')
filter(price__lt='')
filter(price_gte='')
filter(price_lte='') # 存在与某几个条件中
filter(price__in=['','',''])
# 在某个范围内
filter(price__range=[50,90]) # 模糊查询
filter(title__contains='西')
filter(title__icontains='P') # 以什么开头 以什么结尾 # 按年查询
filter(create_time__year='')
多表查询操作演示表
# 多表查询表
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2)
publish_date = models.DateField(auto_now_add=True)
# 外键关系
publish = models.ForeignKey(to='Publish')
authors = models.ManyToManyField(to='Author') # 虚拟字段, 信号字段 def __str__(self):
return '书籍对象的名字:%s'%self.title class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
email = models.EmailField() # 对应就是varchar类型 def __str__(self):
return '出版社对象的名字:%s'%self.name class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
authordetail = models.OneToOneField(to='AuthorDetail') def __str__(self):
return '作者对象的名字:%s'%self.name class AuthorDetail(models.Model):
phone = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
# 多表查询
# 新增
# 直接写id
# models.Book.objects.create(title='红楼梦',price=66.66,publish_id=1)
# 传数据对象
# publish_obj = models.Publish.objects.filter(pk=2).first()
# models.Book.objects.create(title='三国演义',price=199.99,publish=publish_obj) # 修改
# queryset修改
# 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)
# 对象修改
# book_obj = models.Book.objects.filter(pk=1).first()
# book_obj.publish_id = 3 # 点表中真实存在的字段名
# book_obj.save()
# publish_obj = models.Publish.objects.filter(pk=2).first()
# book_obj.publish = publish_obj # 点orm中字段名 传该字段对应的表的数据对象
# book_obj.save() # 删除
# models.Book.objects.filter(pk=1).delete()
# models.Publish.objects.filter(pk=1).delete() # book_obj = models.Book.objects.filter(pk=3).first()
# book_obj.delete() # 给书籍绑定与作者之间的关系
# 添加关系 add:add支持传数字或对象,并且都可以传多个
# book_obj = models.Book.objects.filter(pk=3).first()
# # 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=3).first()
# # book_obj.authors.add(author_obj)
# book_obj.authors.add(author_obj,author_obj1) # 修改书籍与作者的关系 set() set传的必须是可迭代对象!!!
# book_obj = models.Book.objects.filter(pk=3).first()
# 可以传数字和对象,并且支持传多个
# book_obj.authors.set((1,))
# book_obj.authors.set((1,2,3))
#
# author_list = models.Author.objects.all()
# book_obj = models.Book.objects.filter(pk=3).first()
# book_obj.authors.set(author_list) # 删除书籍与作者的绑定关系
# book_obj = models.Book.objects.filter(pk=3).first()
# # book_obj.authors.remove(1)
# # book_obj.authors.remove(2,3)
# # author_obj = models.Author.objects.all().first()
# author_list = models.Author.objects.all()
# # book_obj.authors.remove(author_obj)
# book_obj.authors.remove(*author_list) # 需要将queryset打散 # 清空 clear() 清空的是你当前这个表记录对应的绑定关系
# book_obj = models.Book.objects.filter(pk=3).first()
# book_obj.authors.clear() # 基于对象的表查询
# 正向
# 查询书籍是三国演义的出版社邮箱
# book_obj = models.Book.objects.filter(title='三国演义').first()
# print(book_obj.publish.email)
# 查询书籍是小王子的作者的姓名
# book_obj = models.Book.objects.filter(title='小王子').first()
# print(book_obj.authors) # app01.Author.None
# print(book_obj.authors.all())
# 查询作者为jason电话号码
# user_obj = models.Author.objects.filter(name='jason').first()
# print(user_obj.authordetail.phone) # 反向
# 查询出版社是东方出版社出版的书籍 一对多字段的反向查询
# publish_obj = models.Publish.objects.filter(name='东方出版社').first()
# print(publish_obj.book_set) # app01.Book.None
# print(publish_obj.book_set.all()) # 查询作者jason写过的所有的书 多对多字段的反向查询
# author_obj = models.Author.objects.filter(name='jason').first()
# print(author_obj.book_set) # app01.Book.None
# print(author_obj.book_set.all()) # 查询作者电话号码是110的作者姓名 一对一字段的反向查询
# authordetail_obj = models.AuthorDetail.objects.filter(phone=110).first()
# print(authordetail_obj.author.name) # 基于双下滑线的查询
# 正向
# 查询书籍为三国演义的出版社地址
# res = models.Book.objects.filter(title='三国演义').values('publish__addr','title')
# print(res)
# 查询书籍为小王子的作者的姓名
# res = models.Book.objects.filter(title='小王子').values("authors__name",'title')
# print(res)
# 查询作者为jason的家乡
# res = models.Author.objects.filter(name='jason').values('authordetail__addr')
# print(res) # 反向
# 查询南方出版社出版的书名
# res = models.Publish.objects.filter(name='南方出版社').values('book__title')
# print(res)
# 查询电话号码为120的作者姓名
# res = models.AuthorDetail.objects.filter(phone=120).values('author__name')
# print(res)
# 查询作者为jason的写的书的名字
# res = models.Author.objects.filter(name='jason').values('book__title')
# print(res)
# 查询书籍为三国演义的作者的电话号码
# res = models.Book.objects.filter(title='三国演义').values('authors__authordetail__phone')
# print(res) # 查询jason作者的手机号
# 正向
# res = models.Author.objects.filter(name='jason').values('authordetail__phone')
# print(res)
# 反向
# res = models.AuthorDetail.objects.filter(author__name='jason').values('phone')
# print(res) # 查询出版社为东方出版社的所有图书的名字和价格
# 正向
# res = models.Publish.objects.filter(name='东方出版社').values('book__title','book__price')
# print(res)
# 反向
# res = models.Book.objects.filter(publish__name='东方出版社').values('title','price')
# print(res) # 查询东方出版社出版的价格大于400的书
# 正向
# res = models.Publish.objects.filter(name="东方出版社",book__price__gt=400).values('book__title','book__price')
# print(res)
# 反向
# res = models.Book.objects.filter(price__gt=400,publish__name='东方出版社').values('title','price')
# print(res) # 聚合查询 aggregate
from django.db.models import Max,Min,Count,Sum,Avg
# 查询所有书籍的作者个数
# res = models.Book.objects.filter(pk=3).aggregate(count_num=Count('authors'))
# print(res)
# 查询所有出版社出版的书的平均价格
# res = models.Publish.objects.aggregate(avg_price=Avg('book__price'))
# print(res) # 4498.636
# 统计东方出版社出版的书籍的个数
# res = models.Publish.objects.filter(name='东方出版社').aggregate(count_num=Count('book__id'))
# print(res) # 分组查询(group_by) annotate
# 统计每个出版社出版的书的平均价格
# res = models.Publish.objects.annotate(avg_price=Avg('book__price')).values('name','avg_price')
# print(res)
# 统计每一本书的作者个数
# res = models.Book.objects.annotate(count_num=Count('authors')).values('title','count_num')
# print(res)
# 统计出每个出版社卖的最便宜的书的价格
# res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price')
# print(res)
# 查询每个作者出的书的总价格
# res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price')
# print(res)
创建图书管理系统表(给作者表加一张作者详情表为了一对一的查询),诠释一对一关联其实就是外健关联再加一个唯一性约束而已
ForeignKey(unique=Ture) >>> OneToOneField()
# 即一对一可以用ForeignKey来做,但是需要设唯一性约束并且会报警告信息,不建议使用,建议用OneToOneField
# 用了OneToOneField和用ForeignKey会自动在字段后面加_id
# 用了ManyToMany会自动创建第三张表
一对多的书籍记录增删改查
# 针对外键关联的字段 两种添加方式
# 第一种通过publish_id
# 第二种通过publish传出版社对象
# 删除书籍直接查询删除即可,删除出版社会级联删除
# 编辑数据也是两种对应的方式(对象点的方式(这里能点publish和publish_id)最后点save(),queryset方式update())
多对多的书籍与作者的增删改查
"""前提:先获取书籍对象,再通过书籍对象点authors来进行书籍作者的增删改查"""
# 1.给书籍新增作者add
# 1.add可以传作者id,也可以直接传作者对象,并且支持传多个位置参数(不要混着用)
# 2.给书籍删除作者remove
# 1.remove同样可以传id,对象,并且支持传多个位置参数(不要混着用)
# 3.直接清空书籍对象所有的作者数据clear()不用传任何参数
# 4.修改书籍对象所关联的作者信息set,注意点set括号内必须传可迭代对象,里面可以传id,对象
"""总结:一对多增删改,多对多add,remove,clear,set"""
正向反向概念
# 正向与方向的概念解释
# 一对一
# 正向:author---关联字段在author表里--->authordetail 按字段
# 反向:authordetail---关联字段在author表里--->author 按表名小写
# 查询jason作者的手机号 正向查询
# 查询地址是 :山东 的作者名字 反向查询
# 一对多
# 正向:book---关联字段在book表里--->publish 按字段
# 反向:publish---关联字段在book表里--->book 按表名小写_set.all() 因为一个出版社对应着多个图书
# 多对多
# 正向:book---关联字段在book表里--->author 按字段
# 反向:author---关联字段在book表里--->book 按表名小写_set.all() 因为一个作者对应着多个图书
# 连续跨表
# 查询图书是三国演义的作者的手机号,先查书,再正向查到作者,在正向查手机号
# 总结:基于对象的查询都是子查询,这里可以用django配置文件自动打印sql语句的配置做演示
基于双下划线的查询
# 一对一
-连表查询
-一对一双下划线查询
-正向:按字段,跨表可以在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)
"""
再次强调:
- 对于所有类型的关联字段,add()、create()、remove()和clear(),set()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用save()方法。
聚合查询和分组查询
聚合(利用聚合函数)
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}
如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:
>>> models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price"))
{'price__avg': 13.233333, 'price__max': Decimal('19.90'), 'price__min': Decimal('9.90')}
分组
我们在这里先复习一下SQL语句的分组。
假设现在有一张公司职员表:
我们使用原生SQL语句,按照部分分组求平均工资:
select dept,AVG(salary) from employee group by dept;
ORM查询:
from django.db.models import Avg
Employee.objects.values("dept").annotate(avg=Avg("salary").values(dept, "avg")
这里需要注意的是annotate分组依据就是他前面的值,
如果前面没有特点的字段,则默认按照ID分组,
这里有dept字段,所以按照dept字段分组
连表查询的分组:
SQL查询:
select dept.name,AVG(salary) from employee inner join dept on (employee.dept_id=dept.id) group by dept_id;
ORM查询:
from django.db.models import Avg
models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")
更多示例:
示例1:统计每一本书的作者个数
>>> book_list = models.Book.objects.all().annotate(author_num=Count("author"))
>>> for obj in book_list:
... print(obj.author_num)
...
1
示例2:统计出每个出版社买的最便宜的书的价格
>>> publisher_list = models.Publisher.objects.annotate(min_price=Min("book__price"))
>>> for obj in publisher_list:
... print(obj.min_price)
...
9.90
19.90
方法二:
>>> models.Book.objects.values("publisher__name").annotate(min_price=Min("price"))
<QuerySet [{'publisher__name': '沙河出版社', 'min_price': Decimal('9.90')}, {'publisher__name': '人民出版社', 'min_price': Decimal('19.90')}]>
示例3:统计不止一个作者的图书
>>> models.Book.objects.annotate(author_num=Count("author")).filter(author_num__gt=1)
<QuerySet [<Book: 番茄物语>]>
示例4:根据一本图书作者数量的多少对查询集 QuerySet进行排序
>>> models.Book.objects.annotate(author_num=Count("author")).order_by("author_num")
<QuerySet [<Book: 香蕉物语>, <Book: 橘子物语>, <Book: 番茄物语>]>
示例5:查询各个作者出的书的总价格
>>> models.Author.objects.annotate(sum_price=Sum("book__price")).values("name", "sum_price")
<QuerySet [{'name': '小精灵', 'sum_price': Decimal('9.90')}, {'name': '小仙女', 'sum_price': Decimal('29.80')}, {'name': '小魔女', 'sum_price': Decimal('9.90')}]>
总结
value里面的参数对应的是sql语句中的select要查找显示的字段,
filter里面的参数相当于where或者having里面的筛选条件
annotate本身表示group by的作用,前面找寻分组依据,内部放置显示可能用到的聚合运算式,后面跟filter来增加限制条件,最后的value来表示分组后想要查找的字段值
最后的小总结
模型层ORM
ORM操作
class User(models.Model):
name = models.CharField(max_length=32)
... def save(self):
# 在对象调用save保存到数据库之前,在这里可以拦截进行相应的操作
super().save() def delete(self):
# 在对象调用delete删除数据之前,在这里可以拦截进行相应的操作
super().delete() 单表操作
增
# 方式1:
user_obj = models.User.objects.create(**kwargs) # 注意create方法有返回值,并且就是新建数据对象本身
# 方式2:
user_obj = models.User(**kwargs)
user_obj.save()
查
models.User.objects.filter(**kwargs) # 多个过滤条件是and关系
models.User.objects.get() # 不推荐使用
models.User.objects.all() # 惰性查询
改
models.User.objects.filter(**kwargs).update(**kwargs) # 批量更新 user_obj = models.User.objects.filter(**kwargs).first()
user_obj.name = 'jason'
user_obj.save()
user_obj.update() # 对象没有点update的方法
删
models.User.objects.filter(**kwargs).delete() # 批量删除 user_obj = models.User.objects.filter(**kwargs).first()
user_obj.delete() 多表操作
如何确立表关系:
一个A能否有多个B
一个B能否有对个A 如果两者都能那么就是 多对多
如果只有一方可以 一对多
如果双方都不可以但是两者却有关系 一对一 表关系:
一对一(OneToOneField):无论建在哪一方都可以,但是推荐建在查询频率较高的一方
一对多(ForeignKey):建在多的那一方
多对多(ManyToManyField):无论建在哪一方都可以,但是推荐建在查询频率较高的一方 外键字段的增删改查
一对多字段的增删改查(publish)
增
models.Book.objects.create(publish_id=1) publish_obj = models.Publish.objects.filter(pk=1).first()
models.Book.objects.create(publish=publish_obj) 改
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.publish = new_publish_obj book_obj = models.Book.objects.filter(pk=1).update(publish_id=2)
book_obj = models.Book.objects.filter(pk=1).update(publish=publish_obj) 删
删除书籍正常删除
删除出版社那么会级联删除改出版社对应的所有的书籍 多对多字段增删改查
增
add()
改
set()
删
remove() # 上面三个方法都可以支持传多个数字或对象,set必须接收一个可迭代对象
清空
clear()
跨表表查询
正向反向
关联字段在你当前这表查询另一张叫正向
关联字段不在你当前这表查询另一张叫反向
总结:正向查询按字段,反向查询按表名小写(******) # 基于对象的跨表查询(子查询)
# 基于双下划线的跨表查询(联表查询) 基于对象
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.publish.addr
book_obj.publish.name
book_obj.authors.all() publish_obj = models.Publish.objects.filter(pk=1).first()
publish_obj.book_set.all() 基于双下划线的跨表查询
res = models.Book.objects.filter(publish__name='东方出版社',title='小王子').values('title','publish__name','authors__authordetail__phone') settings文件配置
直接拷贝使用即可 queryset对象.query也能够查看内部对应的sql语句
all()
filter()
values()
value_list()
order_by()
reverse()
distinct()
exclude() count() 计数
exists() 布尔值
get() 数据对象本身
first()
last() 聚合查询
from django.db.models import Max,Min,Sum,Count,Avg
aggragate() 分组查询(group by)
annotate() group_concat() concat()
ORM常用字段及方式的更多相关文章
- Django框架之第六篇(模型层)--单表查询和必知必会13条、单表查询之双下划线、Django ORM常用字段和参数、关系字段
单表查询 补充一个知识点:在models.py建表是 create_time = models.DateField() 关键字参数: 1.auto_now:每次操作数据,都会自动刷新当前操作的时间 2 ...
- python 之 Django框架(ORM常用字段和字段参数、关系字段和和字段参数)
12.324 Django ORM常用字段 .id = models.AutoField(primary_key=True):int自增列,必须填入参数 primary_key=True.当model ...
- Django中ORM常用字段及字段参数
Object Relational Mapping(ORM) ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据 ...
- Django orm常用字段和字段参数
1.Object Relational Mapping(ORM) 1.1ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象 ...
- ORM常用字段及查询
目录 ORM常用字段及参数 创建表 ORM常用字段 ORM字段参数 ORM表关系创建 ForeignKey OneToOneField ManyToManyField 多对多三种创建方式 单表查询 q ...
- 06 ORM常用字段 关系字段 数据库优化查询
一.Django ORM 常用字段和参数 1.常用字段 models中所有的字段类型其实本质就那几种,整形varchar什么的,都没有实际的约束作用,虽然在models中没有任何限制作用,但是还是要分 ...
- Django ORM 常用字段和参数
Django ORM 常用字段和参数 一:常用字段 AutoField int自增列,必须填入参数 primary_key=True.当model中如果没有自增列,则自动会创建一个列名为id的列. I ...
- ORM常用字段和参数
目录: ORM常用字段和参数
- ORM常用字段介绍
Django中的ORM Django项目使用MySQL数据库 1. 在Django项目的settings.py文件中,配置数据库连接信息: DATABASES = { "default&qu ...
随机推荐
- configure: error: C compiler cannot create executables报错处理
在测试环境安装php的imagick扩展在执行./configure生成编译文件时出现报错如下: 通过查看config.log发现有报错,在网上经验教程里发现前面的报错不管,直奔最后的报错即可,发现是 ...
- 三层交换机配置DHCP为不同VLAN分配IP地址
三层交换的原理以及DHCP的原理,作者在这里就不详细的解释了,在这里通过一个案例来了解使用三层交换做DHCP服务器,并为不同网段分配IP地址.在生产环境中,使用路由器或交换机做DHCP服务器要常见一些 ...
- ES介绍与实践
一.ES介绍 1.基础概念介绍 1. 索引:Elasticsearch中的“索引”有点像关系数据库中的数据库. 它是存储/索引数据的地方: 2.分片 shard “分片”是Lucene的一个索引. 它 ...
- OpenStack官方镜像无法ssh登陆
0x00 序 当前主流的Linux系统都有提供可以在OpenStack中直接使用cloud镜像,但当使用从官方网站下载的镜像创建云主机时,你会发现Linux下经常使用的ssh竟然无法登陆新创建好的云主 ...
- 全栈新视觉——前后端分离
1234 前端工程化从单纯的 HTML/CSS/JavaScript,到 gulp/webpack 以及 node.js.可能还需要其他的插件 sass.less.vue.react.angular. ...
- Java实体映射工具MapStruct的使用
官网地址:http://mapstruct.org/ MapStruct 是一个代码生成器,简化了不同的 Java Bean 之间映射的处理,所谓的映射指的就是从一个实体变化成一个实体.例如我们在实际 ...
- Linux sed命令实例解析
最近看project的makefile,又见到了sed的强大编辑能力,在makefile工作之前,通常都是执行脚本或者make menuconfig来配置好各种全局变量.sed活动阶段通常在bash ...
- 金矿还是大坑 VR创业真有那么美好?
VR创业真有那么美好?"> 近段时间,一个段子在疯狂流传:彩票中奖的1000万,其实是存放在银行里,而彩民每次花两块钱买彩票,其实就是去输一次密码,只要够坚持,总会取出那1000万-- ...
- maven笔记--持续更新
笔记: 在创建maven项目的时候,如果用到servlet的时候,需要导入包,这时候,需要导入本地仓库的jar包,即依赖包.语法如下 <dependency> <groupId> ...
- Dubbo源码解析之SPI(一):扩展类的加载过程
Dubbo是一款开源的.高性能且轻量级的Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用.智能容错和负载均衡,以及服务自动注册和发现. Dubbo最早是阿里公司内部的RPC框架,于 ...