博客园项目前夕之ORM操作回顾

创建表(建立模型)

创建表首先我们应该知道自己想要创建什么表,就比如老师,或者作者这一类的,字段就应该是他的姓名、年龄、之类的。

我们就用作者和书籍这一类来举例。

作者模型:作者姓名和年龄

作者详细模型:这个里面就是作者具体的详细信息。生日、手机号、家庭住址等信息

作者模型和作者是一对一的关系

出版社:出版社名称、地址

书籍:有书籍的名称,一本书也有可能有多个作者一个作者也可能写很多本书,所以他们两个之间是

多对多的关系(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"))

 

posted @ 2018-02-03 15:57  兰博~~  阅读(173)  评论(0编辑  收藏  举报