DjangoORM常用的操作 项目位置 G:asdORMdemo
实例:我们来假定下面这些概念,字段和关系
作者模型:一个作者有姓名和年龄。
作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one)
出版商模型:出版商有名称,所在城市以及email。
书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。
建立关系表如下:
<wiz_code_mirror>
38
1
from django.db import models
2
3
4
class Author(models.Model):
5
nid = models.AutoField(primary_key=True)
6
name=models.CharField( max_length=32)
7
age=models.IntegerField()
8
9
# 与AuthorDetail建立一对一的关系
10
authorDetail=models.OneToOneField(to="AuthorDetail", on_delete=models.CASCADE)
11
12
13
class AuthorDetail(models.Model):
14
15
nid = models.AutoField(primary_key=True)
16
birthday=models.DateField()
17
telephone=models.BigIntegerField()
18
addr=models.CharField( max_length=64)
19
20
21
class Publish(models.Model):
22
nid = models.AutoField(primary_key=True)
23
name=models.CharField( max_length=32)
24
city=models.CharField( max_length=32)
25
email=models.EmailField()
26
27
28
class Book(models.Model):
29
nid = models.AutoField(primary_key=True)
30
title = models.CharField( max_length=32)
31
publishDate=models.DateField()
32
price=models.DecimalField(max_digits=5,decimal_places=2)
33
34
# 与Publish建立一对多的关系,外键字段建立在多的一方
35
publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
36
# 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
37
authors=models.ManyToManyField(to='Author',)
38
生成表如下:
添加表记录
操作前先简单的录入一些数据:
publish表:
author表:
authordetail表:
<wiz_code_mirror>
x
1
# 一对多创建表
2
# 方式一: 通过实例一个对象
3
publish_obj = Publish.objects.get(pk=1)
4
book_obj = Book.objects.create(title="西游记", publishDate="2013-03-03", publish=publish_obj, price=100.00)
5
6
# 方式二: 通过外键字段 + __id
7
book_obj = Book.objects.create(title="西游记", publishDate="2012-12-12", price=100.00, publish_id=1)
基于对象的查询
一对多查询 :
<wiz_code_mirror>
x
1
# 正向查询(按字段:publish):
2
book_obj = Book.objects.get(title="西游记").publish.city
3
print(book_obj)
4
5
# 反向查询(按表名:book_set):
6
book_list = Publish.objects.get(id=1).book_set.all()
7
for book_obj in book_list:
8
print(book_obj.title)
一对一查询:
<wiz_code_mirror>
15
1
# 正向查询(按字段:authorDetail):
2
3
egon=Author.objects.filter(name="egon").first()
4
print(egon.authorDetail.telephone)
5
6
7
# 反向查询(按表名:author):
8
# 查询所有住址在北京的作者的姓名
9
10
authorDetail_list=AuthorDetail.objects.filter(addr="beijing")
11
for obj in authorDetail_list:
12
print(obj.author.name)
13
14
author_obj = AuthorDetail.objects.get(pk=1).author.name
15
print(author_obj)
多对多查询:
<wiz_code_mirror>
13
1
# 正向查询(按字段:authors)
2
# 金瓶眉所有作者的名字以及手机号
3
author_list = Book.objects.get(title="金瓶眉").authors.all()
4
print(author_list)
5
for author in author_list:
6
print(author.name, author.authorDetail.telephone)
7
8
# 反向查询(按表名:book_set):
9
# 查询egon出过的所有书籍的名字
10
book_list = Author.objects.get(name="yuan").book_set.all()
11
for book in book_list:
12
print(book.title)
13
注意这里还可以设置related_name给外键表重命名:表名_set换成外键表的重命名即可
基于Queryset的跨表查询
正向查询按字段,反向查询按表名小写用来告诉ORM引擎join哪张表 他们的本质都是进行了跨表查询
一对多:查询苹果出版社出版过的所有书籍的名字与价格(一对多)
<wiz_code_mirror>
18
1
# 练习: 查询苹果出版社出版过的所有书籍的名字与价格(一对多)
2
3
# --------------------基于Queryset的跨表查询------------------
4
# 一对多查询
5
# 反向查询
6
# 练习: 查询苹果出版社出版过的所有书籍的名字与价格(一对多)
7
book_list = Publish.objects.filter(name="苹果出版社").values("book__title", "book__price")
8
print(book_list)
9
10
# 正向查询Book中的字段
11
book_list = Book.objects.filter(publish__name="苹果出版社").values("title", "price")
12
print(book_list)
13
14
15
# 添加了related_name: publish=models.ForeignKey(to="Publish", to_field="nid", related_name="pub", on_delete=models.CASCADE)
16
# 反向查询添加了related_name
17
book_list = Publish.objects.filter(name="苹果出版社").values("books__title", "books__price")
18
print(book_list)
多对多:查询alex出过的所有书籍的名字(多对多)
<wiz_code_mirror>
8
1
# 练习: 查询alex出过的所有书籍的名字(多对多)
2
# 反向
3
book_obj = Author.objects.filter(name="alex").values("book__title")
4
print(book_obj)
5
6
# 正向
7
book_list = Book.objects.filter(authors__name="alex").values("title")
8
print(book_list)
一对一:查询alex的手机号
<wiz_code_mirror>
5
1
# 正向查询
2
ret=Author.objects.filter(name="alex").values("authordetail__telephone")
3
4
# 反向查询
5
ret=AuthorDetail.objects.filter(author__name="alex").values("telephone")
进阶练习
<wiz_code_mirror>
10
1
# 查询苹果出版社出版过的所有书籍的名字以及作者的姓名
2
3
ret = Book.objects.filter(publish__name="苹果出版社").values("title", "authors__authorDetail__addr")
4
print(ret)
5
6
# 练习: 手机号以133开头的作者出版过的所有书籍名称以及出版社名称
7
8
ret = Book.objects.filter(authors__authorDetail__telephone__regex="133").values("title", "publish__name")
9
print(ret)
10
聚合查询和分组查询
聚合查询就是mysql里面的聚合函数!
aggregate
<wiz_code_mirror>
15
1
from django.db.models import Avg, Sum, Max, Min, Count
2
3
4
avg_price = Book.objects.all().aggregate(Avg("price"))
5
print(avg_price)
6
>>> {'price__avg': 19.79} # 返回一个字典
7
8
# 指定一个键
9
avg_price = (Book.objects.all().aggregate(print_avg=Avg("price")))
10
print(avg_price)
11
>>> {'print_avg': 19.79}
12
13
price = Book.objects.all().aggregate(Avg("price"), Sum("price"), Max("price"))
14
print(price)
15
>>> {'price__avg': 19.79, 'price__sum': Decimal('98.95'), 'price__max': Decimal('29.00')}
分组查询就是mysql里面的group_by!
annotate
<wiz_code_mirror>
x
1
# 查询每本书作者的个数
2
3
# select SUM(author_id), book_id from app01_author_books GROUP BY app01_author_books.book_id
4
ret = Book.objects.all().annotate(author_num=Count("author"))
5
print(ret)
6
# <QuerySet [<Book: 跟pontoon学python>, <Book: pontoon想跟dandylee谈朋友>, <Book: 特别想跟dandylee谈朋友>, <Book: pontoon一定要努力学好python>, <Book: 争取一入行就跟取加dandylee的微信>]>
7
8
注意这里!他相当于给Book表增加了一个字段author_num(作者的数量)
9
for book in ret:
10
print("书名:{}, 作者数量:{}".format(book.title, book.author_num))
11
>>> 书名:特别想跟dandylee谈朋友, 作者数量:2
12
书名:pontoon一定要努力学好python, 作者数量:0
13
书名:争取一入行就跟取加dandylee的微信, 作者数量:0
14
15
--------------------------------------------------------------------------------------------------------------------------------
16
# 查询作者数量大于1的书
17
ret = Book.objects.all().annotate(author_num=Count("author")).filter(author_num__gt=1)
18
print(ret)
19
20
>>><QuerySet [<Book: 跟pontoon学python>, <Book: 特别想跟dandylee谈朋友>]>
21
# ret = Book.objects.all().annotate(author_num=Count("author"))得到的是一个查询集,可以用filter进行筛选(Having)
22
23
for book in ret:
24
print("书名: %s, 作者的个数: %s" % (book.title, book.author_num))
25
26
>>>书名: 跟pontoon学python, 作者的个数: 3
27
书名: 特别想跟dandylee谈朋友, 作者的个数: 2
28
F查询就是mySQL里面的两个字段进行比较
F
给 book表增加两个新字段
<wiz_code_mirror>
9
1
class Book(models.Model):
2
id = models.AutoField(primary_key=True)
3
price = models.DecimalField(max_digits=5, decimal_places=2, default=0.00)
4
# 库存
5
kucun = models.IntegerField(default=0)
6
# 售出
7
sail = models.IntegerField(default=0)
8
title = models.CharField(max_length=32)
9
publisher = models.ForeignKey(to="Publisher", to_field='id', on_delete=models.CASCADE, related_name="books")
<wiz_code_mirror>
1
1
Q 或运算 相当与mySQL里面的 or
<wiz_code_mirror>
1
# 查询卖出数卖出数小于100 价格小于10.00的书
2
ret = Book.objects.filter(Q(sail__lt=100) | Q(price__lt=10.00))
3
print(ret)
4
5
# 查询# 查询卖出数卖出数小于100 价格小于10.00的书,书名包含pontoon的书
6
ret = Book.objects.filter(Q(sail__lt=100) | Q(price__lt=10.00), title__contains="pontoon")
7
print(ret)