Django框架之模型层 多表操作

一、多表关系

回顾一下设置外键的sql语句:

foreign key(外键字段) references 关联表(关联字段)

设置级联关系:

on update cascade   # 更新级联关系,要改一起改
on delete cascade   # 删除历练关系,要死一起死
  • 一对一

外键在任何一方都可以,但是尽量放在使用的次数多的一方,并设置字段唯一键,

  • 一对多

外键放在多的一方,此时外键不唯一

  • 多对多

一定要创建第三张表(关系表),每一个外键值不唯一,但可以多个外键建立联合唯一

二、多表操作

首先多表操作,应该在建表之前,就先设计好多表关系,然后再去创建表。

2.1 分析多表关系

需求:现在需要写一个图书管理的程序,需要设计表。如何设计

  1. 图书表

    图书表包括(书名、价格、出版日期)

  2. 出版社表

    出版社表包括(出版社名、地址)

  3. 作者简介表

    作者简介表包括(作者名、年龄)

  4. 作者详情表

    作者详情表包括(电话、地址)

  • 一对一:一个作者简介唯一对应作者详情表,一个作者详情也唯一对应作者简介
  • 一对多:一个图书对应唯一对应一个出版社,一个出版社可以对应多本书
  • 多对多:一个图书对应多个作者,一个作者也同样对应多本书

2.2 创建表

还是在模型层中去创建表

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)  # 长度8位,两位小数
    publish_date = models.DateField(auto_now_add=True)

    '''一对多关系 ForeignKey'''
    publish = models.ForeignKey(to="Publish")   # 不能加id

    '''多对多关系 ManyToManyField'''
    author = models.ManyToManyField(to="Author")    # 只需要取要关联的第三表,不能加id

class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)

class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()

    author_detail = models.OneToOneField("AuthorDetail")

class AuthorDetail(models.Model):
    Phone = models.BigIntegerField()
    addr = models.CharField(max_length=32)

2.3 外键字段的增删改查

增,先增加被关联表数据

# 出版社表
models.Publish.objects.create(name="东方出版",addr="北京")
models.Publish.objects.create(name="南方出版",addr="南京")
# 作者详情表
models.AuthorDetail.objects.create(Phone="110", addr="上海")
models.AuthorDetail.objects.create(Phone="120", addr="安徽")
models.AuthorDetail.objects.create(Phone="119", addr="重庆")
# 作者简介表
models.Author.objects.create(name="haha",age=18,author_detail_id=1)
models.Author.objects.create(name="aaa",age=19,author_detail_id=2)
models.Author.objects.create(name="bbb",age=29,author_detail_id=3)
# 书表
models.Book.objects.create(name="python从入门到放弃",price=12,publish_id=1)
models.Book.objects.create(name="鬼谷子",price=123,publish_id=2)
models.Book.objects.create(name="墨菲定律",price=12,publish_id=1)

book_obj = models.Book.objects.filter(pk=2).first()
print(book_obj.publish)     # 获取到当前所对应的出版社对象
print(book_obj.publish_id)  # 获取到的就是表中的实际字段

改 默认是级联更新,级联删除

models.Book.objects.filter(pk=2).update(publish_id=1)   # _id 直接给出实际id
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.filter(pk=2).update(publish=publish_obj)    # publish_obj做更新,默认就是id

删除 默认是级联更新,级联删除

models.Publish.objects.filter(pk=2).delete()

注意: 如果要用外键字段

直接是用表类中外键字段名就要传一个对象,如果是数据库中的外键字段名,就传id号

2.4 多对多字段的四个方法

  • 增 add()
"""
   add() 括号内既可以传数字也可以传数据对象
   并且都支持传多个
"""
# 通过id
book_obj = models.Book.objects.filter(pk=3).first()
print(book_obj.author)  # 就相当于 已经在书籍和作者的关系表了
book_obj.author.add(2,6)    # 从书籍表中找到第三张关系表中  添加作者id 2和6
# 通过对象
book_obj = models.Book.objects.filter(pk=2).first()
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
book_obj.author.add(author_obj,author_obj1)    # 通过书籍表中找到第三张关系表 添加author_obj的主键
  • 改 set()
"""
   set() 括号内 既可以传数字也传对象 
   并且也是支持传多个的
   但是需要注意 括号内必须是一个可迭代对象
"""
# 通过id
book_obj = models.Book.objects.filter(pk=3).first() # 将作者主键为3的纪录全部重设成set中的
book_obj.author.set([1,2,6])
# 通过对象
book_obj = models.Book.objects.filter(pk=2).first()     # 将作者主键为2的纪录全部重设set中的
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
book_obj.author.set((author_obj,author_obj1))
  • 删 remove()
"""
    remove() 括号内 既可以传数字也传对象 
并且也是支持传多个的
"""
# 通过id
book_obj = models.Book.objects.filter(pk=3).first() # 将作者主键为3的纪录并且,作者id满足删除
book_obj.author.remove(1,2)
# 通过对象
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
book_obj = models.Book.objects.filter(pk=2).first()  # 将作者主键为3的纪录并且,作者id满足删除
book_obj.author.remove(author_obj,author_obj1)
  • 清空 clear()
"""clear()括号内不需要传任何参数 直接清空当前书籍对象所有的记录"""
book_obj = models.Book.objects.filter(pk=3).first()
book_obj.author.clear()

三、跨表查询

ORM跨表查询

  1. 子查询
  2. 连表查询

正反向的概念 :

  • 外键字段在谁那儿 由谁查谁就是正向
  • 谁手里有外键字段 谁就是正向查,没有外键字段的就是反向

跨表查询最重要的口诀:

  • 正向查询按字段
  • 反向查询按表名小写...

3.1 子查询

基于对象的跨表查询

'''正向查询按字段'''
'''
什么时候需要.all()
    当查询的结果可以是多个的情况下 需要加.all()
'''
# 1.查询书籍是 python从入门到放弃 的出版社名称
book_obj = models.Book.objects.filter(name="python从入门到放弃").first()
print(book_obj.publish.name)

# 2.查询书籍主键是3的作者姓名
book_obj = models.Book.objects.filter(pk=3).first()
print(book_obj.author)  # app01.Author.None代表有多条记录要使用all()
print(book_obj.author.all())

# 3.查询作者是 hhh 的手机号
author_obj = models.Author.objects.filter(name="hhh").first()
print(author_obj.author_detail.Phone)


'''反向查询按表名小写 '''
'''
只要有多个关系就要加_set

当查询的结果可以是多个的情况下 需要加_set.all()

什么时候不需要加_set
    当查询的结果有且只有一个的情况下 不需要加任何东西 直接表名小写即可
'''
# 4.查询出版社是 东方出版 出版过的书籍
publish_obj = models.Publish.objects.filter(name="东方出版").first()
print(publish_obj.book_set.all()) # 查询的是多个就要加_set,不然会报错。app01.Book.None,要加all()

# 5.查询作者是 hhh 写过的所有的书
author_obj = models.Author.objects.filter(name='hhh').first()
print(author_obj.book_set.all())

# 6.查询手机号是110的作者
authorDetail_obj = models.AuthorDetail.objects.filter(Phone=110).first()
print(authorDetail_obj.author.name)

# 7.查询书籍是 python从入门到放弃 的作者的手机号
author_dic = models.Book.objects.filter(name="python从入门到放弃").values("author").first()
author_id = author_dic.get("author")
author_obj = models.Author.objects.filter(pk=author_id).first()
print(author_obj.author_detail.Phone)

3.2 连表查询

基于双下划线的跨表查询

优点:它可以无限跨表,只要有关系

'''
MySQL
left join
inner join
right join
union
        
ORM多表查询口诀:
    正向查询按字段
    反向查询按表名小写
'''
# 1.查询书籍是 python从入门到放弃 的出版社名称
# 正向
res = models.Book.objects.filter(name="python从入门到放弃").values("publish__name")
print(res)
# 反向
res = models.Publish.objects.filter(book__name="python从入门到放弃").values("name")
print(res)

# 2.查询作者是 hhh 的手机号码
# 正向
res = models.Author.objects.filter(name='hhh').values('author_detail__Phone')
print(res)
# 反向
res = models.AuthorDetail.objects.filter(author__name="hhh").values("Phone")
print(res)

# 3.查询手机号是120的作者姓名
# 反向:
res = models.AuthorDetail.objects.filter(Phone=120).values("author__name")
print(res)
# 正向:
res = models.Author.objects.filter(author_detail__Phone=120).values("name")
print(res)  # 先连表,然后拿name字段

# 4.查询出版社是 东方出版 出版的书籍名称
# 反向
res = models.Publish.objects.filter(name="东方出版").values("book__name")
print(res)
# 正向
res = models.Book.objects.filter(publish__name="东方出版").values("name")
print(res)

# 5.查询作者是 hhh 的写过的书的名字和价格
# 正向
res = models.Author.objects.filter(name="hhh").values("book__name","book__price")
print(res)
# 反向
res = models.Book.objects.filter(author__name="hhh").values("name","price")
print(res)

# 查询书籍是 python从入门到放弃 的作者的手机号
# 正向
res = models.Book.objects.filter(name="python从入门到放弃").values("author__author_detail__Phone")
print(res)
# 反向
res = models.AuthorDetail.objects.filter(author__book__name="python从入门到放弃").values("Phone")
print(res)

猜你喜欢

转载自www.cnblogs.com/XuChengNotes/p/11735719.html