本文总结:多对多常见API如何使用,分组查询的多种情况、ORM如何开启事务,ORM中常见的字段和参数有哪些?在不同情况下创建自己需要的多对多关系表~什么?ORM创建表的类中还可以写Meta类?
示例
# 当前生成的书籍对象
book_obj=Book.objects.create(title="三国演义",price=200,publishDate="2012-11-12",publish_id=1)
# 为书籍绑定的做作者对象
hans=Author.objects.filter(name="hans").first() # 在Author表中主键为2的纪录
tom=Author.objects.filter(name="tom").first() # 在Author表中主键为1的纪录
# 绑定多对多关系,即向关系表book_authors中添加纪录
book_obj.authors.add(hans,tom) # 将某些特定的 model 对象添加到被关联对象集合中。 ======= book_obj.authors.add(*[])
book = Book.objects.filter(name='红楼梦').first()
Hammer=Author.objects.filter(name='Hammer').first()
hans=Author.objects.filter(name='hans').first()
# 1 没有返回值,直接传对象
book.authors.add(Hammer,hans)
# 2 直接传作者id
book.authors.add(1,3)
# 3 直接传列表,会打散
book.authors.add(*[1,2])
# 解除多对多关系
book = Book.objects.filter(name='红楼梦').first()
# 1 传作者id
book.authors.remove(1)
# 2 传作者对象
hans = Author.objects.filter(name='hans').first()
book.authors.remove(hans)
#3 传*列表
book.authors.remove(*[1,2])
#4 删除所有
book.authors.clear()
# 5 拿到与 这本书关联的所有作者,结果是queryset对象,作者列表
ret=book.authors.all()
# 6 queryset对象,又可以继续点(查询红楼梦这本书所有作者的名字)
ret=book.authors.all().values('name')
print(ret)
book_obj.authors.remove() # 将某个特定的对象从被关联对象集合中去除。 ====== book_obj.authors.remove(*[])
book_obj.authors.clear() #清空被关联对象集合
book_obj.authors.set() #先清空再设置
分组查询一般会用到聚合函数,所以使用前要先从 django.db.models 引入 Avg,Max,Min,Count,Sum(首字母大写)
from django.db.models import Avg,Max,Min,Count,Sum # 引入函数
返回值:
注意:MySQL 中的 limit 相当于 ORM 中的 QuerySet 数据类型的切片,annotate 里面放聚合函数
总结
格式:表名.objects.values('group by 的字段').annotate(聚合函数('统计的字段'))
# select count(id) from emp group by dep
# 示例一:查询每一个部门的名称,以及平均薪水
# select dep,Avg(salary) from app01_emp group by dep
from django.db.models import Avg, Count, Max, Min
ret=Emp.objects.values('dep').annotate(Avg('salary'))
# 重新命名
ret=Emp.objects.values('dep').annotate(avg_salary=Avg('salary'))
print(ret)
# 示例2 查询每个省份对应的员工数
ret=Emp.objects.values('province').annotate(Count('id'))
ret=Emp.objects.values('province').annotate(c=Count('id'))
print(ret)
# 补充知识点:
ret=Emp.objects.all()
# select * from emp
ret=Emp.objects.values('name')
# select name from emp
'''单表下,按照id进行分组是没有任何意义的'''
ret=Emp.objects.all().annotate(Avg('salary'))
print(ret)
'''多表分组查询'''
# 查询每一个出版社出版的书籍个数
ret=Book.objects.values('publish_id').annotate(Count('nid'))
print(ret)
# 查询每个出版社的名称以及出版社书的个数(先join在跨表分组)
# 正向
ret=Publish.objects.values('name').annotate(Count('book__name'))
ret=Publish.objects.values('nid').annotate(c=Count('book__name')).values('name','c')
print(ret)
# 反向
ret=Book.objects.values('publish__name').annotate(Count('name'))
ret=Book.objects.values('publish__name').annotate(c=Count('name')).values('publish__name','c')
print(ret)
# 查询每个作者的名字,以及出版过书籍的最高价格
ret=Author.objects.values('pk').annotate(c=Max('book__price')).values('name','c')
print(ret)
# 跨表查询的模型:每一个后表模型.objects.value('pk').annotate(聚合函数('关联表__统计字段')).values()
# 查询每一个书籍的名称,以及对应的作者个数
ret=Book.objects.values('pk').annotate(c=Count('authors__name')).values('name','c')
print(ret)
# 统计不止一个作者的图书
ret=Book.objects.values('pk').annotate(c=Count('authors__name')).filter(c__gt=1).values('name','c')
print(ret)
1、统计每一本书作者个数
# 1、统计每一本书作者个数
from django.db.models import Avg, Max, Min, Sum, Count, F, Q
res = models.Book.objects.all().annotate(author_num = Count('authors')).values('title','author_num')
print(res)
2、统计每一个出版社的最便宜的书
res = models.Publish.objects.all().annotate(min_price = Min('book__price')).values_list('name','min_price')
print(res)
# <QuerySet [('北方出版社', Decimal('168.80')), ('东方出版社', Decimal('168.80')), ('南方出版社', Decimal('180.00')), ('西方出版社', None)]>
res1 = models.Publish.objects.all().annotate(min_price=Min('book__price')).values('name', 'min_price')
print(res)
# <QuerySet [{'name': '北方出版社', 'min_price': Decimal('168.80')}, {'name': '东方出版社', 'min_price': Decimal('168.80')}, {'name': '南方出版社', 'min_price': Decimal('180.00')}, {'name': '西方出版社', 'min_price': None}]>
3、统计每一本包含‘水’的书籍的作者个数
res = models.Book.objects.filter(title__contains='水').annotate(author_num=Count('authors')).values('title','author_num')
print(res) # <QuerySet [{'title': '水浒传', 'author_num': 3}]>
4、统计不止一个作者的图书:(作者数量大于一)
res = models.Book.objects.all().annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title','author_num')
print(res) # <QuerySet [{'title': '水浒传', 'author_num': 3}]>
5、统计不止一个写过一本书的作者:(书数量大于一)
# 4、统计不止一个写过一本书的作者:(书数量大于一)
res = models.Author.objects.all().annotate(book_num = Count('book')).filter(book_num__gt=1).values('name','book_num')
print(res) # <QuerySet [{'name': '李白', 'book_num': 2}]>
6、根据一本图书作者数量的多少对查询集 QuerySet
进行排序:
res = models.Book.objects.all().annotate(author_num=Count('authors')).values_list('title','author_num').order_by('author_num')
print(res) # 升序:<QuerySet [('三国演义', 0), ('西游记', 0), ('西游记', 1), ('水浒传', 3)]>
res = models.Book.objects.all().annotate(author_num=Count('authors')).values_list('title','author_num').order_by('author_num')
print(res) # 降序:<QuerySet [('水浒传', 3), ('西游记', 1), ('三国演义', 0), ('西游记', 0)]>
7、查询各个作者出的书的总价格:
res = models.Author.objects.annotate(book_price=Sum('book__price')).values('name','book_price')
print(res)
# <QuerySet [{'name': '李白', 'book_price': Decimal('348.70')}, {'name': '杜甫', 'book_price': Decimal('179.90')}, {'name': '王羲之', 'book_price': Decimal('179.90')}]>
8、查询每个出版社的名称和书籍个数
res = models.Publish.objects.annotate(book_num=Count('book')).values('name','book_num')
print(res)
# <QuerySet [{'name': '北方出版社', 'book_num': 2}, {'name': '南方出版社', 'book_num': 1}, {'name': '东方出版社', 'book_num': 1}, {'name': '西方出版社', 'book_num': 0}]>
'''django开启事务'''
导入模块: from django.db import transaction
# 示例
from django.db import transaction
try:
'''执行的SQL语句'''
with transaction.Atomic:
# sql1
# sql2
# sqln···
pass
# 写在这个里面的都是属于同一个事务
except Exception as e:
print(e)
transaction.rollback() # 回滚
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()实例
ps:DateField和DateTimeField可以添加auto_now_add
和auto_now
参数,auto_now_add表示如果配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库,auto_now表示如果配置上auto_now=True,每次更新数据记录的时候会更新该字段
null:用于表示某个字段可以为空
unique:如果设置为unique=True 则该字段在此表中必须是唯一的
db_index:如果db_index=True 则代表着为此字段设置索引
default:为该字段设置默认值
针对可选,可列举的可能性,我们可以使用choices参数,比如性别,爱好,学历等
'''定义表字段的时候添加'''
gender_choices = (
(1, '男'),
(2, '女'),
(3, '其他'),
)
gender = models.IntegerField(choices=gender_choices)
# 这样我们在插入数据的时候就可以以该数值插入,1代表男,2二代表女,3代表其他,那么查询的时候输出的还是对应的字符串(男,女,其他)
注意:对于choices参数我们该如何选择数据类型?比如上面的性别,那么就看提前设定的小元组内第一个元素是什么类型的参数,下面定义字段就采用什么参数
# 字符串的情况
score_choices = (
('A', '优秀'),
('B', '良好'),
('C', '及格'),
('D', '不及格'),
)
score = models.CharField(max_length=8)
读取存入的数据
res = models.User.objects.filter(pk=4).first()
print(res)
print(res.gender)
print(res.get_gender_display()) # 固定语法:get_字段名_display()
'''
固定语法结构取值:get_字段名_display()
如果查询出来的数据不再choices范围内,会显示原始数据,比如gender只定义了1-3,那么读取4的时候返回的就是数值4
'''
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name="书名")
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name="作者姓名")
# 自己创建第三张表,分别通过外键关联书和作者
class Author2Book(models.Model):
author = models.ForeignKey(to="Author")
book = models.ForeignKey(to="Book")
class Meta:
unique_together = ("author", "book")
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name="书名")
# 通过ORM自带的ManyToManyField自动创建第三张表
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name="作者姓名")
books = models.ManyToManyField(to="Book", related_name="authors")
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name="书名")
# 自己创建第三张表,并通过ManyToManyField指定关联
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name="作者姓名")
books = models.ManyToManyField(to="Book", through="Author2Book", through_fields=("author", "book"))
# through_fields接受一个2元组('field1','field2'):
# 其中field1是定义ManyToManyField的模型外键的名(author),field2是关联目标模型(book)的外键名。
class Author2Book(models.Model):
author = models.ForeignKey(to="Author")
book = models.ForeignKey(to="Book")
class Meta:
unique_together = ("author", "book")
注意
ORM对应的类里面包含另一个Meta类,而Meta类封装了一些数据库的信息。主要字段如下:
db_table
ORM在数据库中的表名默认是 app_类名,可以通过db_table可以重写表名
index_together
联合索引
unique_together
联合唯一索引
ordering
指定默认按什么字段排序,只有设置了该属性,我们查询到的结果才可以被reverse()
class UserInfo(models.Model):
nid = models.AutoField(primary_key=True)
username = models.CharField(max_length=32)
class Meta:
# 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
db_table = "table_name"
# 联合索引:多个字段建索引
index_together = [
("pub_date", "deadline"),
]
# 联合唯一索引:当两个字段同时一样的时候就不能存入
unique_together = (("driver", "restaurant"),)
ordering = ('name',) # ordering设置默认按什么排序
如果想在django中使用原生sql,那么raw方法可以实现
from app01 import models
res=models.Author.objects.raw('select * from app01_author where nid>1')
for author in res:
print(author.name)
'''上面看起来是使用了作者表,来查了数据,但是执行原生sql,跟对象类型无关了,查出什么字段,可以直接使用该字段'''
res = models.Author.objects.raw('select * from app01_book where nid>1')
for book in res:
print(book.price)
# 这样看起来是使用了作者表,但是可以查书的相关数据
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://www.cnblogs.com/48xz/p/15965955.html
内容来源于网络,如有侵权,请联系作者删除!