【Django—模板层之多表查询】

神奇的双下划线查询

方法描述
__gt大于
__lt小于
__gte大于等于
__lte小于等于
__in成员运算
__range范围查询
__contains区分大小写
__icontains忽略大小写
__startswith开头查询
__endswith结尾查询
__regex正则
__year按照年份筛选数据
__month按照月份筛选数据

ORM创建外键关系

表与表的关系:

  1. 一对多(ForeignKey)
  2. 多对多(ManyToManyField)
  3. 一对一(OneToOneField)

参数解析:

参数to指定模型名,参数to_field指定要关联的那个字段
on_delete=models.CASCADE 级联删除

模型创建
# 表app01_publish
class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)


# 表app01_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()

    # 表app01_book多对一表app01_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,则新表名为app01_book_authors,若变量名为xxx,则新表名为app01_book_xxx


# 表app01_author
class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)
    age = models.IntegerField()

    # 表app01_author一对一表app01_authordetail
    author_detail = models.OneToOneField(to='AuthorDetail',to_field='nid',unique=True,on_delete=models.CASCADE)


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

在创建关联时,针对参数to,如果传入的是字符串(to=“模型名”),则模型类的定义不区分先后顺序,如果传入的是模型名(to=Author),则Author类必须事先定义

添加数据
# 1、需求:通过模型Publish往表app01_publish里插入三家出版社
Publish.objects.create(name='北京出版社')
Publish.objects.create(name='长春出版社')
Publish.objects.create(name='大连出版社')

# 2、需求:通过模型AuthorDetail往表app01_authordetail里插入三条作者详情
AuthorDetail.objects.create(tel='18611312331')
AuthorDetail.objects.create(tel='15033413881')
AuthorDetail.objects.create(tel='13011453220')
# 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.objects.create(title='玉女心经', price=5000, pub_date='1988-3-24', publish_id=2)

book_obj2 = Book.objects.create(title='玉男心经', price=3000, pub_date='1985-6-17', publish_id=2)

book_obj3 = Book.objects.create(title='九阴真经', price=6000, pub_date='1983-8-17', publish_id=3)


外键字段的增删改查

 一对多、一对一外键字段操作
    新增数据
    models.Book.objects.create(title='聊斋志异', price=16987.22, publish_id=1)  # 直接填写关联数据的主键值
    publish_obj = models.Publish.objects.filter(pk=2).first()
    models.Book.objects.create(title='资本论', price=56777.98, publish=publish_obj)
    修改关系字段
    models.Book.objects.filter(pk=1).update(publish_id=3)
    publish_obj = models.Publish.objects.filter(pk=2).first()
    models.Book.objects.filter(pk=1).update(publish=publish_obj)

    多对多字段操作
    添加关系
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.add(1)  # 在第三张关系表中添加数据
    book_obj.authors.add(1, 2)  # 可以直接填写数据主键值
    author_obj1 = models.Author.objects.filter(pk=1).first()
    author_obj2 = models.Author.objects.filter(pk=2).first()
    book_obj.authors.add(author_obj1)
    book_obj.authors.add(author_obj1,author_obj2)
    修改关系
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.set([3, ])
    book_obj.authors.set([1, 2])
    author_obj1 = models.Author.objects.filter(pk=3).first()
    author_obj2 = models.Author.objects.filter(pk=4).first()
    book_obj.authors.set([author_obj1, ])
    book_obj.authors.set([author_obj1, author_obj2])
    移除关系
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.remove(3)
    book_obj.authors.remove(3,4)
    author_obj1 = models.Author.objects.filter(pk=1).first()
    author_obj2 = models.Author.objects.filter(pk=2).first()
    book_obj.authors.remove(author_obj1)
    book_obj.authors.remove(author_obj1,author_obj2)
    清空关系
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.clear()

正反向的概念

正反向的概念
核心在于当前数据对象是否含有外键字段 有则是正向 没有则是反向
例如表模Book与Publish,关联字段存在于Book中

当以Book为基表时,称之为正向查询
Book(基表)-------正向---------->Publish
当以Publish为基表时,称之为反向查询
Book<-------反向----------Publish(基表)

多表查询

使用原生sql进行多表关联查询时无非两种方式:子查询、join连表查询,ORM里同样有两种查询方式(严格依赖正向、反向的概念) 基于对象的跨表查询和基于双下划线的跨表查询

基于对象的跨表查询
  1. 一对一查询(模型类Author与AuthorDetail)

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

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

反向查询:按模型名(小写):author

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

  1. 多对一查询(模型类Book与Publish)

正向查询,按关联字段: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]) # 输出:['葵花宝典', '菊花宝典', '桃花宝典']
  1. 多对多查询(模型类Book与Author)

正向查询,按关联字段,如authors

# 需求:查询葵花宝典的所有作者
# 1、先取出书籍对象
book_obj=Book.objects.filter(title='葵花宝典').first()
# 2、正向查询:根据书籍对象下的关联字段authors取到所有作者
author_objs=book_obj.authors.all()
print([obj.name for obj in author_objs]) # 输出:['egon', 'kevin']

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

# 需求:查询作者rose出版的所有书籍
# 1、先取出作者对象
egon=Author.objects.filter(name='rose').first() 
# 2、反向查询:根据book_set取到作者对象
book_objs=egon.book_set.all()
print([book_obj.title for book_obj in book_objs]) # 输出:['玉女心经', '九阴真经', '玉男心经']
基于双下划线的跨表查询

一对一查询(模型类Author与AuthorDetail)

正向查询,按关联字段+双下划线: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.nid where app01_author.name = 'egon';

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

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

补充:基表决定了正向还是反向

# 1、针对上例中正向查询的需求:查询作者egon的手机号,如果我们选取的基表是AuthorDetail,那么就成了反向查询,应该用反向查询的语法
res = AuthorDetail.objects.filter(author__name='egon').values('tel').first()
print(res)  # {'tel': '18611312331'}

# 2、针对上例中反向查询的需求:查询手机号为'18611312331'的作者名,如果我们选取的基表是Author,那么就成了正向查询,应该用正向查询的语法
res=Author.objects.filter(author_detail__tel='18611312331').values('name').first()
print(res) # {'name': 'egon'}

多对一查询(模型类Book与Publish)

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

# 需求:查询葵花宝典的出版社名字
# 注意values()中的参数是:关联字段名__要取的那张被关联表中的字段
res=Book.objects.filter(title='葵花宝典').values('publish__name').first()
print(res['publish__name']) # {'publish__name': '北京出版社'}

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

# 需求:查询北京出版社都出版的所有书籍名字
# 注意values()中的参数是:小写的模型名__要取的那张被关联表中的字段
res = Publish.objects.filter(name='北京出版社').values('book__title')
print(res)  # <QuerySet [{'book__title': '葵花宝典'}, {'book__title': '菊花宝典'}, {'book__title': '桃花宝典'}]>

补充:基表决定了正向还是反向

# 1、针对上例中正向查询的需求:查询葵花宝典的出版社名字,如果我们选取的基表是Publish,那么就成了反向查询,应该用反向查询的语法
res = Publish.objects.filter(book__title='葵花宝典').values('name').first()
print(res)  # {'name': '北京出版社'}

# 2、针对上例中反向查询的需求:查询北京出版社都出版的所有书籍名字,如果我们选取的基表是Book,那么就成了正向查询,应该用正向查询的语法
res=Book.objects.filter(publish__name='北京出版社').values('title')
print(res) # <QuerySet [{'title': '葵花宝典'}, {'title': '菊花宝典'}, {'title': '桃花宝典'}]>

多对多查询(模型类Book与Author)

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

# 需求:查询葵花宝典的所有作者
# 注意values()中的参数是:关联字段名__要取的那张被关联表中的字段
res=Book.objects.filter(title='葵花宝典').values('authors__name')
print(res) # <QuerySet [{'authors__name': 'egon'}, {'authors__name': 'kevin'}]> 

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

# 需求:查询作者rose出版的所有书籍
# 注意values()中的参数是:小写的模型名__要取的那张被关联表中的字段
res = Author.objects.filter(name='rose').values('book__title')
print(res) # <QuerySet [{'book__title': '玉女心经'}, {'book__title': '九阴真经'}, {'book__title': '玉男心经'}]>

补充:基表决定了正向还是反向

# 1、针对上例中正向查询的需求:查询葵花宝典的所有作者,如果我们选取的基表是authors,那么就成了反向查询,应该用反向查询的语法
res=Author.objects.filter(book__title='葵花宝典').values('name')
print(res) # <QuerySet [{'name': 'egon'}, {'name': 'kevin'}]>

# 2、针对上例中反向查询的需求:查询作者rose出版的所有书籍,如果我们选取的基表是Book,那么就成了正向查询,应该用正向查询的语法
res=Book.objects.filter(authors__name='rose').values('title')
print(res) # <QuerySet [{'title': '玉女心经'}, {'title': '九阴真经'}, {'title': '玉男心经'}]>

聚合和分组查询

F查询与Q查询

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于Django的模型、视图和模板,我可以做个简单的介绍: Django是一个MVC框架,其中的M、V、C分别指的是模型、视图和控制器(其中控制器Django中对应的是URLconf),而这里的MVC与传统的MVC有所不同,更倾向于MVT的架构,即模型(Model)、视图(View)和模板(Template)。 - 模型(Model):模型主要是把应用中需要用到的数据以类似面向对象的方式进行定义、管理和操作,通常对应database中的表。Django中的ORM(Object-relational mapping)对开发者屏蔽了底SQL操作,开发者可以直接以Python语言去操作数据库,而不需要关心底SQL的实现细节。 - 视图(View):视图最主要的作用是处理用户的请求,响应相应的结果给用户。一般来说,视图会从数据库、缓存等数据源中获取数据,然后将结果进行组装,返回HttpResponse给用户。Django中视图可以通过函数或者类的方式来定义,对外提供一个可被URLconf调用的可调用对象。 - 模板(Template):模板是视图生成响应结果的主要组成部分,可以理解为一个动态生成的HTML页面,其中包含了数据展示、控制逻辑、页面渲染等元素。Django中的模板提供了超过100个内置的指令和过滤器,开发者可以非常方便的实现模板的渲染和页面的实现。 总结一下,模型主要和数据打交道,视图主要和操作和生成Http Response联系在一起,模板主要负责页面的渲染和数据展示。希望这个介绍可以帮到你。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值