神奇的双下划线查询
方法 | 描述 |
---|---|
__gt | 大于 |
__lt | 小于 |
__gte | 大于等于 |
__lte | 小于等于 |
__in | 成员运算 |
__range | 范围查询 |
__contains | 区分大小写 |
__icontains | 忽略大小写 |
__startswith | 开头查询 |
__endswith | 结尾查询 |
__regex | 正则 |
__year | 按照年份筛选数据 |
__month | 按照月份筛选数据 |
ORM创建外键关系
表与表的关系:
- 一对多(ForeignKey)
- 多对多(ManyToManyField)
- 一对一(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里同样有两种查询方式(严格依赖正向、反向的概念) 基于对象的跨表查询和基于双下划线的跨表查询
基于对象的跨表查询
- 一对一查询(模型类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
- 多对一查询(模型类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]) # 输出:['葵花宝典', '菊花宝典', '桃花宝典']
- 多对多查询(模型类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': '玉男心经'}]>