Django之ORM跨表操作

一、准备数据库

models.py文件内容:

from django.db import models
# Create your models here.
class Book(models.Model):
    title=models.CharField(max_length=32)
    price=models.DecimalField(max_digits=6,decimal_places=2)
    create_time=models.DateField()
    memo=models.CharField(max_length=32,default="")
    publish=models.ForeignKey(to="Publish",default=1)       #定义一对多关系,会在book表添加publish_id字段
    author=models.ManyToManyField("Author")                 #定义多对多关系,会专门生成一张book和author的关系表
    def __str__(self):
        return self.title
class Publish(models.Model):
    name=models.CharField(max_length=32)
    email=models.CharField(max_length=32)
class Author(models.Model):
    name=models.CharField(max_length=32)
    def __str__(self):return self.name
    
class AuthorDetail(models.Model):
    tel=models.CharField(max_length=32)
    email=models.EmailField()
    author=models.OneToOneField("Author")
    def __str__(self):return self.email


#执行下面python语句生成相关表

python3 manage.py makemigrations
python3 manage.py migrate


添加数据后各个表数据如下:

QQ截图20180422103401.png                                                   QQ截图20180422103335.png


QQ截图20180422103306.png  QQ截图20180422103223.png


QQ截图20180422103247.png

二、基于对象的跨表查询

1、一对一关系

(1)查询wang的手机号(反向查询,按表名小写)

obj = Author.objects.filter(name="wang").first()                           # 得到name="wang"的作者的对象
print(obj.authordetail.tel)                    # obj.authordetail表名得到作者对应的详细信息对象,再 .tel得到结果 18971232312

(2)查询手机号为13451222125的作者的名字 (正向查询,按字段)

obj = AuthorDetail.objects.filter(tel="13451222125").first()           # 得到tel="13451222125"的作者详细信息的对象
print(obj.author.name)                      # obj.author字段得到作者对象,再 .name得到结果 li


2、一对多关系

(1)查询id=15的书籍的出版社的名称(正向查询,按字段)

book_obj = Book.objects.filter(id=15).first()                  #得到id=15的数的对象
print(book_obj.publish.name)              # book_obj.publish得到书对应的出版社对象,再.name得到出版社的名字 上海出版社


(2)查询天津出版社出版过的书籍名称(反向查询,按表名小写_set)

publish_obj = Publish.objects.filter(name="天津出版社").first()  #得到name="天津出版社"的出版社对象
print(publish_obj.book_set.all())           # 得到出版社出版的书籍的对象集合:<QuerySet [<Book: go>, <Book: 操作系统原理>]>
for book in publish_obj.book_set.all():
    print(book.title)                                #遍历得到结果:go和操作系统原理

3、多对多关系

(1)查询(1)查询书名为go的所有作者的名字(正向查询,按字段)

obj = Book.objects.filter(title="go").first()                    #得到书名为go的对象
for i in obj.author.all():                                                   # obj.author.all()得到对应作者的集合
    print(i.name)                                                              # 遍历得到结果:wang和zhang


(2)查询zhang出版过的所有书籍名称(反向查询,按表名小写_set)

obj = Author.objects.filter(name="zhang").first()               #得到名字为"zhang"的作者的对象
for i in obj.book_set.all():                                 # obj.book_set.all()得到对应书籍的集合
    print(i.title)                                    # 遍历得到结果:go,操作系统原理,Linux,python
    
print(obj.book_set.all().values("title"))             # 结果:<QuerySet [{'title': 'go'}, {'title': '操作系统原理'}, {'title': 'Linux'}, {'title': 'python'}]>

上面的多对多关系过滤后值剩下一条数据了,不能完全反应问题,下面就看看多条数据的处理

(3)查询2018年出版社出版过的所有书籍的作者名字以及出版社名称

 obj=Book.objects.filter( publishDate__year=2018 ).all()            #得到书籍的对象集合
 for i in obj:
     print([i.name for i in  i.authors.all()],i.publish.name)

(4)查询价格为233的书对应的作者以及对应的出版社

obj = Book.objects.filter(price="233").all()
for i in obj:
     print([i.name for i in i.authors.all()],i.publish.name)


三、基于queryset查询

1、一对一关系

(1)查询wang的手机号(反向查询,按表名小写)

ret = Author.objects.filter(name="wang").values("authordetail__tel")
print(ret)  # 结果:<QuerySet [{'authordetail__tel': '18971232312'}]>


(2)查询手机号为13451222125的作者的名字 (正向查询,按字段)

ret = AuthorDetail.objects.filter(tel="13451222125").values("author__name")
print(ret)  # 结果:<QuerySet [{'author__name': 'li'}]>


2、一对多关系


(1)查询id=15的书籍的出版社的名称(正向查询,按字段)

ret = Book.objects.filter(id=15).values("publish__name")
print(ret)  # 结果:<QuerySet [{'publish__name': '上海出版社'}]>

(2)查询天津出版社出版过的书籍名称(反向查询,按表名小写)

ret = Publish.objects.filter(name="天津出版社").values("book__title")
print(ret)  # 结果:<QuerySet [{'book__title': 'go'}, {'book__title': '操作系统原理'}]>


3、多对多关系

(1)查询(1)查询书名为go的所有作者的名字(正向查询,按字段)

ret = Book.objects.filter(title="go").values("author__name")
print(ret)  # 结果:<QuerySet [{'author__name': 'wang'}, {'author__name': 'zhang'}]>


(2)查询zhang出版过的所有书籍名称(反向查询,按表名小写)

ret = Author.objects.filter(name="zhang").values("book__title")
print(ret)  # 结果:<QuerySet [{'book__title': 'go'}, {'book__title': 'python'}, {'book__title': '操作系统原理'}, {'book__title': 'Linux'}]>


# 查询手机号以1开头的作者出版过的所有书籍名称以及出版社名称

ret=AuthorDetail.objects.filter(tel__startswith="189").values("author__book__title","author__book__publish__name")
print(ret)  #结果是:<QuerySet [{'author__book__title': 'go', 'author__book__publish__name': '天津出版社'}, {'author__book__title': 'css', 'author__book__publish__name': '上海出版社'}, {'author__book__title': '操作系统原理', 'author__book__publish__name': '天津出版社'}, {'author__book__title': 'Linux', 'author__book__publish__name': '河北出版社'}]>

四、聚合和分组

from django.db.models import Avg, Count, Max, Min


1、统计所有书籍的平均价格

ret = Book.objects.all().aggregate(c=Avg("price"))
print(ret)  # 结果是:{'c': 249.5}


2、查询每一个出版社出版的书籍个数

ret = Publish.objects.all().annotate(c=Count("book")).values("name", "c")
print(ret)  # 结果是:<QuerySet [{'name': '北京出版社', 'c': 0}, {'name': '上海出版社', 'c': 2}, {'name': '天津出版社', 'c': 2}, {'name': '河北出版社', 'c': 1}, {'name': '唐山出版社', 'c': 1}]>


3、查询每一个作者出版的书籍的平均价格

ret = Author.objects.all().annotate(price_avg=Avg("book__price")).values("name", "price_avg")
print(ret)  # 结果是:<QuerySet [{'name': 'song', 'price_avg': 252.25}, {'name': 'wang', 'price_avg': 230.0}, {'name': 'li', 'price_avg': 280.0}, {'name': 'zhang', 'price_avg': 280.0}, {'name': 'zhao', 'price_avg': None}, {'name': 'zhou', 'price_avg': None}]>


4、查询每一本书籍名称以及作者的个数

ret = Book.objects.all().annotate(author_num=Count("author")).values("title", "author_num")
print(ret)  # 结果是:<QuerySet [{'title': 'linux', 'author_num': 2}, {'title': 'css', 'author_num': 2}, {'title': 'go', 'author_num': 2}, {'title': '操作系统原理', 'author_num': 3}, {'title': 'Linux', 'author_num': 4}, {'title': 'python', 'author_num': 3}]>


5、查询价格大于200的每一本书籍名称以及作者的个数

ret = Book.objects.filter(price__gt=200).annotate(author_num=Count("author")).values("title", "author_num")
print(ret)  # 结果是:<QuerySet [{'title': 'linux', 'author_num': 2}, {'title': 'go', 'author_num': 2}, {'title': 'python', 'author_num': 3}, {'title': '操作系统原理', 'author_num': 3}, {'title': 'Linux', 'author_num': 4}]>

五、F查询和Q查询

from django.db.models import F,Q

1、F查询

(1)查找comment_num数量大于poll_num的书

ret = Book.objects.filter(comment_num__gt=F("poll_num"))
print(ret)


(2)查找comment_num数量大于10倍的poll_num的书

ret = Book.objects.filter(comment_num__gt=F("read_num") * 10)
print(ret)


(3)把所有书的价格都加100

Book.objects.all().update(price=F("price") + 100)


2、Q查询

(1)查找以Java开头并且价格大于200的书

ret = Book.objects.filter(title__startswith="java", price__gt=200)
print(ret)


(2)查找以Java开头或者价格小于200的书

ret = Book.objects.filter(Q(title__startswith="java") | Q(price__lt=200))
print(ret)


(3)查找2017年出版的Java开头的书或者2017年的价格小于200的书

ret = Book.objects.filter(Q(title__startswith="java") | Q(price__lt=200), create_time__year=2017, )
print(ret)




猜你喜欢

转载自blog.51cto.com/qidian510/2106457