Django框架之ORM操作
ORM操作
ORM常用字段与参数
常用字段类型 | 常用参数 |
---|---|
AutoField | primary_key |
IntegerField | choices |
DecimalField | max_digits,decimal_places |
DateField | auto_now,auto_now_add |
DateTimeField | auto_now,auto_now_add |
CharField | max_lenght |
TextField | \ |
EmailField | \ |
URLField | \ |
choice:为字段设置对应关系
choices = (
(1,'male'),
(2,'female'),
(3,'others')
) # 创建对应关系
gender = models.IntegerField(choices=choices) # 将对应关系传给IntegerField
# 获取对应关系的值:数据对象.get_字段名_display() 当没有对应关系的时候 该句式获取到的还是数字
- 如果存的是不在对应关系表里的数据是也是可以存进去的
- 如果我们存的是元组范围的话实际上也是以数字存在数据库中
注:“\”一般无特殊情况不加参数
准备数据
-
models.py
from django.db import models # Create your models here. class Author_info(models.Model): phone = models.BigIntegerField() addr = models.CharField(max_length=32) def __str__(self): return self.addr class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() author_info = models.OneToOneField(to="Author_info") def __str__(self): return self.name class Publish(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=64) def __str__(self): return self.name 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=True) publish = models.ForeignKey(to=Publish) author = models.ManyToManyField(to="Author") def __str__(self): return self.title
-
数据库建表
python manage.py makemigrations python manage.py migrate
-
插入数据(mysql)
insert into `app01_author_info`(`id`,`phone`,`addr`) values (1,110,'温州'),(2,120,'温岭'),(3,130,'台州'); insert into `app01_author`(`id`,`name`,`age`,`author_info_id`) values (1,'ly',18,1),(2,'zzh',19,3),(3,'wht',20,2); insert into `app01_publish`(`id`,`name`,`addr`) values (1,'东方出版社','东京'),(2,'南方出版社','南京'),(3,'北方出版社','北京'); insert into `app01_book`(`id`,`title`,`price`,`publish_date`,`publish_id`) values (1,'三国演义','69.00','2004-07-25',1),(2,'西游记','110.00','1994-07-29',2),(3,'水浒传','80.00','2010-06-26',3),(4,'封神榜','56.00','2000-11-03',1),(6,'西厢记','87.00','2000-07-11',1),(7,'红楼梦','65.00','1996-06-22',3),(10,'鹿鼎记','88.00','2019-10-26',1);
-
创建测试环境
import os,django if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings") django.setup() from app01 import models
常规查询操作
-
get
book_obj = models.Book.objects.get(pk=1) # 获取一个数据表对象 print(book_obj) # 三国演义 ## 这是同__str__修改了输出信息
-
filter
book_obj = models.Book.objects.filter(pk=2) # 获取一个结果集,Queryset套数据库对象 print(book_obj) # <QuerySet [<Book: 西游记>]>
-
all
book_obj = models.Book.objects.all() # 获取数据表的所有数据,Queryset套数据库对象 print(book_obj) # <QuerySet [<Book: 三国演义>, <Book: 西游记>, <Book: 水浒传>, <Book: 封神榜>, <Book: 西厢记>, <Book: 红楼梦>, <Book: 鹿鼎记>]>
-
first
book_obj = models.Book.objects.first() # 取结果集第一个对象 print(book_obj.first()) # 三国演义
-
last
book_obj = models.Book.objects.last() # 取结果集最后一个对象 print(book_obj.last()) # 鹿鼎记
-
exclude
book_obj = models.Book.objects.exclude(pk=3) # 除此之外,除了主键值为3的数据之外都查询出来 print(book_obj) # <QuerySet [<Book: 三国演义>, <Book: 西游记>, <Book: 封神榜>, <Book: 西厢记>, <Book: 红楼梦>, <Book: 鹿鼎记>]>
-
values
book_obj = models.Book.objects.all().values("id","title") # 查询指定字段,Queryset套字典 print(book_obj) # <QuerySet [{'id': 1, 'title': '三国演义'}, {'id': 2, 'title': '西游记'}, {'id': 3, 'title': '水浒传'}, {'id': 4, 'title': '封神榜'}, {'id': 6, 'title': '西厢记'}, {'id': 7, 'title': '红楼梦'}, {'id': 10, 'title': '鹿鼎记'}]>
-
values_list
book_obj = models.Book.objects.all().values("id","title") # 查询指定字段,Queryset套元组 print(book_obj) # <QuerySet [(1, '三国演义'), (2, '西游记'), (3, '水浒传'), (4, '封神榜'), (6, '西厢记'), (7, '红楼梦'), (10, '鹿鼎记')]>
-
count
count = models.Book.objects.count() # 统计数据表内的数据条数 print(count) # 7
-
distinct
book_obj = models.Book.objects.all().values("title").distinct() # 去重,只有当所查字段都一样时才会触发去重的机制 print(book_obj) # <QuerySet [{'title': '三国演义'}, {'title': '西游记'}, {'title': '水浒传'}, {'title': '封神榜'}, {'title': '西厢记'}, {'title': '红楼梦'}, {'title': '鹿鼎记'}]>
-
order_by
book_obj = models.Book.objects.all().order_by("title") # 排序 print(book_obj) # <QuerySet [<Book: 三国演义>, <Book: 封神榜>, <Book: 水浒传>, <Book: 红楼梦>, <Book: 西厢记>, <Book: 西游记>, <Book: 鹿鼎记>]>
-
reverse
book_obj = models.Book.objects.all().order_by("title").reverse() # 反转排序的顺序 print(book_obj) # <QuerySet [<Book: 鹿鼎记>, <Book: 西游记>, <Book: 西厢记>, <Book: 红楼梦>, <Book: 水浒传>, <Book: 封神榜>, <Book: 三国演义>]>
-
exists
book_obj = models.Book.objects.filter(title="西游记").exists() # 查询是否存在 print(book_obj) # True book_obj = models.Book.objects.filter(title="东游记").exists() print(book_obj) # False
下划线操作
-
__gt
book_obj = models.Book.objects.filter(pk__gt=3) # 大于 print(book_obj) # <QuerySet [<Book: 封神榜>, <Book: 西厢记>, <Book: 红楼梦>, <Book: 鹿鼎记>]>
-
__lt
book_obj = models.Book.objects.filter(pk__lt=3) # 小于 print(book_obj) # <QuerySet [<Book: 三国演义>, <Book: 西游记>]>
-
__gte
book_obj = models.Book.objects.filter(pk__gte=3) # 大于等于 print(book_obj) # <QuerySet [<Book: 水浒传>, <Book: 封神榜>, <Book: 西厢记>, <Book: 红楼梦>, <Book: 鹿鼎记>]>
-
__lte
book_obj = models.Book.objects.filter(pk__lte=3) # 小于等于 print(book_obj) # <QuerySet [<Book: 三国演义>, <Book: 西游记>, <Book: 水浒传>]>
-
__in
book_obj = models.Book.objects.filter(pk__in=[2,3,5]) # 包含 print(book_obj) # <QuerySet [<Book: 西游记>, <Book: 水浒传>]>
-
__range
book_obj = models.Book.objects.filter(pk__range=[2,7]) # 在这个范围 print(book_obj) # <QuerySet [<Book: 西游记>, <Book: 水浒传>, <Book: 封神榜>, <Book: 西厢记>, <Book: 红楼梦>]>
-
__contains
book_obj = models.Book.objects.filter(title__contains="记") # 包含,区分大小写 print(book_obj) # <QuerySet [<Book: 西游记>, <Book: 西厢记>, <Book: 鹿鼎记>]>
-
__icontains
book_obj = models.Book.objects.filter(title__icontains="记") # 包含,不区分大小写 print(book_obj) # <QuerySet [<Book: 西游记>, <Book: 西厢记>, <Book: 鹿鼎记>]>
-
__startswith
book_obj = models.Book.objects.filter(title__startswith="红") # 匹配开头 print(book_obj) # <QuerySet [<Book: 红楼梦>]>
-
__endswith
book_obj = models.Book.objects.filter(title__startswith="记") # 匹配结尾 print(book_obj) # <QuerySet [<Book: 西游记>, <Book: 西厢记>, <Book: 鹿鼎记>]>
-
__year
book_obj = models.Book.objects.filter(publish_date__year=2019) # 匹配年份 print(book_obj) # <QuerySet [<Book: 鹿鼎记>]>
-
__month
book_obj = models.Book.objects.filter(publish_date__month=6) # 匹配月份 print(book_obj) # <QuerySet [<Book: 水浒传>, <Book: 红楼梦>]>
多表操作
-
add
book_obj = models.Book.objects.filter(pk=2).first() # 获取书籍对象 book_obj.author.add(1,2,3) # 将作者id添加到多对多字段的中间表去
-
set
book_obj = models.Book.objects.filter(pk=2).first() # 获取书籍对象 book_obj.author.set([1,3]) # 传递的为一个可迭代对象,将中间表的记录修改,如果已经存在对应的记录,便不会修改,不存在的会添加,没有对应的就会被删除。 # 下面这种方法可以删除关于这本书籍的记录 book_obj = models.Book.objects.filter(pk=2).first() book_obj.author.set([])
-
remove
book_obj = models.Book.objects.filter(pk=2).first() # 获取书籍对象 book_obj.author.remove(1,2) # 删除对应的记录
-
clear
book_obj = models.Book.objects.filter(pk=2).first() # 获取书籍对象 book_obj.author.clear() # 删除书籍对应的所有记录
跨表查询
上面已经讲了怎么对多表进行增删改,下面就是对多表查询
跨表查询只需要记住两句话就可以了:
1. 从外键所在的表查询用字段名(使用Django建表)
2. 从费外键所在的表查询使用表名小写
第二条这里还需要分两种情况,多值和单值
1. 单值直接加表名小写
2. 多值需要表名小写并加上_set_all
查询方法也有两个方式:
- 通过对象查询(基于子查询)
- 通过双下划綫查询(基于连表查询)
表间数据自己随便填
用例:
-
查询作者是gredae的手机号码(一对一)
-
对象查询
author = models.Author.objects.filter(name="gredae").first() # 获取作者对象 phone = author.author_info.phone # 从作者表跨到作者详情表获取phone print(phone) # 110
-
双下划綫查询
author_info_obj = models.Author_info.objects.filter(author__name="gredae").first() # 获取作者详情表,条件是作者名字 print(author_info_obj.phone) # 110
-
-
查询东方出版社出版过得书(一对多)
-
对象查询
publish_obj = models.Publish.objects.filter(name="东方出版社").first() # 获取出版社对象 print(publish_obj.book_set.all()) # 通过出版社跨到书籍表,通过all()将所有是东方出版社出版的书全部查询出来
-
双下划綫查询
book_ls = models.Book.objects.filter(publish__name="东方出版社") # 直接获取所有是东方出版社出版的书 print(book_ls) # <QuerySet [<Book: 三国演义>, <Book: 封神榜>, <Book: 西厢记>, <Book: 鹿鼎记>]>
-
-
查询水浒传的作者名字(多对多)
-
对象查询
book_obj = models.Book.objects.filter(title="水浒传").first() # 获取书籍对象 for author_obj in book_obj.author.all(): # 通过书籍对象查询作者 print(author_obj.name) # gredae zzh
-
双下划綫查询
author_ls = models.Author.objects.filter(book__title="水浒传") # 直接可以获取作者对象 for author_obj in author_ls: # 循环打印作者名字 print(author_obj.name)
-
聚合查询
聚合函数:Max,Min,Sum,Count,Avg
-
Max
price_max = models.Book.objects.aggregate(Max("price")) print(price_max) # {'price__max': Decimal('110.00')}
-
Min
price_min = models.Book.objects.aggregate(Min("price")) print(price_min) # {'price__min': Decimal('56.00')}
-
Sum
price_sum = models.Book.objects.aggregate(Sum("price")) print(price_sum) # {'price__sum': Decimal('555.00')}
-
Count
price_count = models.Book.objects.aggregate(Count("price")) print(price_count) # {'price__count': 7}
-
Avg
price_avg = models.Book.objects.aggregate(Avg("price")) print(price_avg) # {'price__avg': 79.285714}
分组查询
关键字:annotate
-
统计每本书作者数
book_author_count = models.Book.objects.annotate(count_author = Count("author")).values("count_author") print(book_author_count) # <QuerySet [{'count_author': 2}, {'count_author': 2}, {'count_author': 2}, {'count_author': 1}, {'count_author': 1}, {'count_author': 1}, {'count_author': 3}]>
-
统计出版社最便宜的书
publish_book_price_min = models.Publish.objects.annotate(min_price_book = Min("book__price")).values("min_price_book") print(publish_book_price_min) # <QuerySet [{'min_price_book': Decimal('56.00')}, {'min_price_book': Decimal('110.00')}, {'min_price_book': Decimal('65.00')}]>
F与Q查询
-
F查询
快到双十一了需要为所有的书籍提价10%
models.Book.objects.all().update(price=F("price")*1.1) 为所以的书籍提价10%
-
Q查询
我们知道filter的关系是and关系,我们很多时候需要or关系,所以就有了Q查询。
res = models.Book.objects.filter(Q(price__lt=60)|Q(price__gt=100)) # 价格小于60或价格大于100
数据库查询优化
- only和defer
- only:会将括号内的数据放到对象中,点该字段不需要再从数据库中查询,如果是不在括号内就会频繁的从数据库中拿去数据
- defer:不会将括号内的数据放到对象中,其他字段已经查询完毕,只要点了括号内的就会频繁从数据库中查询数据
- select_related和prefetch_related
- select_related:会自动连表,将连表后的数据放到对象中,并且括号内的只能是外键,并且多对多字段不能放
- prefetch_related:类似于子查询,只能放外键字段,并且多对多字段不能放
ORM中的事务
from django.db import transaction
with transaction.atomic():
# 在该代码块中所写的orm语句 同属于一个事务
对象序列化
# 将用户表的数据 查询出来 返回给前端
给前端的是一个大字典 字典里面的数据的一个个的字段
from django.core import serializers
def ser(request):
user_queryset = models.Book.objects.all() # 获取数据库中的书籍数据
res = serializers.serialize('json',user_queryset) # 将对象序列化成json对象
return render(request,'ser.html',locals())