单表、多表操作
一、单表操作
1.1 在python的脚本下调用Django环境
import os if __name__ == '__main__': os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day76.settings") import django django.setup()
1.2 用orm创建表
from django.db import models # Create your models here. class Book(models.Model): # id 在建表时可以不用写,默认会自动添加 name = models.CharField(max_length=55) price = models.CharField(max_length=11) publish = models.CharField(max_length=44) date = models.DateField(null=True) # 指定输出显示内容的格式 def __str__(self): return 'name: %s, price: %s' % (self.name, self.price)
- 数据的迁移操作
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 创建表操作
- 创建类,添加字段
from django.db import models # Create your models here. class Book(models.Model): name = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) publish = models.ForeignKey(to='Publish', to_field='id') authors = models.ManyToManyField(to='Author') def __str__(self): return self.name class Author(models.Model): name = models.CharField(max_length=33) sex = models.IntegerField() # 一对一关系建议使用 OneToOneField author_details = models.OneToOneField(to='AuthorDetails') def __str__(self): return self.name class AuthorDetails(models.Model): phone = models.CharField(max_length=21) address = models.CharField(max_length=66) class Publish(models.Model): name = models.CharField(max_length=33) address = models.CharField(max_length=64) email = models.EmailField() def __str__(self): return self.name ''' 注意点: 一对一: OneToOneField 一对多: ForeignKey 多对多: ManyToManyField OneToOneField 和 ForeignKey 在建模型表时会在字段名后自动添加_id,如:publish_id ManyToManyField 会自动创建第三张表 '''
-
添加出版社信息
Publish.objects.create(name='环球出版社', address='北京', email='0000@foxm.com') Publish.objects.create(name='华夏出版社', address='北京', email='1111@foxm.com')
-
添加书籍信息
# 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) # 反向: 查找邮箱是 0000@foxm.com 的出版社出版的 雷神之诸神黄昏 这本书的价格 email = Publish.objects.filter(email='0000@foxm.com').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中每一个对象都生成一个独立的统计值(统计方法用聚合函数)。
- 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
本文来自博客园,仅供参考学习,如有不当之处还望不吝赐教,不胜感激!转载请注明原文链接:https://www.cnblogs.com/rong-z/p/10022956.html
作者:cnblogs用户