单表多表操作

Posted rongge95500

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单表多表操作相关的知识,希望对你有一定的参考价值。

一、单表操作

1.1 在python的脚本下调用Django环境

技术分享图片test.py

1.2 用orm创建表

技术分享图片models.py
  • 数据的迁移操作
python3 manage.py makemigrations    #只是对变化做一个记录,记录文件在app的migrations文件夹下
python3 manage.py migrate        #把更改提交到数据库
python3 manage.py showmigrations    #查看那个app中的数据没有提交到数据库,打×表示已提交

1.3 对数据的操作

  • 添加数据
# 方法一:
models.Book.objects.create(name=‘阿甘正传‘, price=‘23‘, publish=‘环球出版社‘, date=‘2018-8-8‘)

# 方法二:
import datetime
c_time = datetime.datetime.now()
book = models.Book(name=‘史前人类‘, price=‘68‘, publish=‘华夏出版社‘, date=c_time)
book.save()
  • 删除数据
# 方法一:
models.Book.objects.filter(name=‘史前人类‘).delete()

# 方法二:
book = models.Book.objects.filter(name=‘史前人类‘).first()
book.delete(
  • 修改数据
# 方法一:
book = models.Book.objects.filter(name=‘阿甘正传‘).update(price=‘44‘)

# 方法二:
book = models.Book.objects.filter(name=‘阿甘正传‘).first()
book.price = ‘55‘
book.save()
  • 查询数据
1> all():                  查询所有结果                   
2> filter(**kwargs):       它包含了与所给筛选条件相匹配的对象      
3> get(**kwargs):          返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。 
4> exclude(**kwargs):      它包含了与所给筛选条件不匹配的对象 
5> order_by(*field):       对查询结果排序(‘-id‘)   
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():            从返回结果中剔除重复纪录
# 补充:对象.query,可查看查询的sql语句
# .all()
book = models.Book.objects.all()

# .filter()
book = models.Book.objects.filter(name=‘孝庄秘史‘)

# .get(**kwargs) 有且只有一个结果时才能用,如果有一个,返回的是对象,不是queryset对象,通常用在,用id查询的情况
book = models.Book.objects.get(name=‘阿甘正传‘)
# name: 阿甘正传, price: 55

# .exclude(**kwargs) 除了符合条件的结果,结果也是queryset对象
book = models.Book.objects.exclude(name=‘神秘的西夏王陵‘)

# .order_by()
# 按价格升序排序
book = models.Book.objects.all().order_by(‘price‘)
# 按价格降序排序
book = models.Book.objects.all().order_by(‘-price‘)
# 其后可继续跟筛选条件
book = models.Book.objects.all().order_by(‘price‘).filter(name=‘阿甘正传‘)

# .reverse() 将查询结果进行反向排序
book = models.Book.objects.all().order_by(‘price‘).reverse()

# .count() 查询结果的个数
book = models.Book.objects.filter(name=‘阿甘正传‘).count()

# .last() 多个结果时返回最后一个
book = models.Book.objects.filter(name=‘阿甘正传‘).last()

# .exists() 返回的是结果的布尔值
book = models.Book.objects.filter(name=‘阿甘正传‘).exists()

# .values() queryset对象里套字典
book = models.Book.objects.all().values(‘name‘)
# < QuerySet[{‘name‘: ‘阿甘正传‘}, {‘name‘: ‘孝庄秘史‘}, {‘name‘: ‘神秘的西夏王陵‘}] >

# .value_list() queryset对象里套元组
book = models.Book.objects.all().values_list(‘name‘)
# < QuerySet[(‘阿甘正传‘,), (‘孝庄秘史‘,), (‘神秘的西夏王陵‘,)] >

# .distinct() 必须完全一样,才能去重,不适用与用id的查询结果
book = models.Book.objects.all().values(‘name‘).distinct()

1.4 数据的模糊查询

Book.objects.filter(price__in=[45,98,56]) 价格在[]的书
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])   在XX范围内
Book.objects.filter(name__contains="阿")     查询名字有‘%阿%‘的书
Book.objects.filter(name__icontains="python")  查询名字带python的书,忽略大小写
Book.objects.filter(name__startswith="神")    以‘神‘开头的书
Book.objects.filter(date__year=2017)        按年查询

 二、多表操作

案例:以下面这些概念,字段和关系查询

作者模型:一个作者有姓名和性别及其他详细信息。

作者详细模型:把作者的详情放到详情表,包含手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(OneToOneField)

出版社模型:出版社有名称,所在城市以及email。

书籍模型: 书籍有书名、价格、作者(一本书可能会有多个作者,一个作者也可以写多本书),所以作者和书籍的关系就是多对多的关联关系(ManyToManyField),但是一本书只应该由一个出版社出版,所以出版社和书籍是一对多的关联关系(ForeignKey)。

2.1 创建表操作

  • 创建类,添加字段
技术分享图片models.py
  • 添加出版社信息

Publish.objects.create(name=‘环球出版社‘, address=‘北京‘, email=‘[email protected]‘)
Publish.objects.create(name=‘华夏出版社‘, address=‘北京‘, email=‘[email protected]‘)
  • 添加书籍信息

# pk 为主键,可通过主键查找,也可通过 id 查找
publish = Publish.objects.filter(pk=1).first()
Book.objects.create(name=‘雷神之诸神之怒‘, price=65.9, publish=publish)
Book.objects.create(name=‘雷神之黑暗世界‘, price=75.3, publish=publish)
Book.objects.create(name=‘雷神之诸神黄昏‘, price=45.5, publish=publish)
  • 添加作者详情信息

AuthorDetails.objects.create(phone=‘18800001‘, address=‘昌平‘)
AuthorDetails.objects.create(phone=‘16600002‘, address=‘五环‘)
  • 添加作者信息

au_details = AuthorDetails.objects.filter(id=1).first()
Author.objects.create(name=‘jack‘, sex=1, author_details=au_details)
au_details = AuthorDetails.objects.filter(id=2).first()
Author.objects.create(name=‘peter‘, sex=1, author_details=au_details)

2.2 连表的增删改查

# 获取作者
jack = Author.objects.filter(name=‘jack‘).first()
peter = Author.objects.filter(name=‘peter‘).first()

# 获取书名
book = Book.objects.filter(name=‘雷神之诸神之怒‘).first()
# 一:.add() 添加,可添加一个或多个对象,id
# 为 雷神之诸神之怒 新增作者 jack,peter
book.authors.add(jack, peter)
# 也可以按作者id添加
book.authors.add(1,2)

# 二:.remove() 删除,可以是id,也可以是对象,能传多个值
book.authors.remove(jack) # 按名字删除
book.authors.remove(1, 2) # 按id删除

# 三:.clear() 清空所有,不用传值
book.authors.clear()

# 四:.set() 先清空,再新增,注意点:传的值必须是列表,列表内可以是id,或者对象
book.authors.set([jack,])

2.3 基于对象的连表查询

基于对象的连表查询是子查询,即多次查询

  • 一对一

正向:由关联字段所在的表去查找其他表时---按字段

反向:由其他表去查找关联字段所在的表时---按表名小写

# 正向: 查找作者jack的phone信息时
author = Author.objects.filter(name=‘jack‘).first()
res = author.author_details.phone # author.author_details 作者详情对象
print(res)

# 反向: 查找地址是五环的作者名字
address = AuthorDetails.objects.filter(address=‘五环‘).first()
author = address.author.name # address.author 作者对象
print(author)
  • 一对多

正向: 由关联字段所在的表去查找其他表时---按字段

反向: 由其他表去查找关联字段所在的表时---按表名小写_set.all()

# 正向: 查找 雷神之诸神之怒 的出版社邮箱
book = Book.objects.filter(name=‘雷神之诸神之怒‘).first()
publish_email = book.publish.email
print(publish_email)

# 反向: 查找邮箱是 [email protected] 的出版社出版的 雷神之诸神黄昏 这本书的价格
email = Publish.objects.filter(email=‘[email protected]‘).first()
book = email.book_set.all().filter(name=‘雷神之诸神黄昏‘).values(‘price‘) # email.book_set.all() 拿出的是所有图书
print(book)
  • 多对多

正向: 由关联字段所在的表去查找其他表时---按字段.all()

反向: 由其他表去查找关联字段所在的表时---按表名小写_set.all()

# 正向: 查找 雷神之诸神之怒 的作者信息
book = Book.objects.filter(name=‘雷神之诸神之怒‘).first()
author = book.authors.all()
print(author)

# 反向: 查找 作者jack 所写的书籍
author = Author.objects.filter(name=‘jack‘).first()
books = author.book_set.all()
print(books)

2.4 基于双下划线的连表查询

***正向查询按字段,反向连表查询按表名小写***

  • 一对一

# 查询 作者jack 的phone信息
# 以 Author 表作为基表查询
phone = Author.objects.filter(name=‘jack‘).values(‘author_details__phone‘)

# 以 AuthorDetails 表作为基表查询
phone = AuthorDetails.objects.filter(author__name=‘jack‘).values(‘phone‘)
print(phone)
  •  一对多
# 查询出版社为北京的出版社出版的所有图书的名字、价格
# 以 Publish 为基表查询
res = Publish.objects.filter(name=‘北京出版社‘).values(‘book__name‘,‘book__price‘)
# 以 Book 为基表查询
res = Book.objects.filter(publish__name=‘北京出版社‘).values(‘name‘, ‘price‘)
print(res)
  • 多对多
# 查询 雷神之诸神之怒 的所有作者的名字
# 以 Book 为基表查询
authors = Book.objects.filter(name=‘雷神之诸神之怒‘).values(‘authors__name‘)
# 以 Author 为基表查询
authors = Author.objects.filter(book__name=‘雷神之诸神之怒‘).values(‘name‘)
print(authors)
# 查询图书价格大于30的所有作者的名字
# 以 Book 为基表查询
authors = Book.objects.filter(price__gt=30).values(‘authors__name‘)
# 以 Author 为基表查询
authors = Author.objects.filter(book__price__gt=30).values(‘name‘)
print(authors)
  • 多次连表查询

# 查询 环球出版社 出版过的书籍的名字和作者的名字
# 以 Publish 为基表查询
res = Publish.objects.filter(name=‘环球出版社‘).values(‘book__name‘, ‘book__authors__name‘)
print(res)
# 以 Book 为基表查询
res1 = Book.objects.filter(publish__name=‘环球出版社‘).values(‘name‘, ‘authors__name‘)
print(res1)
# 以 Author 为基表查询
res2 = Author.objects.filter(book__publish__name=‘环球出版社‘).values(‘book__name‘, ‘name‘)
print(res2)

2.5 聚合查询&分组查询

  • 聚合查询 .aggregate()
    • aggregate()QuerySet 的一个终止子句,即它返回一个包含一些键值对的字典
from django.db.models import Avg, Min, Max, Sum, Count

# 计算所有书籍的平均价格,最高价格,最低价格,总和
avg_price = Book.objects.aggregate(Avg(‘price‘))
max_price = Book.objects.aggregate(Max(‘price‘))
min_price = Book.objects.aggregate(Min(‘price‘))
sum_price = Book.objects.aggregate(Sum(‘price‘))
print(avg_price)
print(max_price)
print(min_price)
print(sum_price)

# 查询 环球出版社 出版书籍的数量
count = Publish.objects.filter(name=‘环球出版社‘).aggregate(Count(‘book‘))
print(count)
  • 分组查询 .annotate()
    • annotate()为调用的 QuerySet中每一个对象都生成一个独立的统计值(统计方法用聚合函数)。
# 统计书籍名以‘黄昏‘结尾的书的作者的个数
res = Book.objects.all().filter(name__endswith=‘黄昏‘).annotate(num=Count(‘authors‘)).values(‘name‘,‘num‘)
print(res)

# 总结:以谁分组, 就以谁做基表, filter过滤, annotate取分组, values取值
# 模板
    # values 在前表示group by,在后表示取值
    # filter 在前表示where条件,在后表示having

# 统计书籍名以‘黄昏‘结尾的书的作者的个数(按模板)
res = Book.objects.values(‘name‘).filter(name__endswith=‘黄昏‘).annotate(num=Count(‘authors‘)).values(‘name‘, ‘num‘)
print(res)

# 查询每个作者所出书籍的价格的总和
res = Author.objects.values(‘name‘).annotate(num=Sum(‘book__price‘)).values(‘name‘, ‘num‘)
print(res)

2.6 F查询 & Q查询

Django 提供 F() 来对两个字段的值做比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值

# F 函数
from django.db.models import F,Q

# 将所有书籍的价格加10元
res = Book.objects.all().update(price=F(‘price‘)+10)
print(res)


# Q 函数
# 表示或(|)、非(~)关系
# 查询作者的名字是jack 或 peter 的 书
res = Book.objects.filter(Q(authors__name=‘jack‘)|Q(authors__name=‘peter‘))
print(res)

2.7 常用字段及参数

  • orm字段
AutoField----->int 自增,必须输入参数primary_key=True
CharField(max_length=[0-255])----->字符类型,必须提供max_length参数
DateTimeField----->日期+时间格式 YY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
DateField----->日期格式 YY-MM-DD
TimeField----->时间格式 HH:MM[:ss[.uuuuuu]][TZ]
EmailField----->字符串类型
IntegerField----->整数(-2147483648 ~ 2147483647)
PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)----->正整数(0 ~ 2147483647)
NullBooleanField----->可以为空的布尔值
TextField----->文本类型
  • orm字段参数
null - ---->表示某个字段可以为空
unique - ---->值为True时,该字段就必须是唯一的
db_index - ---->值为True时,为该字段设置索引
default - ---->设置默认值


# DateField & DateTimeField
auto_now_add - ---->值为True时,创建数据记录是会将当前时间添加到数据库
auto_now - ---->值为True时,每次更新数据记录都会更新该字段


# ForeignKey
to - ---->设置要关联的表
to_field - ---->设置要关联的字段
related_name - ---->在反向操作时, 使用的字段名,用于代替原反向查询时的‘表名_set‘
# eg:
class Classes(models.Model):
    name = models.CharField(max_length=32)


class Student(models.Model):
    name = models.CharField(max_length=32)
    theclass = models.ForeignKey(to="Classes")

# 反向查询 班级所有的学生时
students = models.Classes.objects.first().student_set.all()

# 但是当设置了 related_name="students" 后
theclass = models.ForeignKey(to="Classes", related_name="students")
# 就可以这样查询
students = models.Classes.objects.first().students.all()

related_query_name - ---->反向查询操作时,使用的连接前缀,用于替换表名
db_constraint - ---->是否在数据库中创建外键约束,默认为True
on_delete - ---->当删除关联表中的数据时,当前表与其关联的行的行为
    # models.CASCADE 删除关联数据,与之关联也删除
    # models.DO_NOTHING 删除关联数据,引发错误IntegrityError
    # models.SET 删除关联数据
        a.与之关联的值设置为指定值,设置:models.SET(值)
        b.与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)


# ManyToManyField
db_table - ---->默认创建第三张表时,数据库中表的名称
through_fields - ---->设置关联的字段
symmetrical - ---->仅用于多对多自关联时,指定内部是否创建反向操作的字段。默认为True

以上是关于单表多表操作的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 基础之 单表多表联查

Mybatis单表多表查询,动态SQL使用

Django模型层:单表多表操作F与Q查询

wen应用/路由控制/视图函数/单表多表操作

Mysql单表多表查询

mysql单表多表查询