一、创建模型
设定如下概念,字段和关系
作者模型:一个作者:姓名和年龄。
作者详细模型:把作者的详情放到详情表,
包含:生日,手机号,住址等信息。
作者详情模型和作者模型之间是一对一的关系(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("查询成功")