Django学习笔记:ORM之多表操作

一、创建模型
设定如下概念,字段和关系

作者模型:一个作者:姓名和年龄。
作者详细模型:把作者的详情放到详情表,
包含:生日,手机号,住址等信息。
作者详情模型和作者模型之间是一对一的关系(one-to-one)
出版社模型:出版社有名称,地址和email。
书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);
一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。

模型建立如下:

from django.db import models
# 存放表结构
class Book(models.Model):
    """第一表"""
    nid = models.AutoField(primary_key=True) #自动递增主键
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2) #999999.99
    pub_date = models.DateTimeField() #"2019-10-01"
    publish = models.ForeignKey(to="Publish",on_delete=models.CASCADE)  # 级联删除
    # 细节:to="Publish" 加了引号,如果不加,会提示错误.如果放在 class Publish 下面就可以不加
    authors = models.ManyToManyField(to="Author")  # 此语法与创建 第三表 结果一样,推荐用此方法: ManyToManyField 会自动创建表
    def __str__(self):
        return self.title

class Publish(models.Model):
    """第二表"""
    nid = models.AutoField(primary_key=True)  # 自动递增主键
    name = models.CharField(max_length=32)
    email = models.CharField(max_length=32)
    def __str__(self):
        return self.name

class Author(models.Model):
    """第三表"""
    nid = models.AutoField(primary_key=True)  # 自动递增主键
    name = models.CharField(max_length=32)
    age = models.IntegerField()  # 整数字段不用加“max_length=32”
    email = models.CharField(max_length=32)
    ad = models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE)  # 与下一行代码一样,推荐此方法
    # ad = models.ForeignKey("AuthorDetail",on_delete=models.CASCADE,unique=True)
    def __str__(self):
        return self.name

# 一对一的关系表
class AuthorDetail(models.Model):
    addr = models.CharField(max_length=32)
    tel = models.IntegerField()  # 整数字段不用加“max_length=32”
    def __str__(self):
        return self.addr

注意
1、表的名称myapp_modelName,是根据 模型中的元数据自动生成的,也可以为别的名称  
2、id 字段是自动添加的
3、对于外键字段,Django 会在字段名上添加"_id" 来创建数据库中的列名
4、Django 会根据settings 中指定的数据库类型来使用相应的SQL 语句。
5、定义好模型之后,需要告诉Django使用这些模型,要做的就是修改配置文件中的INSTALL_APPSZ中设置,在其中添加models.py所在应用的名称。
6、外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None 。

二、添加表记录

操作前用 Navicat 先录入一些数据:

三、基于对象的跨表查询

1、一对多查询(Publish 与 Book)
正向查询(按字段:publish):
反向查询(按表名:book_set):

    """
        正向查询 : 按字段:book.publish
    Book ------------------------> Publish
         <------------------------
        反向查询 : 按表名的小写 + _set.all() :pub_obj.book_set.all()
    """"""
    book.authors.all()   # 查询与书籍关联的所有queryset的集合
    """

    # 1 查询 Python 出版社的名字和邮箱
    book = Book.objects.filter(title="Python").first()
    pub_obj = Publish.objects.filter(nid=book.publish_id).first()

    print(pub_obj.name)
    print(pub_obj.email)
    # -------
    book = Book.objects.filter(title="python").first()
    print(book.publish)  # Publish object (1)  查询对应的出版社对象
    print(book.publish.name)  
    print(book.publish.email)  

    # -------
    # 2 查询 人民出版社 出版社的所有的书籍名字
    pub_obj = Publish.objects.get(name="苹果出版社")
    print(pub_obj.book_set.all())  # <QuerySet [<Book: python>]>
    print(pub_obj.book_set.all().values("title"))  # <QuerySet [{'title': 'python'}]>

2、多对多查询 (Author 与 Book)
正向查询(按字段:authors):
反向查询(按表名:book_set):

"""
        正向查询 : 按字段:book.authors.all()
    Book ------------------------> Author
         <------------------------> 
        反向查询 : 按表名的小写 + _set.all() : alex.book_set.all()
    """
    # 正向查询
    # 1 查询 Python 书的作者的年龄
    book = Book.objects.filter(title="python").first()
    ret = book.authors.all().values("age")  # 与 python 书关联的所有作者的集合 : <QuerySet [{'age': 11}, {'age': 12}]>
    print(ret)

    # 反向查询
    # 1 查询 alex 出版的所有书籍名称
    alex = Author.objects.filter(name="alex").first()
    print(alex.book_set.all())

一对一查询(Author 与 AuthorDetail)

"""
        正向查询 : 按字段:alex.ad
    Author ------------------------> AuthorDetail
           <------------------------
        反向查询 : 按表名的小写 ad.author
    """

    # 正向查询
    # 1 查询 alex 的手机号
    alex = Author.objects.filter(name="alex").first()
    print(alex.ad.tel)  # 111

    # 反向查询
    # 1 查询手机号为 111 的作者的名字
    ad = AuthorDetail.objects.filter(tel=111).first()
    print(ad.author.name)  # alex

注意
可以通过在 ForeignKey() 和ManyToManyField的定义中设置 related_name 的值来覆写 FOO_set 的名称。

publish = ForeignKey(Book, related_name='bookList')

所以接下来结果就是这样:

# 查询 人民出版社出版过的所有书籍
publish=Publish.objects.get(name="人民出版社")
book_list=publish.bookList.all()  # 与人民出版社关联的所有书籍对象集合
四、基于双下划线的跨表查询

要跨关系查询,就使用两个下划线来链接模型(model)间关联字段的名称,直到链接到你想要的model 为止。
核心正向查询按字段,反向查询按表名小写,简而言之,就是拼表

def query2(request):
	#  一对多查询!!
    # 1 查询 Python 出版社的名字和邮箱
    # 正向查询按字段,反向查询按表名小写用来告诉ORM引擎join哪张表
    ret = Book.objects.filter(title="python").values("publish__name")   # 正向跨表
    print(ret)

    # 2 查询 人民出版社 出版的所有的书籍名字
    ret=Publish.objects.filter(name="人民出版社").values("book__title")   # 反向跨表
    print(ret)   # <QuerySet [{'book__title': 'Python'}, {'book__title': 'Linux'}]>
    ret=Book.objects.filter(publish__name="人民出版社").values("title")
    print(ret)   # <QuerySet [{'title': 'Python'}, {'title': 'Linux'}]>

    # 多对多查询!!
    # 3 查询 Python 书的作者的年龄
    ret=Book.objects.filter(title="python").values("authors__age")  # 正向跨表
    print(ret)  # <QuerySet [{'authors__age': 11}, {'authors__age': 12}]>
    Author.objects.filter(book__title="python").values("age")

    # 4 查询 alex 出版的所有书籍名称
    ret=Book.objects.filter(authors__name="alex").values("title")
    ret=Author.objects.filter(name="alex").values("book__title")
    print(ret)

    #  一对一查询!!
    # 5 查询 alex 的手机号
    Author.objects.filter(name="alex").values("ad__tel")  # 正向跨表
    AuthorDetail.objects.filter(author__name="alex").values("tel")
    
    # 6 查询手机号为 111 的作者的名字
    ret=AuthorDetail.objects.filter(tel=111).values("author__name")  # 正向跨表
    ret=Author.objects.filter(ad__tel=111).values("name")
    print(ret)
    
    return  HttpResponse("查询成功")
五、连续跨表查询
def query2(request):
	# 查询 人民出版社 出版的书籍名字以及作者的姓名
    ret=Publish.objects.filter(name="人民出版社").values("book__title","book__authors__name")
    ret=Book.objects.filter(publish__name="人民出版社").values("title","authors__name")
    print(ret)
    """
    <QuerySet [{'title': 'Python', 'authors__name': 'alex'}, {'title': 'Linux', 'authors__name': 'alex'}, {'title': 'Python', 'authors__name': 'jack'}]>
    <QuerySet [{'book__title': 'Python', 'book__publish__name': '人民出版社'}, {'book__title': 'Linux', 'book__publish__name': '人民出版社'}]>
    """

    # 手机号以 111 开头的作者出版过的所有书籍和出版社名称
    # 方式一:
    ret=Author.objects.filter(ad__tel__startswith=111).values("book__title","book__publish__name")
    print(ret)

    # 方式二:
    ret=AuthorDetail.objects.filter(tel__startswith=111).values("author__book__title","author__book__publish__name")
    print(ret)

    # 方式三:
    ret=Book.objects.filter(authors__ad__tel__startswith=111).values("title","publish__name")
    print(ret)
    """
    <QuerySet [{'book__title': 'Python', 'book__publish__name': '人民出版社'}, {'book__title': 'Linux', 'book__publish__name': '人民出版社'}]>
    <QuerySet [{'author__book__title': 'Python', 'author__book__publish__name': '人民出版社'}, {'author__book__title': 'Linux', 'author__book__publish__name': '人民出版社'}]>
    """
    return  HttpResponse("查询成功")
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值