一.单表操作
增删改查:
①Objects管理器,里面封装着增删改查的所有方法.
查:
models.类名.objects.all() 取所有
models.类名.objects.get() 取一个, 取不到就报错
models.类名.objects.filter(条件) 根据条件查找,返回的是[object1, objdect2 ...]
models.类名.objects.exclude(条件) 排除满足条件的
models.类名.objects.first()
models.类名.objects.last()
增加:
Create方法有返回值,返回的是一个对象。
models.类名.objects.create(name="王永飞", age=18)
obj = models.类名(name="王永飞", age=18)
bj.save()
删除:models.类名.objects.filter(age=18).delete()
修改:models.类名.objects.filter(age=18).update(name="装嫩")
注意:单个对象不能调用update
obj = models.类名.objects.get(id=2)
obj.name = "一枝花"
obj.save()
二. ORM查询API
(1) 这些查询API只有返回数据对象的才可以”.”表结构中的字段,返回其他数据类型的都不 可以”.”表结构中的字段,因为表是以类的形式写的,只有对象才可以用”.”调用属性.
(2) 返回对象的数据类型,之后不能够·其他的ORM查询API.
(3) 终止字句:终止字句是后面不能再继续”.”的API方法,count就是终止字句.
(4) 配合filter做查询的各种查询方法,如果后面不再点返回非QuerySet对象的方法,返回值是QuerySet。
(5) QuerySet的特点
a.可切片
①不支持不支持负的索引
②一旦切片就不能继续first()了
Cannot filter a query once a slice has been taken.
切片后的结果还是列表(queryset)
可迭代
articleList=models.Article.objects.all()
for article in articleList:
print(article.title)
b.惰性查询
注意是惰性查询,不是惰性创建
创建的查询语句不会自动带来数据库的访问,查询语句需要求值时才会执行。
s=models.Book.objects.all()[:2] # not hits database
print(s) # hits database
# , ]>
for book in s: # hits database
print(book.title) # hits database
# 打印结果:
# linux宝典
(6)get方法的特点
get方法返回的是model对象,返回值只能由一个,如果超过一个或者没有返回值,则查询结果报错。
返回QuerySet的:
- .all()
- .filter()
括号中:字段1=值1,字段2=值2
其中逗号的作用表示:且
也表示:是同一条记录的字段
不传参数,表示取所有的 - values()
返回值是列表套字典的形式
注意:传入的参数是表中的字段,而且传入必须是”字段”的形式。 - .values_list()
返回值是列表套元组的形式
注意:传入的参数是表中的字段,而且传入必须是”字段”的形式。 - exclude()
与所给筛选条件不匹配的对象 - order_by()
对结果进行排序
在括号里面得值加负号,堆排序结果再次反序 - reverse()
对结果进行反向排序
在括号里面得值加负号,堆排序结果再次反序 - distinct()
从返回结果中剔除重复纪录
返回单个数据对象:
- first()
返回第一条记录 - last()
返回最后一条记录 - get()
返回与所给筛选条件相匹配的对象,返回结果有且只有一个,
如果符合筛选条件的对象超过一个或者没有都会抛出错误
返回布尔值的:
- exists()
如果QuerySet包含数据,就返回True,否则返回False
ret=Book.objects.all().first()
应用:以下ret=Book.objects.all().exists()虽然返回的是布尔值,但实际上代码再运行的时候,只要能够查询到一条,就返回为True,运行效率比较高。
ret=Book.objects.all().exists()
if ret:
pass
返回数字的:
- count()
- 注意:count取出来的是一个数字,不能再继续点下去
配合filter()来做各种查询。
- id__gt=1 大于
- id__lt=3 小于
- id__in=[1,2,3] 在之内
是否在一个给定的列表中。 - id__range=[1,5]
包含的范围。前包含,也后包含 - name__contains="s"
icontains忽略大小写的包含匹配 - name__icontains="s"
不忽略大小写的包含匹配 - name__startwith="a"
startswith大小写敏感的以....开头。 - name__endswith="x"
endswith大小写敏感的以....结尾。 - first_day__year="2018"
- cname__isnull=True *!
据 SQL 查询是空 IS NULL 还是非空 IS NOT NULL,返回相应的 True 或 False。
示例
# model.py
class Book():
title=model.CharField(max_length=32)
单表操作:
添加:
book_obj=Book.objects.create(title="python",price=123)
book_obj=Book(title="python",price=123)
book_obj.save()
查询:
1.Book.objects.all() # QuerySet() [obj1,obj2,....]
2.Book.objects.filter(price__gt=100,id__gt=5) # QuerySet() [obj1,obj2,....]
3.Book.objects.get(title="python") # model对象
4.Book.objects.exclude()
5.Book.objects.all().order_by("-price")
6.Book.objects.all().values("title","id","publish__name") # QuerySet() []
7.Book.objects.all().values_list()
8.Book.objects.all().values("title","id","publish__name").distinct()
9.Book.objects.all().count() #终止子句
10.Book.objects.all().first() model对象
11.Book.objects.all().last() model对象
12.Book.objects.all()[2:5]
注意Values的原理
l=[]
for obj in Book.objects.all():
temp={}
temp["title"]=obj.title
temp["id"]=obj.id
temp["publish__name"]=obj.publish.name # QuerySet() []
l.append(temp)
删除:
Book.objects.all().delete()
修改:
Book.objects.filter(id=1).update(title="linux") --- 推荐
obj=Book.objects.filter(id=1)[0]
obj.title="linux"
obj.save()
三.多表查询
表之间的关系
- 一对多
- 一对一
①对应关系:
类 --> 表
类的属性 --> 字段
实例对象 --> 一条数据(数据行)
②数据库层面:
外键 对应 另外一个表的一条记录
③ORM层面:
假如在models的某张表中外键是字段为“s”,那么在表中的字段为“s_id”
外键对应 另外一个表的一个对象
Student_objs.s --->指的是对象
student_obj.s_id --> 具体的值
④正向查询与反向查询的定义
通过在models.py中foreignKey,或OneToOneField或ManyToMany所在表结构对应的表,查询另一张表叫做正向查询。反之叫做反向查询。
- 多对多
老师 和 班级
通过第三张表关联
Teacher表
id tname
1 Alex
2 Egon
3 yuan
Class表
id cname
1 1班
2 2班
3 3班
TeacherToClass
id teacher_id class_id
1 1 1
2 1 2
3 1 3
4 2 1
5 2 3
6 1 1
4.双下划线:
双下划线表示跨表,将两张表合在一起进行查询。
5.三种创建多对多关系的方法
①通过外键创建创建,自定义第三张表,通过外键关联上面两张表
class Class(models.Model):
id = models.AutoField(primary_key=True) # 主键
cname = models.CharField(max_length=32) # 班级名称
first_day = models.DateField() # 开班时间
class Teacher(models.Model):
tname = models.CharField(max_length=32)
class Teacher2Class(models.Model):
teacher = models.ForeignKey(to="Teacher")
the_class = models.ForeignKey(to="Class")
class Meta:
unique_together = ("teacher", "the_class")
②通过ManyToMany创建
自动创建出的第三张表,django就会自动不允许有相同的记录(不用判断id)
class Class(models.Model):
id = models.AutoField(primary_key=True) # 主键
cname = models.CharField(max_length=32) # 班级名称
first_day = models.DateField() # 开班时间
class Teacher(models.Model):
tname = models.CharField(max_length=32)
# 通过ManyToManyField自动创建第三张表
cid = models.ManyToManyField(to="Class", related_name="teachers")
③通过外键和ManyToMany创建
通过ManyToManyField和手动创建第三张表,相对于第二种方法优点是可以在第三张表中添加字段。
class Class(models.Model):
id = models.AutoField(primary_key=True) # 主键
cname = models.CharField(max_length=32) # 班级名称
first_day = models.DateField() # 开班时间
class Teacher(models.Model):
tname = models.CharField(max_length=32
cid = models.ManyToManyField(to="Class", through="Teacher2Class", through_fields=("teacher", "the_class"))
class Teacher2Class(models.Model):
teacher = models.ForeignKey(to="Teacher")
the_class = models.ForeignKey(to="Class")
class Meta:
unique_together = ("teacher", "the_class")
查询规则:
注意:下面的obj代表对象
①单表查询 只在一张表里查各种字段
②一对一
正向查:obj.外键.属性
反向查:obj.表名
②一对多(外键)
正向:obj.外键.属性
反向查:obj.表名set.
注意:
如果在外键的字段中加了related_name属性,则按照该属性的值来反向查找
例如: publish = ForeignKey(Blog, related_name='bookList')
obj.表名set.则替换为obj.bookList.
③多对多
正向查:obj.多对多字段名.all() --> QuerySet()
反向查:obj.表名set.all() --> QuerySet()
④双下划线 表示跨表查询
正向: 关联的字段名另外一张表的字段名
反向: 另外一张表的表名_另外一张表的字段名
聚合和分组
from django.db.models import Avg, Max, Min,sum,count
聚合查询就是在一张表中进行查询
①aggregate()是QuerySet 的一个终止子句。不能够再继续往下点了。
②返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。
③可以聚合值指定一个名称。
- 查询所有书籍中最高的价格
class Book(models.Model):
price = models.CharField(max_length=32)
ret=Book.objects.all().aggregate(m=Max("price"))
print(ret)
打印结果:
Book.objects.all().aggregate(m=Max("price"))
{'m': '30'}
Ps:例子相当于sql语句 select Max("price") from book
分组查询:
分组的标准:
题目中有关键字“每”,一般要进行分组,关键字为annotate
如果是all()的话,则publish表中的每一条记录是分类标准,也可以filter筛选一些内容作为分类标准。
Publish.objects.all().annotate(c=Count("book__id")).values("c","book__title")
结果:
原生sql语句:
SELECT "app01_book"."title", COUNT("app01_book"."id") AS "c"
FROM "app01_publish" LEFT OUTER JOIN "app01_book" ON ("app01_publish"."id" = "app01_book"."publish_id")
GROUP BY "app01_publish"."id", "app01_publish"."name", "app01_book"."title" LIMIT 21; args=()
①在这里publish表和book表拼成一张表,以Publish表中的每一条记录为分组标准进行查询
②可以聚合值指定一个名称。此时相当于在拼成的表中添加了一个新的字段,字段的名称就是重新指定的名称**
③分类查出来的结果是QuerySet类型,可以继续点。
④注意:合成的那张表在pycharm里面看不到,在其他地方也没发现能看到。
⑤all()可以省去,简写为Publish.objects.annotate(c=Count("book__id")).values("c","book__title")**
1.每一个出版社出版过得书籍的最高价格*
ret=Publish.objects.all().annotate(m=Max("book__price")).values("name","m")
print(ret)
2.****每一个作者出版过的书籍的个数
ret=Author.objects.all().annotate(c=Count("book")).values("name","c")
找出最大值:
分组和聚合的区别:分组是找出每组的最大值,聚合是指出所有的值当中的最大值。
专题练习:
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
# 与AuthorDetail建立一对一的关系
ad = models.OneToOneField(to="AuthorDetail")
class AuthorDetail(models.Model):
birthday = models.DateField()
telephone = models.BigIntegerField()
addr = models.CharField(max_length=64)
class Publish(models.Model):
name = models.CharField(max_length=32)
city = models.CharField(max_length=32)
email = models.EmailField()
class Book(models.Model):
title = models.CharField(max_length=32)
publishDate = models.DateField()
price = models.DecimalField(max_digits=5, decimal_places=2)
keepNum = models.IntegerField()
commentNum = models.IntegerField()
与Publish建立一对多的关系,外键字段建立在多的一方
publish = models.ForeignKey(to="Publish", to_field="nid")
与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
authors = models.ManyToManyField(to='Author')
三个关联字段:
与AuthorDetail建立一对一的关系
ad = models.OneToOneField(to="AuthorDetail")
与Publish建立一对多的关系,外键字段建立在多的一方
publish = models.ForeignKey(to="Publish", to_field="nid")
与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
authors = models.ManyToManyField(to='Author')
一对多:
正向查询按字段:publis
Book------------------------------->Publish
反向查询按表名小写_set
多对多:
正向查询按字段:authors
Book--------------------------------->Author
反向查询按表名小写_set
一对一
正向查询按字段:ad
Author------------------------->AuthorDetail
反向查询按表名小写
基于对象查询(子查询)
基于Queryset查询(join查询)
单表查询
查询id为1 的书籍的价格
Book.objects.filter(id=1).values("price")
多表查询
一对多
1 .查询python这本书的出版社的城市和email
book_obj=Book.objects.filter(title="python").first()
print(book_obj.publish.email,book_obj.publish.city)
2.查询北京出版社出版社过得所有书籍名称
publish_obj=Publish.objects.filter(name="南京出版社").first()
book_list=publish_obj.book_set.all() # Queryset[obj,obj]
for obj in book_list:
print(obj.title)
多对多
- 查询go书籍的作者名称和年龄
book_obj=Book.objects.filter(title="go").first()
author_list=book_obj.authors.all()
for obj in author_list:
print(obj.name,obj.age)
2.alex出版过得所有书籍的名称和价格
author_obj=Author.objects.filter(name="alex").first()
book_list=author_obj.book_set.all()
for obj in book_list:
print(obj.title,obj.price)
一对一
1.查询alex的电话号码
author_obj = Author.objects.filter(name="alex").first()
print(author_obj.ad.telephone)
2.查询电话号码以123开头的作者名称
ad_obj=AuthorDetail.objects.filter(telephone__startswith=123).first()
print(ad_obj.author.name)
基于QuerySet和双下划线的多表查询
一对多
1.查询python这本书的出版社的城市和email
ret=Book.objects.filter(title="python").values("publish__city","publish__email")
print(ret)
values("publish__city"):
book_list=Book.objects.filter(title="python")
temp=[]
for obj in book_list:
d={}
d["publish__city"]=obj.publish.city
d["publish__email"]=obj.publish.email
temp.append(d)
return temp #
2.查询北京出版社出版社过得所有书籍名称
ret=Publish.objects.all().values("book__title")
print(ret)
publish_list=Publish.objects.filter(name="北京出版社")
temp=[]
for obj in publish_list:
book_list=obj.book_set.all()
for book in book_list:
d={}
d["book__title"]=book.title
temp.append(d)
return temp
多对多
1.查询go书籍的作者名称和年龄
ret=Book.objects.filter(title="go").values("authors__name","authors__age")
ret=Book.objects.filter(title="go").values_list("authors__name","authors__age")
print(ret)# [('alex', 33), ('egon', 38)]>
2.alex出版过得所有书籍的名称和价格
ret=Author.objects.filter(name="alex").values("book__title","book__price")
一对一
1.查询alex的电话号码
ret=Author.objects.filter(name="alex").values("ad__telephone")
- 查询电话号码以123开头的作者名称
ret=AuthorDetail.objects.filter(telephone__startswith=123).values("author__name")
print(ret)
扩展查询
1.查询python这本书的出版社的城市和email
ret=Book.objects.filter(title="python").values("publish__city")
ret=Publish.objects.filter(book__title="python").values("email","city")
2.查询go书籍的作者名称和年龄
ret=Book.objects.filter(title="go").values("authors__name", "authors__age")----基表是book
Author.objects.filter(book__title="go").values("name","age")------------------------基表是author
ORM 跨表查询
class Book(models.Model):
title = models.CharField( max_length=32)
publish=models.ForeignKey(to="Publish",to_field="id")
authors=models.ManyToManyField(to='Author',related_name='bookList')
class Publish(models.Model):
name=models.CharField( max_length=32)
class Author(models.Model):
name=models.CharField( max_length=32)
ad=models.OneToOneField("AuthorDetail")
class AuthorDetail(models.Model):
telephone=models.BigIntegerField()
基于对象查询(sql:子查询)
一对多的关系****(Publish--Book)
正向查询,按字段:
查询python这本书的出版社所在的名称
book_obj=Book.objects.filter(title="python").first()
print(book_obj.publish.name)
反向查询,按表名小写_set:
人民出版社出版过的所有书籍名称
publish_obj=Publish.objects.filter(name="人民出版社出版").first()
print(publish_obj.book_set.all())
for obj in publish_obj.book_set.all():
print(obj.title)
多对多的关系
正向查询,按字段:
python这本书所有作者的名字
book_obj=Book.objects.filter(title="python").first()
book_obj.authors.all()
反向查询,按表名小写_set:
alex出版过的所有书籍名称
alex=Author.objects.filter(name="alex").first()
alex.bookList.all()
一对一的关系
正向查询,按字段:
查询alex的手机号
alex=Author.objects.filter(name="alex").first()
alex.ad.telephone
反向查询:按表名小写
以151开头的手机号的作者的名字
ad=AuthorDetail.objects.get(telephone__startswith="151")
ad.author.name
基于****Queryset****和 __****(****sql****:****join****语句)****:
正向查询,按字段
反向查询,按表名小写
一对多的关系(Publish--Book)
查询python这本书的所在出版社的名称
Book.objects.filter(title="python").values("publish__name")
for obj in Book.objects.filter(title="python"):
temp={}
temp["publish__name"]=obj.publish.name
人民出版社出版过的所有书籍名称
Publish.objects.filter(name="人民出版社出版").values("book__title")
多对多的关系
python这本书所有作者的名字
Book.objects.filter(title="python").values("authors__name")
alex出版过的所有书籍名称
Author.objects.filter(name="alex").values("book__title")
一对一的关系
查询alex的手机号
Author.objects.filter(name="alex").values("ad__telephone")
以151开头的手机号的作者的名字
AuthorDetail.objects.filter(telephone__startswith="151").values("author__name")
扩展:
练习1:
查询python这本书的所在出版社的名称
Book.objects.filter(title="python").values("publish__name")
Publish.objects.filter(book__title="python").values("name")
练习2:
手机号以151开头的作者出版过的所有书籍名称以及出版社名称
Book.objects.filter(authors__ad__telephone__startswith="151").values("title","publish__name")
一对多的添加
class Publish(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
city = models.CharField(max_length=32)
email = models.EmailField()
class Book(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField(max_length=32)
publishDate = models.DateField()
price = models.DecimalField(max_digits=5, decimal_places=2)
publish = models.ForeignKey(to="Publish", to_field="nid")
注意:此时在另外一张表中数据不存在,也可以创建外键,手动在表格中添加也可以。
Book.objects.create(title="****金瓶眉****",publishDate="2012-12-12",price=665,publish_id=1)
publish_obj = Publish.objects.get(nid=1)
Book.objects.create(title="金瓶眉", publishDate="2012-12-12", price=665,publish=publish_obj)
多对多关系的增删改
class Author(models.Model):
name =models.CharField(max_length=12)
class Book(models.Model):
title =models.CharField(max_length=100)
authors = models.ManyToManyField("Author")
Author表
book 表
id title
1 python
book_authors
id book_id author_id
book_obj=Book.objects.create(title="python")
Alex=Author.objects.get(name="alex")
Egon=Author.objects.get(name="egon")
Wu=Author.objects.get(name="wu")
author_list=Author.objects.all()
注意:
(1)
Objects未封装add(),set(),remove(),clear()方法,使用着几个方法的时候不要用objects,否则会报错。
(2)如果在这些方法中传入多个数据,必须使用号进行打散。
(3)语法格式:对象.属性.方法
Add()方法
传入的参数对象,传入其他类型的参数,会报错
传入数据不是对象,必须使用打散使之变成对象,若只有一个数据直接传入即可,不必使用。
结果在第三张表(关联表)中创建数据
(4)代码步骤
首先确定是正查还是反查
获取对象
获取数据,将这些数据放到参数的位置
拼写代码进行操作
Create()方法
b=Book.objects.create(title="c++")------》》在book表中创建一条数据
e=b.authors.create(name="alex")-------》》通过字段在author表中创建一条数据
这两条记录的关系在第三张表中自动创建
Add()方法
book_obj.authors.add([alex,wu,egon])
book_obj.authors.add(author_list)
Remove()方法,
传入的参数是对象,传入的参数不是对象会报错。
传入多个数据必须置于列表当中,且必须打散,若只有一个数据直接传入即可,不必置于列表中。
结果在第三张表(关联表)中删除关联表中相应的记录,不影响其他表中的数据。
book_obj.authors.remove([alex,wu])
book_obj.authors.remove(egon)
Clear()方法
不必传入参数
把关联表中的记录全部删除,不影响其他的表
book_obj.authors.clear()
注意:支持反向查询的语法即:表名_set
b2=Author.objects.create(name="egon")------在author表中的创建一条记录
C2=b2.book_set.create(title="python")--------在Book表中创建一条记录
这两条记录的关系在第三张表中自动创建
d=Author(name="wu")
d.save(force_insert=True)------------不会在第三张表中自动创建
author_obj=Author.objects.filter(id=3).first()
book_list=Book.objects.all()
author_obj.book_set.add(*book_list)
(这里假设第三张表是空的)
author_obj=Author.objects.filter(id=3).first()
book_list=Book.objects.filter(id=3).first()
author_obj.book_set.remove(book_list)
Clear()方法
author_obj.book_set.clear()