创建表(建立模型)
创建表首先我们应该知道自己想要创建什么表,就比如老师,或者作者这一类的,字段就应该是他的姓名、年龄、之类的。
我们就用作者和书籍这一类来举例。
作者模型:作者姓名和年龄
作者详细模型:这个里面就是作者具体的详细信息。生日、手机号、家庭住址等信息
作者模型和作者是一对一的关系
出版社:出版社名称、地址
书籍:有书籍的名称,一本书也有可能有多个作者一个作者也可能写很多本书,所以他们两个之间是
多对多的关系(manytomany);一本书应该只有一个出版社,但是出版社可以出版很多本书,所以他和出版社应该是一对多的关系。
具体模型如下:
"""
作者表
"""
class Author(models.Model):
nid = models.AutoField(primary_key=True)
name=models.CharField( max_length=32)
age=models.IntegerField()
# 与AuthorDetail建立一对一的关系
authorDetail=models.OneToNoeFiled(to="AsuthorDetail")
"""
作者详细信息表
"""
class AuthorDetail(models.Model):
nid = models.AutoField(primary_key=True)
birthday=models.DateField()
telephone=models.BigIntegerField()
addr=models.CharField( max_length=64)
"""
出版社表
"""
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)
keepNum=models.IntegerField()<br> commentNum=models.IntegerField()
# 与Publish建立一对多的关系,外键字段建立在多的一方
publish=models.ForeignKey(to="Publish",to_field="nid")
# 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
authors=models.ManyToManyField(to='Author')
添加表记录
普通字段
两种方式:
1.
publish_obj=Publish(name="新华出版社",city="北京")
publish_obj.save() #将数据保存到数据库
2.
publish_obj=Publish.objects.create(name="新华出版社",city="北京")
外键字段
两种方式
1.
publish_obj
=
Publish.objects.get(nid
=
1
)
Book.objects.create(title
=
"金瓶眉"
,publishDate
=
"2012-12-12"
,price
=
665
,pageNum
=
334
,publish
=
publish_obj)
2.
Book.objects.create(title="平凡的世界",publishDate="2012-12-12",price=75,pageNum=334,publish_id=1)
多对多字段
book_obj=Book.objects.create(title="追风筝的人",publishDate="2012-12-12",price=69,pageNum=4521,publish_id=2)
author_lan=Author.objects.create(name="lan",age=21,authorDeatil=1)
author_cao=Author.objects.create(name="cao",age=26,authorDetil=2)
book_obj.authors.add(author_lan,author_cao)
# 将某个特定的 model 对象添加到被关联对象集合中。 ======= book_obj.authors.add(*[])
book_obj.authors.create()
#创建并保存一个新对象,然后将这个对象加到被关联对象的集合中,然后返回这个新对象。
解除关系
book_obj.authors.remove() 将某个特定的对象从被关联对象集合中除去也就是#book_obj.authors.remove(*[])
book_obj.authors.clear() 清空被关联的对象集合
set方法()
先清空,再设置,编辑书籍时就可以用到
注意:
对于所有的类型的关联字段,add()、create()、remove()和clear,set()都会马上更新数据库,也就是说,在关联的任何一端,都不需要再调用save()方法
直接赋值:
通过赋值一个新的可迭代的对象,关联对象集可以被整体替换掉。
>>> new_list
=
[obj1, obj2, obj3]
>>> e.related_set
=
new_list
如果外键关系满足null=True,关联管理器会在添加new_list中的内容之前,首先调用clear()方法来解除关联集中一切已存在对象的关联。否则, new_list中的对象会在已存在的关联的基础上被添加。
查询表记录
我们在这里再次将API相关查询写一下
<1> all(): 查询所有结果
<2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
<3> get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,
如果符合筛选条件的对象超过一个或者没有都会抛出错误。
<5> exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
<4> values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
model的实例化对象,而是一个可迭代的字典序列
<9> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
<6> order_by(*field): 对查询结果排序
<7> reverse(): 对查询结果反向排序
<8> distinct(): 从返回结果中剔除重复纪录
<10> count(): 返回数据库中匹配查询(QuerySet)的对象数量。
<11> first(): 返回第一条记录
<12> last(): 返回最后一条记录
<13> exists(): 如果QuerySet包含数据,就返回True,
否则返回False
双下划线之单表查询
models.User.objects.filter(id_lt=),id_gt=1) 获取id大于1且小于10的值
models.User.objects.filter(id_in=[11,55,88]) 获取id等于11,55,88的值
models.User.objects.exclude(id_id=[11,55,88]) 不等于这个的
models.Tb1.objects.
filter
(name__contains
=
"ven"
)
models.Tb1.objects.
filter
(name__icontains
=
"ven"
)
# icontains大小写不敏感
models.Tb1.objects.
filter
(id__range
=
[
1
,
2
])
# 范围bettwen and
startswith,istartswith, endswith, iendswith
基于对象的跨表查询
一对多查询(publish与Book)
正向按字段
查询nid=1的书籍的出版社所在的城市
book_obj=Book.objects.get(nid=1)
print(book_obj.publish.city)
# book_obj.publish 是nid=1的书籍对象关联的出版社对象
反向查询按表名
查询人民出版社出版过的所有书籍
publish=Publish.objects.filter(name="人民出版社")
book_list=publish.book_set.all() #与人民出版社关联的所有书籍对象集合
for book_obj in book_list:
print(book_obj.title)
一对一查询(Author与AuthorDetail)
正向查询(按字段:authorDetail)
#查询lan作者的手机号
author_obj=Author.objects.get(namae="lan")
print(author_obj.authorDetail.telphone)
反向查询(按表名:author)
#查询所有住在北京的作者的姓名
authorDetail_list=AuthorDetail.objects.filter(addr="beijing")
for obj in authorDetail_list:
print(obj.author.name)
多对多查询(Author与Book)
正向查询(按字段:authors)
#平凡的世界所有的作者的名字以及手机号
book_obj=Book.objects.filter(title="平凡的世界").first()
author_list=book_obj.authors.all()
for obj in author_list:
print(obj.name.obj.authorDetail.telphone)
反向查询(按表名:book_set)
查询lan出过的所有书籍的名字
author_obj=author.objects.filter(name="lan").first()
book_obj=author_obj.book_set.all()
for obj in book_obj:
print(book_obj.title)
基于双下划线的跨表查询
这是一种高效只管的查询表中关系的方式,可以自动确认sql join联系
正向查询按字段,反向查询按表名
用几道练习题来再次熟悉一下
1.查询人民出版社出版过的所有书籍的名字与价格(一对多)
正向查询按字段
Book.objects.filter(publish__name="人民出版社").values_list("title","price")
反向查询按表名
obj=Publish.objects.filter(name="人民出版社").values_list("book__title","book__price")
2.查询lan出过的所有的书籍的名字(多对多)
正向查询按字段 authors
obj=Book.objects.filter(authors__name="lan").values_list("title")
反向查询按表名
Author.objects.filter(name="lan").values_list("book__title")
3.查询人民出版社出版过的所有书籍的名字以及作者的名字
反向查询
obj=Publish.objects.filter(name="人民出版社").values_list("book__title","book__authors__name")
正向查询
Book.objects.filter(publish__name="人民出版社").values("title","authors__name")
4.查询手机号以151开头的作者出版过的所有书籍名称以及出版社名称
Book.objects.filter(authors__authorDetail__telephone__startwith=="151").values_list("title","publish__name")
ps反向查询时,如果定义了related_name,则用related_name替换表名
,例如: publish = ForeignKey(Blog, related_name='bookList'):
查询人民出版社出版过的所有书籍的名字与价格
反向查询不再是按表名,而是related_name:bookList
obj=Publish.objects.filter(name="人民出版社").values_list("bookList__title","bookList__price")
聚合查询与分组查询
聚合:aggregate(*args,**kwargs)
计算所有图书的平均价格
from django,db.models import Avg
Book,objects,all().aggregate(Avg("price"))
{
'price__avg'
:
34.35
}
aggregate是queryset的一个终止子句,它返回的是一个包含一些键值对的字典,键的名称是聚合值的标示符,值是计算出来的聚合值,键的名称是按照字段和聚合函数的名称自动生成出来的,如果你想要为聚合值指定一个名称,可以向聚合子句提供它。
Bookobjects.aggregate(average_price=Avg("price"))
{
'average_price'
:
34.35
}
如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:
from
django.db.models
import
Avg,
Max
,
Min
Book.objects.faggregate(Avg("price"),Max("price"),Min(price))
{
'price__avg'
:
34.35
,
'price__max'
: Decimal(
'81.20'
),
'price__min'
: Decimal(
'12.99'
)}
分组:annotate()
为调用的queryset中的每一个对象都生成一个独立的统计值(统计方法用聚合函数)
1.练习:统计每一本书的作者个数
bookList=Book.objects.annotate(authorsNum=Count("authors"))
for book_obj in bookList:
print(book_obj.title.authorsNum)
2.如果想对所查询对象的关联对象进行聚合
练习:统计没一个出版社最便宜的书
publishList=Publish.objects.annotate(MinPrice=Min("book__price"))
for publish_obj in publishList:
print(publish_obj.name,publish_obj.MinPrice)
annotate的返回值是queryset,如果不想遍历对象,可以用valueslist:
query=Publish.pbjects.annotate(MinPrice=Min("book__price")).values_list("name","Minprice")
3.统计每一本以py开头的书籍的作者个数
queryResult=Book.objects .filter(title__startswith="Py").annotate(num_authors=Count('authors'))
4.统计不止一个作者的图书
Book.objects.annotate(num_authors=Count('authors')).filter(num_authors__gt=1)
5.根据一本书作者的数量的多少飞查询集queryset进行排序
Book.objects.annotate(num_authors=Count("authors")).order_by('num_authors')
6.按照各个作者出的书的总价格
# 按author表的所有字段 group by
obj=Author.objects.annotate(SumPrice=Sum("book__price")).values_list("name","SumPrice")
# 按authors__name group by
Book.objects.values("author__name").annotate(SumPrice=Sum("price")).values_list("authors__name","SumPrice")
F查询和Q查询
F是用来做比较的
F查询
1.查询评论数大于收藏数的书籍
from django.db.models import F
Book.objects.filter(commentNum_lt=F("keepNum"))
Django支持F()对象之间以及F()对象和常数之间的加减乘除和取模的操作
2.查询评论数大于收藏数2倍的书籍
Book,objects.filter(commentNum__lt=F("keepNum")*2)
修改操作也可以用F函数,比如将一本书的价格提高30元
Book.objects.all().update(price=F("price")+30)
Q查询
q查询类似于or
from django.db.models import Q
q对象可以使用&和|符组合起来,当一个操作符在两个Q对象上使用时,它会产生一个新的Q对象
BookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))