外键在哪里,哪里就是正向。
1、由外键所在的表去查其他表,这就是正向
2、由没有外键所在的表去查,这就是反向
例子
书和出版社:外键设置在书表中
1、通过书表去查对应的出版社,这是正向查询
2、通过出版社表去查出版的所有书,这就是反向
正向查询按字段
在多对多关系表中,正方向也要加all()
反向查询按表名小写.__set
查询结果是多个时,再加上 .all()
正向查询:点外键字段
特殊:查询结果 是多个时加 .all(), (多对多关系表的正向查询要加all())
反向查询:点表名小写_set.all()
特殊:查询结果只有一个时,直接点表名(一对一关系表)
表数据,人与人的详细信息,外键设置在人表上
class Person(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=20)
persondetail = models.OneToOneField(to='PersonDetail',on_delete=models.CASCADE,db_constraint=False)
def __str__(self):
return self.name
class PersonDetail(models.Model):
id = models.AutoField(primary_key=True)
phone = models.CharField(max_length=13)
address = models.CharField(max_length=100,null=True)
def __str__(self):
return self.phone
#外键在person表中,通过个人详细信息找到人
persondetail = models.PersonDetail.objects.get(id=1)
#反向查询,一对一的反向查询,直接点Person表名小写
person = persondetail.person
#外键在person表中
person = models.Person.objects.get(id=1)
#正向查询,直接点外键字段获取表对象
persondetail = person.persondetail
print(persondetail)
表数据:书与出版社,一对多关系
class Book(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=20)
publish = models.ForeignKey(to='Publish',on_delete=models.DO_NOTHING,db_constraint=False)
def __str__(self):
return self.name
class Publish(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=20)
def __str__(self):
return self.name
2.1、子查询的反向查询
'''
反向查询,是给没有外键的表使用
1、一对多关系表中,外键在多上,所以这种方式的反向查询,一定要加上all()
2、对于多对多关系表中,反向查询也一定要加上all()
3、对于一对一关系表中,反向查询就不需要加all()
'''
#外键设置在book上,查询id=1的出版社出版的所有书
publish = models.Publish.objects.filter(id=1).first()
#反向查询使用对方表小写+_set,数据有多条再加 .all()
books = publish.book_set.all()
for book in books:
print(book)
2.2、子查询的正向查询
#书与出版社是一对多,外键在书上,查询某本书是哪个出版社出版的,是正向查询
book = models.Books.objects.filter(id=3).first()
#通过外键字段获取数据对象
publish = book.publish
print(publish)
数据准备:书和作者,是多对多的关系,是通过第三张表实现多对多关系,哪个表的字段设置了ManyToManyField的,该字段就算是外键了。
外键设置到书上了
半自动生成第三张表
class Book(models.Model):
id = models.AutoField(primary_key=True,verbose_name='主键')
name = models.CharField(max_length=100,verbose_name='书名')
price = models.DecimalField(max_digits=10,decimal_places=2,verbose_name='价格')
authors = models.ManyToManyField(to='Author',through='Book2Author',through_fields=('book','author'))
class Author(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=50,verbose_name='作者')
address = models.CharField(max_length=100,verbose_name='作者地址')
class Book2Author(models.Model):
id = models.AutoField(primary_key=True,verbose_name='书作者关系主键')
book = models.ForeignKey(to='Book',on_delete=models.DO_NOTHING,db_constraint=False)
author = models.ForeignKey(to='Author',on_delete=models.DO_NOTHING,db_constraint=False)
create_time = models.DateTimeField(auto_now_add=True,verbose_name='创建时间')
class Meta:
#书与作者联合唯一,book=1 和 author=1在表中只记录一次
unique_together=['book','author']
#查看某个作者的写过的所有书,外键在书表中
author = models.Author.objects.get(id=1)
#多对多都是:表名小写_set.all()
books = author.book_set.all()
print(books)
book = models.Book.objects.get(id=2)
#多对多的正向查询,需要加all() 因为是多对多关系,系统默认就是一本书有多个作者的,即使已经知道该书只有一个作者也是需要使用all()的
authors = book.authors.all()
print(authors)
你的查询没有错误,只是少了.all() , 因为你这个查询默认是返回多条数据的,所以需要使用all()方法来拿。
1、正向查询时,通过外键跨表,返回多个数据时,要使用.all()获取。[只有多对多关系需要.all(),系统默认会拿到多个数据]
2、反向查询时,通过表名小写[_set.all()],返回多个数据时就必须加_set.all(). [在一对一关系表中,就直接表名小写就可以了]、
3、带all()的结果是列表套字典
4、不带all()的结果就是query对象了
正向查询:通过 外键__字段 获取另一张的字段数据
反向查询:通过 表名小写__字段 获取另一张的字段数据
数据准备:人和人的详细信息,一对一关系,外键在人表上。
1.1、正向查询
#查询id=1的人的姓名,地址和电话(在另一张表上),正向查询直接外键跨到另一张表中,通过__字段,获取另一张表的字段数据
person = models.Person.objects.filter(id=1).values('persondetail__address','persondetail__phone','name')
#下面拿到的是一个字典
print(person.first())
print(person.first().get('persondetail__address'))
1.2、反向查询
#通过个人详细信息找到对应的名字,反向查询,通过表名小写进行跨表,__字段获取指定字段数据
persondetail = models.PersonDetail.objects.filter(id=2).values('person__name','address','phone')
#拿到的是一个列表套字段,values决定的
print(persondetail)
#拿到个人的名字 print(persondetail.first().get('person__name'))
数据准备:books 和publish,多对一关系
class Books(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=20)
publish = models.ForeignKey(to='Publish',on_delete=models.DO_NOTHING,db_constraint=False)
def __str__(self):
return self.name
class Publish(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=20)
def __str__(self):
return self.name
1、正向查询
'''拿到聊斋书的出版社信息和聊斋书的信息'''
#正向查询通过外键__字段,拿到另一张表的字段数据,多查一,返回一个数据,
books = models.Books.objects.filter(name='聊斋').values('name','id','publish__name','publish__id')
print(books)
结果:格式列表套字典,vlaues决定
<QuerySet [{'name': '聊斋', 'id': 3, 'publish__name': '南京出版社', 'publish__id': 1}]>
2、反向查询
'''拿到南京出版社出版的所有书籍'''
#反向查询,通过表名小写__字段,获取另一张表名中的字段数据
publish = models.Publish.objects.filter(name='南京出版社').values('name','id','books__name','books__id')
print(publish)
#结果:列表套字典,values决定
<QuerySet [{'name': '南京出版社', 'id': 1, 'books__name': '水浒传', 'books__id': 5}, {'name': '南京出版社', 'id': 1, 'books__name': '西游记', 'books__id': 4}, {'name': '南京出版社', 'id': 1, 'books__name': '聊斋', 'books__id': 3}]>
数据准备: book和author,外键authors在book上
class Book(models.Model):
id = models.AutoField(primary_key=True,verbose_name='主键')
name = models.CharField(max_length=100,verbose_name='书名')
price = models.DecimalField(max_digits=10,decimal_places=2,verbose_name='价格')
authors = models.ManyToManyField(to='Author',through='Book2Author',through_fields=('book','author'))
def __str__(self):
return self.name
class Author(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=50,verbose_name='作者')
address = models.CharField(max_length=100,verbose_name='作者地址')
def __str__(self):
return self.name
class Book2Author(models.Model):
id = models.AutoField(primary_key=True,verbose_name='书作者关系主键')
book = models.ForeignKey(to='Book',on_delete=models.DO_NOTHING,db_constraint=False)
author = models.ForeignKey(to='Author',on_delete=models.DO_NOTHING,db_constraint=False)
create_time = models.DateTimeField(auto_now_add=True,verbose_name='创建时间')
class Meta:
#书与作者联合唯一,book=1 和 author=1在表中只记录一次
unique_together=['book','author']
1、正向查询
#正向查询,通过 外键__字段 ,返回的是一个列表套字典,即使拿到的一个数据,也是这种格式
'''拿到西游记的所以作者'''
book = models.Book.objects.filter(name__startswith='西游').values('name','authors__name','price')
print(book)
打印:
<QuerySet [{'name': '西游记', 'authors__name': 'lhz', 'price': Decimal('58.40')}, {'name': '西游记', 'authors__name': 'zzh', 'price': Decimal('58.40')}]>
print(book.first().get('authors_name'))
2、反向查询
'''找到lhz作者的所有书籍'''
#外键在book中,不在author中
#反向查询通过 表名小写__字段名
author = models.Author.objects.filter(name__startswith='lhz').values('name','book__name','book__price')
print(author)
打印:
<QuerySet [{'name': 'lhz', 'book__name': '水浒传', 'book__price': Decimal('56.40')}, {'name': 'lhz', 'book__name': '西游记', 'book__price': Decimal('58.40')}]>
1、通过filter过滤当前表数据
2、通过values或values_list 来获取指定 的字段数据 (一般使用values,结果列表套字典),拿到当前表字段或通过外键/表名小写__字段拿到跨表的字段数据。
3、正向查询,直接通过外键__字段,获取跨表的数据
4、反向查询,直接通过表名小写__字段,获取跨表的数据
5、无论正向还是反向,结果都是被列表套住的字典或元组。