创建小型数据库

模型层

  • 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()
  1. 字段的参数

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)
"""

再次强调:

  1. 对于所有类型的关联字段,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常用字段及方式的更多相关文章

  1. Django框架之第六篇(模型层)--单表查询和必知必会13条、单表查询之双下划线、Django ORM常用字段和参数、关系字段

    单表查询 补充一个知识点:在models.py建表是 create_time = models.DateField() 关键字参数: 1.auto_now:每次操作数据,都会自动刷新当前操作的时间 2 ...

  2. python 之 Django框架(ORM常用字段和字段参数、关系字段和和字段参数)

    12.324 Django ORM常用字段 .id = models.AutoField(primary_key=True):int自增列,必须填入参数 primary_key=True.当model ...

  3. Django中ORM常用字段及字段参数

    Object Relational Mapping(ORM) ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据 ...

  4. Django orm常用字段和字段参数

    1.Object Relational Mapping(ORM) 1.1ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象 ...

  5. ORM常用字段及查询

    目录 ORM常用字段及参数 创建表 ORM常用字段 ORM字段参数 ORM表关系创建 ForeignKey OneToOneField ManyToManyField 多对多三种创建方式 单表查询 q ...

  6. 06 ORM常用字段 关系字段 数据库优化查询

    一.Django ORM 常用字段和参数 1.常用字段 models中所有的字段类型其实本质就那几种,整形varchar什么的,都没有实际的约束作用,虽然在models中没有任何限制作用,但是还是要分 ...

  7. Django ORM 常用字段和参数

    Django ORM 常用字段和参数 一:常用字段 AutoField int自增列,必须填入参数 primary_key=True.当model中如果没有自增列,则自动会创建一个列名为id的列. I ...

  8. ORM常用字段和参数

    目录: ORM常用字段和参数

  9. ORM常用字段介绍

    Django中的ORM Django项目使用MySQL数据库 1. 在Django项目的settings.py文件中,配置数据库连接信息: DATABASES = { "default&qu ...

随机推荐

  1. configure: error: C compiler cannot create executables报错处理

    在测试环境安装php的imagick扩展在执行./configure生成编译文件时出现报错如下: 通过查看config.log发现有报错,在网上经验教程里发现前面的报错不管,直奔最后的报错即可,发现是 ...

  2. 三层交换机配置DHCP为不同VLAN分配IP地址

    三层交换的原理以及DHCP的原理,作者在这里就不详细的解释了,在这里通过一个案例来了解使用三层交换做DHCP服务器,并为不同网段分配IP地址.在生产环境中,使用路由器或交换机做DHCP服务器要常见一些 ...

  3. ES介绍与实践

    一.ES介绍 1.基础概念介绍 1. 索引:Elasticsearch中的“索引”有点像关系数据库中的数据库. 它是存储/索引数据的地方: 2.分片 shard “分片”是Lucene的一个索引. 它 ...

  4. OpenStack官方镜像无法ssh登陆

    0x00 序 当前主流的Linux系统都有提供可以在OpenStack中直接使用cloud镜像,但当使用从官方网站下载的镜像创建云主机时,你会发现Linux下经常使用的ssh竟然无法登陆新创建好的云主 ...

  5. 全栈新视觉——前后端分离

    1234 前端工程化从单纯的 HTML/CSS/JavaScript,到 gulp/webpack 以及 node.js.可能还需要其他的插件 sass.less.vue.react.angular. ...

  6. Java实体映射工具MapStruct的使用

    官网地址:http://mapstruct.org/ MapStruct 是一个代码生成器,简化了不同的 Java Bean 之间映射的处理,所谓的映射指的就是从一个实体变化成一个实体.例如我们在实际 ...

  7. Linux sed命令实例解析

    最近看project的makefile,又见到了sed的强大编辑能力,在makefile工作之前,通常都是执行脚本或者make menuconfig来配置好各种全局变量.sed活动阶段通常在bash ...

  8. 金矿还是大坑 VR创业真有那么美好?

    VR创业真有那么美好?"> 近段时间,一个段子在疯狂流传:彩票中奖的1000万,其实是存放在银行里,而彩民每次花两块钱买彩票,其实就是去输一次密码,只要够坚持,总会取出那1000万-- ...

  9. maven笔记--持续更新

    笔记: 在创建maven项目的时候,如果用到servlet的时候,需要导入包,这时候,需要导入本地仓库的jar包,即依赖包.语法如下 <dependency> <groupId> ...

  10. Dubbo源码解析之SPI(一):扩展类的加载过程

    Dubbo是一款开源的.高性能且轻量级的Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用.智能容错和负载均衡,以及服务自动注册和发现. Dubbo最早是阿里公司内部的RPC框架,于 ...