Django ORM多表操作

准备数据表

models.py

from django.db import models


# 作者表
class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    # 一对一, to_field 关联字段不填默认是 id,
    # on_delete=models.CASCADE 级联删除 models.SET_NULL 不级联删除但是设置为空
    # 生成表字段之后,会字段变为authorDetail_id
    # django2.x中必须要写on_delete, 否则报错
    authorDetail = models.OneToOneField(to="AuthorDetail", to_field="id", on_delete=models.CASCADE)

    def __str__(self):
        return self.name



# 作者详细信息表
class AuthorDetail(models.Model):
    birthday = models.DateField()
    telephone = models.CharField(max_length=32)  # 设置为字符串,方便做模糊查询
    addr = models.CharField(max_length=64)

    def __str__(self):
        return self.addr


# 出版社表
class Publish(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()  			# 实际是charField

    def __str__(self):
        return self.name


# 书籍表
class Book(models.Model):
    title = models.CharField(max_length=32)
    publishDate = models.DateField()
    price = models.DecimalField(max_digits=5, decimal_places=2)
    # 一对多 related_name 代替反向查询表名
    publish = models.ForeignKey(
        to="Publish", 
        on_delete=models.CASCADE,
        # related_name='xx'				# 起别名
    )
    # 多对多
    authors = models.ManyToManyField(to='Author')
    # 点赞
    good = models.IntegerField(default=1)
    # 评论
    comment = models.IntegerField(default=1)

    def __str__(self):
        return f'{self.id:0>3}---{self.title}'

视图

views.py

一对一

# 方式1
new_author_detail = models.AuthorDetail.objects.create(
    birthday='1979-08-08',
    telephone='1383838438',
    addr='北京市'
)
models.Author.objects.create(
    name='李四',
    age=40,
    authorDetail=new_author_detail
)

# 方式2
obj = models.AuthorDetail.objects.filter(addr='武汉市').first()
models.Author.objects.create(
    name='张三',
    age=20,    
    authorDetail_id=obj.id
)

# 级联删除
models.AuthorDetail.objects.get(id=2).delete()
# 单独删除
models.Author.objects.get(id=4).delete()

author_obj = models.Author.objects.filter(id=5).update(
    age = 10,
    authorDetail = models.AuthorDetail.objects.get(id=5)
    # authorDetail_id = models.AuthorDetail.objects.get(id=5).id
)

基于对象的查询
# 1 正向查询,通过属性(字段)名
author_obj = models.Author.objects.filter(name='alex').first()
print(author_obj.authorDetail)              # authorDetail 对象
print(author_obj.authorDetail.telephone)

# 2 反向查询,通过小写的类(表)名
author_detail_obj = models.AuthorDetail.objects.get(telephone='1383838438')
print(author_detail_obj.author)             # author 对象
print(author_detail_obj.author.name)
基于双下划线的查询
# 正向查询1
obj = models.Author.objects.filter(name='alex').values('authorDetail__telephone')
print(obj)
print(obj.first()['authorDetail__telephone'])
# 正向查询2
obj = models.Author.objects.get(authorDetail__telephone='1383838438')
print(obj.name)
# 反向查询1
obj = models.AuthorDetail.objects.filter(author__name='alex').first()
print(obj.telephone)
# 反向查询2
obj = models.AuthorDetail.objects.filter(telephone='1383838438').values('author__name')
print(obj)
print(obj[0]['author__name'])

一对多

# 方式1
models.Book.objects.create(
    title='床头故事',
    publishDate='2019-07-22',
    price=3,
    publish=models.Publish.objects.get(id=3),
)
# 方式2
models.Book.objects.create(
    title='床头故事2',
    publishDate='2019-07-22',
    price=3.5,
    publish_id = models.Publish.objects.get(id=3).id,
)

# 级联删除
models.Publish.objects.get(id=3).delete()
# 单独删除
models.Book.objects.get(id=5).delete()

models.Book.objects.filter(pk=6)		# pk(primary key),不管字段名是什么,pk代表主键
models.Book.objects.filter(id=6).update(
    publish = models.Publish.objects.get(id=5),
    # publish_id = models.Publish.objects.get(id=5).id
)
# ORM无级联更新(一对一, 一对多)
# models.Publish.objects.filter(id=4).update(id=1)  # 报错

基于对象的查询
# 1 正向查询,通过属性(字段)名
book_obj = models.Book.objects.filter(title='床头的故事').first()
print(book_obj.publish)
print(book_obj.publish.name)

# 2 反向查询,通过小写的类(表)名_set
publish_obj = models.Publish.objects.filter(name='太白出版社').first()
# 类似控制器,可以调用 all, filter, get, exclude
print(publish_obj.book_set.all())

# 3 反向查询 使用 related_name
# publish_obj = models.Publish.objects.filter(name='太白出版社').first()
# print(publish_obj.xx.all())

# 查询太白出版社出版了哪些书,及对应的作者名和作者地址
objs  = models.Book.objects.filter(publish__name='太白出版社')
lst = []
for obj in objs:
    dic = {
        'title': obj.title,
        'author_info' : []
    }
    for author in obj.authors.all():
        ath = {
            'name': author.name,
            'addr': author.authorDetail.addr
        }
        dic['author_info'].append(ath)
    lst.append(dic)
print(lst)
基于双下划线的查询
obj = models.Book.objects.filter(title='床头的故事').values('publish__name')
print(obj)
obj = models.Publish.objects.filter(book__title='床头的故事')
print(obj.name)
obj = models.Publish.objects.filter(xx__title='床头的故事')
print(obj)

obj = models.Publish.objects.filter(name='太白出版社').values('book__title', 'book__authors__name', 'book__authors__authorDetail__addr')
print(obj)

多对多

# 方式1
book_obj = models.Book.objects.get(id=4)
# author_obj对应的id
book_obj.authors.add(3, 4)
# 方式2
book_obj = models.Book.objects.get(id=5)
author1 = models.Author.objects.get(id=1)
author2 = models.Author.objects.get(id=2)
book_obj.authors.add(author1,author2)

# 方式1 remove(对应Author表的id字段)
book_obj = models.Book.objects.get(id=6)
book_obj.authors.remove(1)
# 删除多个
book_obj.authors.remove(3,5)

# 方式2
author = models.Author.objects.get(id=5)
book_obj.authors.remove(author)
book_obj.authors.clear()          # 删除所有
book_obj.authors.set(['5','3'])   # 删除所有然后添加(更新)

book_obj = models.Book.objects.get(id=6)
book_obj.authors.set(['5','3'])   # 删除所有然后添加(更新)

基于对象的查询
# 1 正向查询
book_obj = models.Book.objects.filter(title='床头的故事').first()
print(book_obj.authors.all())

# 2 反向查询
author_obj = models.Author.objects.filter(name='alex').first()
print(author_obj.book_set.all())
基于双下划线的查询
obj = models.Author.objects.filter(book__title='床头的故事')
print(obj)

obj = models.Book.objects.filter(title='床头的故事').values('authors__name')
print(obj)

obj = models.Book.objects.filter(authors__name='alex')
print(obj)

obj = models.Author.objects.filter(name='alex').values('book__title')
print(obj)

聚合、分组、F查询、Q查询

from django.db.models import Avg, Max, Min, Sum, Count, F, Q

聚合查询

obj = models.Book.objects.all().aggregate(Avg('price'))
print(obj)          # {'price__avg': Decimal('10.150000')}

# 起别名,平均值
obj = models.Book.objects.all().aggregate(a=Avg('price'))
print(obj)          # {'a': Decimal('10.150000')}

# 最大值
obj = models.Book.objects.all().aggregate(Max('price'), Min('price'))
print(obj)

# 求和
obj = models.Book.objects.all().aggregate(Sum('price'))
print(obj)

# 计数
obj = models.Book.objects.all().aggregate(Count('id'))
print(obj)

分组查询

#                                        分组条件               要统计的值
obj = models.Book.objects.all().values('publish').annotate(Avg('price'))
print(obj)

obj = models.Publish.objects.annotate(Avg('book__price')).values()
print(obj)

ret = models.Book.objects.all().values('publish_id').annotate(Count('id'))
print(ret)

F 查询

# 查询book表中点赞数大于评论数的书名
obj = models.Book.objects.filter(good__gt=F('comment'))
print(obj)

# 支持4则运算
obj = models.Book.objects.filter(good__gt=F('comment')*2)
print(obj)

# 让所有书籍价格+20
models.Book.objects.all().update(price = F('price')+20)

Q 查询

# 查询点赞数小于80或者评论数大于80的书籍书籍
ret = models.Book.objects.filter(~Q(good__gt=80)|Q(comment__gt=80))
print(ret)
# | 或, & 且 ~非

# 方式2
q_obj = Q()
q_obj.connector='OR'
q_obj.children.append(('good__gt', 80))
q_obj.children.append(('comment__gt', 80))

ORM执行原生SQL

from django.db import connection


ret = models.Publish.objects.raw('select * from app01_publish')
for i in ret:
    print(i.name,i.city)

cursor = connection.cursor()
cursor.execute("select * from app01_book")
ret = cursor.fetchall()
print(ret)

# 查看SQL语句
print(connection.queries)
posted @ 2020-05-25 19:51  _Otis  阅读(74)  评论(0编辑  收藏  举报