Django ORM多表查询

目录

  表与表之间的关系

  创建数据库

  python 调用Django环境

  Django 创建模型

  Django 增删改查

表与表之间的关系

  一对一:每个作者对应一个作者详情。数据字段设置为unique。

  一对多:一个出版社可以出版多本书,一本书不可以被多个出版社印刷。通过外键实现,并外键建在多的一方。

  多对多:一个作者可以写多本书,一本书可以被多个作者写。一般通过第三个表格实现关联。

创建数据库

数据库表:

  共有四张表格分别为:书籍表book、出版社表publish、作者表author、作者详情表author_detail。

一对多(book和publish)

分析:一个出版社可以出版多本书,一本书不可以被多个出版社印刷。

创建数据库表SQL语句:

# 1、由于foreign key的影响,必须先创建被关联表
CREATE TABLE publish (
    id INT PRIMARY KEY auto_increment,
    name VARCHAR (20)
);

# 2、才能创建出关联表
CREATE TABLE book (
    id INT PRIMARY KEY auto_increment,
    title VARCHAR (20),
    price DECIMAL (8, 2),
    pub_date DATE,
    publish_id INT, # 新增关联字段
    FOREIGN KEY (publish_id) REFERENCES publish (id) 
    ON UPDATE CASCADE ON DELETE CASCADE
);

一对一(author与author_detail)

分析:每个作者对应一个作者详情。外键多创建在使用次数多的表 上。

创建数据库表SQL语句:

# 1、由于foreign key的影响,必须先创建被关联表
CREATE TABLE authordetail (
    id INT PRIMARY KEY auto_increment,
    tel VARCHAR (20)
);

# 2、才能创建出关联表
CREATE TABLE app01_author (
    id INT PRIMARY KEY auto_increment,
    name VARCHAR (20),
    age INT,
    authordetail_id INT UNIQUE, # 新增关联字段,并添加唯一性约束unique
    FOREIGN KEY (authordetail_id) REFERENCES authordetail (id) 
    ON UPDATE CASCADE ON DELETE CASCADE
);

多对多(book与author)

分析:一个作者可以写多本书,一本书可以被多个作者写。创建第三张表。

创建数据库SQL语句:

# 1、创建被关联表一:book,例1中已创建
# 2、创建被关联表二:author,例2中已创建

# 3、创建新表,存book于author的关联关系
CREATE TABLE book_authors (
    id INT PRIMARY KEY auto_increment,
    book_id INT, # 新增关联字段,用来关联表book
    author_id INT, # 新增关联字段,用来关联表author
    FOREIGN KEY (book_id) REFERENCES book (id) ON UPDATE CASCADE ON DELETE CASCADE,
    FOREIGN KEY (author_id) REFERENCES author (id) ON UPDATE CASCADE ON DELETE CASCADE
);

Django 创建模型(app/models.py)

from django.db import models

# 表publish
class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)


# 表book
class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=20)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    pub_date = models.DateField()
    # 表book多对一表publish,参数to指定模型名,参数to_field指定要关联的那个字段
    publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
    # 我们自己写sql时,针对书籍表与作者表的多对关系,需要自己创建新表,而基于django的orm,下面这一行代码可以帮我们自动创建那张关系表
    authors=models.ManyToManyField(to='Author') 
    # 变量名为authors,则新表名为book_authors,若变量名为xxx,则新表名为book_xxx


# 表author
class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)
    age = models.IntegerField()
    # 表app01_author一对一表authordetail
    author_detail = models.OneToOneField(to='AuthorDetail',to_field='nid',unique=True,on_delete=models.CASCADE)


# 表authordetail
class AuthorDetail(models.Model):
    nid = models.AutoField(primary_key=True)
    tel = models.CharField(max_length=20)

python 调用Django环境

import os

if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
    import django
    django.setup()

    from app01 import models  #引入也要写在上面三句之后

    books = models.Book.objects.all()
    print(books)

Django 多表曾加 删除 修改记录

曾加

一对多(book与publish)

# 需求:书籍(葵花宝典、菊花宝典、桃花宝典)都是在北京出版社出版的
# 1、先通过模型Publish从出版社表app01_publish查出北京出版社
publish_obj=Publish.objects.filter(name='北京出版社').first()
# 上述代码也可以简写为:publish_obj=Publish.objects.get(name='北京出版社')

# 2、再通过模型Book往书籍表app01_book里插入三本书籍与出版社的对应关系
# 方式一:使用publish参数指定关联
book_obj1=Book.objects.create(title='葵花宝典',price=2000,pub_date='1985-3-11',publish=publish_obj)

book_obj2=Book.objects.create(title='菊花宝典',price=3000,pub_date='1990-1-21',publish=publish_obj)

book_obj3=Book.objects.create(title='桃花宝典',price=4000,pub_date='1991-1-23',publish=publish_obj)

# 方式二:使用publish_id参数指定关联
book_obj1=Book.objects.create(title='葵花宝典',price=2000,pub_date='1985-3-11',publish_id=publish_obj.nid)

book_obj2=Book.objects.create(title='菊花宝典',price=3000,pub_date='1990-1-21',publish_id=1) # 在已经出版社id的情况下,可以直接指定

book_obj3=Book.objects.create(title='桃花宝典',price=4000,pub_date='1991-1-23',publish_id=1)

# 注意:无论方式一还是方式二得到的书籍对象book_obj1、book_obj2、book_obj3
#      都可以调用publish字段来访问关联的那一个出版社对象
#      都可以调用publish_id来访问关联的那一个出版社对象的nid
print(book_obj1.publish,book_obj1.publish_id) 
print(book_obj2.publish,book_obj2.publish_id) 
print(book_obj3.publish,book_obj3.publish_id)
# 三本书关联的是同一个出版社,所以输出结果均相同

 一对一(author与author_detail)

# 需求:插入三个作者,并与作者详情表一一对应
# 由于作者详情表我们已经事先创建好记录,所以只需要往作者表插入记录即可
# 方式一:需要事先过滤出作者详情的对象,然后通过模型Author的字段author来指定要关联的作者详情对象(略)

# 方式二:确定作者详情对象的id,然后通过模型Author通过字段author_id来指定关联关系,
Author.objects.create(name='egon',age=18,author_detail_id=1)
Author.objects.create(name='kevin',age=38,author_detail_id=2)
Author.objects.create(name='rose',age=28,author_detail_id=3)

多对多(book与author)

# 我们参照物理表app01_book_authors制定需求,需要创建如下关系
# 1、葵花宝典的作者为:egon、kevin
# 2、菊花宝典的作者为:egon、kevin、rose
# 3、桃花宝典的作者为:egon、kevin
# 4、玉女心经的作者为:kevin、rose
# 5、玉男心经的作者为:kevin
# 6、九阴真经的作者为:egon、rose

# 需要创建出上述关系,具体做法如下
# 1、先获取书籍对象
book_obj1=Book.objects.get(title='葵花宝典')
book_obj2=Book.objects.get(title='菊花宝典')
book_obj3=Book.objects.get(title='桃花宝典')
book_obj4=Book.objects.get(title='玉女心经')
book_obj5=Book.objects.get(title='玉男心经')
book_obj6=Book.objects.get(title='九阴真经')

# 2、然后获取作者对象
egon=Author.objects.get(name='egon')
kevin=Author.objects.get(name='kevin')
rose=Author.objects.get(name='rose')

# 3、最后依次创建上述关系:在原生SQL中多对多关系涉及到操作第三张关系表,但是在ORM中我们只需要操作模型类Book下的字段author即可
book_obj1.authors.add(egon,kevin)
book_obj2.authors.add(egon,kevin,rose)
book_obj3.authors.add(egon,kevin)
book_obj4.authors.add(kevin,rose)
book_obj5.authors.add(kevin)
book_obj6.authors.add(egon,rose)

 查询

  正向和反向查询

  例如: book与publish,,关联字段在book表中。当以book为基础表查询pulish表为正向查询。反之为反向查询。

  基于对象的跨表查询

  基于双下划线的查询

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

1. 基于对象的跨表查询(子查询)

一对一查询

  正向查询,按关联字段: author_detail

# 需求:查询作者egon的手机号
# 1、先取出作者对象
egon=Author.objects.filter(name='egon').first() 
# 2、正向查询:根据作者对象下的关联字段author_detail取到作者详情
print(egon.author_detail.tel) # 输出:18611312331

  反向查询,,按表名小写: author

# 需求:查询手机号为'18611312331'的作者名
# 1、先取出作者的详情对象
tel=AuthorDetail.objects.filter(tel='18611312331').first()
# 2、反向查询:根据小写的模型名author取到作者对象
print(tel.author.name) # 输出:egon

多对一(多对多查询同多对一

  正向查询,按关联字段:publish

# 需求:查询葵花宝典的出版社名字
# 1、先取书籍对象
book_obj=Book.objects.filter(title='葵花宝典').first()
# 2、正向查询:根据书籍对象下的关联字段publish取到出版社
print(book_obj.publish.name) # 输出:北京出版社

  反向查询,按模型名(小写)_set:book_set

# 需求:查询北京出版社都出版的所有书籍名字
# 1、先取出出版社对象
publish_obj=Publish.objects.filter(name='北京出版社').first()
# 2、反向查询:根据book_set取到所有的书籍
book_objs=publish_obj.book_set.all()
print([book_obj.title for book_obj in book_objs]) # 输出:['葵花宝典', '菊花宝典', '桃花宝典']

2. 基于双下划线的跨表查询

一对一查询(多对一和多对多查询同一对一查询一样

  正向查询,按关联字段+双下划线:author_detail__

# 需求:查询作者egon的手机号
# 注意values()中的参数是:关联字段名__要取的那张被关联表中的字段
res = Author.objects.filter(name='egon').values('author_detail__tel').first()
print(res['author_detail__tel']) # {'author_detail__tel': '18611312331'}

# 注意:基于双下划线的跨表查询会被django的orm识别为join操作,所以上述代码相当于如下sql,后续案例均是相同原理,我们不再累述
select app01_authordetail.tel from app01_author inner join app01_authordetail on app01_author.author_detail_id = app01_authordetail

  反向查询,按模型名(小写)+双下划线:author__

# 需求:查询手机号为'18611312331'的作者名
# 注意values()中的参数是:小写的模型名__要取的那张被关联表中的字段
res=AuthorDetail.objects.filter(tel='18611312331').values('author__name').first()
print(res) # {'author__name': 'egon'}

3. 聚合查询

4. 分组查询

5. F和Q查询

posted @ 2020-03-25 15:53  zhuang6  阅读(230)  评论(0)    收藏  举报