博客核心内容:
1、基于ORM的单表操作(包括外键)
2、基于ORM的单表操作(反向操作)
3、如何在总对象当中通过过滤获取一个对象
4、基于ORM的多表操作(m字段、正向查询)
5、基于ORM的多表操作(m字段、反向查询)
6、基于ORM的操作总结
7、小测(配答案)
8、补充(related_name字段的使用)
场景介绍:
# Create your models here.
class Publisher(models.Model):
name = models.CharField('出版社名字',max_length=100)
city = models.CharField('出版社所在城市',max_length=60)
state_province = models.CharField('出版社所在省份',max_length=30)
address = models.CharField('出版社地址',max_length=100)
class Book(models.Model):
title = models.CharField('书名',max_length=100)
price = models.DecimalField('图书价格',max_digits=6,decimal_places=2)
publication_date = models.CharField('出版日期',max_length=100)
#pub在这里充当外键:构造一对多的关系
pub = models.ForeignKey(to='Publisher',to_field='id')
# 构造多对多的表关系:作者与图书之间是多对多的关系
m = models.ManyToManyField('Author')
class Author(models.Model):
name = models.CharField('姓名',max_length=100)
sex = models.CharField('性别',max_length=5)
birthday = models.CharField('出生日期',max_length=100)
其中图书与出版社是一对多的关系:即一个出版社对应多本书,但是一本书只能对应一个出版社。
图书与作者是多对多的关系:即一本图书对应多个作者,一个作者对应多本图书。
出版社表:
作者表:
图书表:
图书—作者关系表:(m字段衍生出的第三张表)
1、基于ORM的单表操作(正向操作) |
具体操作:
#queryset = [对象,对象,.....]
- objs = models.xx.objects.all()
for row in objs:
row.id
row.host
row.port
row.bs.name
#queryset = [{},{},.....]
- objs = models.xx.objects.all().values('id','host','port','bs__name')
for row in objs:
row['id']
row['host']
row['port']
row['bs__name']
#queryset = [(1, 1.1.1, 80,'web'),(),()....]
- objs = models.xx.objects.all().values_list('id','host','port','bs__name')
for row in objs:
row[0]
row[1]
row[2]
row[3]
示例1:纯all操作
book_list = models.Book.objects.all()
for book in book_list:
print(book.id)
print(book.title)
print(book.price)
print(book.publication_date)
print(book.pub_id)
#下面是对这本图书关联的出版社的查询操作:利用.进行查询
print(book.pub)
print(book.pub.id)
print(book.pub.name)
print(book.pub.city)
print(book.pub.state_province)
print(book.pub.address)
运行结果:(部分)
2
水浒传3
25.00
2002-03-21
5
Publisher object
5
新疆人民出版社
乌鲁木齐
新疆
乌鲁木齐解放南路348号
示例2:返回结果为字典
"""
ORM:字典操作中有无all均可
"""
book_list = models.Book.objects.all().values('id','title','price','publication_date','pub_id',
'pub','pub__id','pub__name','pub__city',
'pub__state_province','pub__address')
for book in book_list:
print(book)
print(book['id'])
print(book['title'])
print(book['price'])
print(book['publication_date'])
print(book['pub_id'])
#下面是对这本图书关联的出版社的查询操作:利用.进行查询
print(book['pub'])
print(book['pub__id'])
print(book['pub__name'])
print(book['pub__city'])
print(book['pub__state_province'])
print(book['pub__address'])
部分运行结果:
{'pub_id': 5, 'publication_date': '2002-03-21', 'title': '水浒传3', 'pub__city': '乌鲁木齐', 'pub__name': '新疆人民出版社', 'pub': 5, 'pub__state_province': '新疆', 'id': 2, 'pub__address': '乌鲁木齐解放南路348号'
, 'price': Decimal('25.00'), 'pub__id': 5}
2
水浒传3
25.00
2002-03-21
5
5
5
新疆人民出版社
乌鲁木齐
新疆
乌鲁木齐解放南路348号
示例3:返回结果为元组
"""
ORM:元组操作中有无all均可
"""
book_list = models.Book.objects.all().values_list('id','title','price','publication_date','pub_id',
'pub','pub__id','pub__name','pub__city',
'pub__state_province','pub__address')
for book in book_list:
print(book)
print(book[0])
print(book[1])
print(book[2])
print(book[3])
print(book[4])
#下面是对这本图书关联的出版社的查询操作:利用.进行查询
print(book[5])
print(book[6])
print(book[7])
print(book[8])
print(book[9])
print(book[10])
部分运行结果:
(2, '水浒传3', Decimal('25.00'), '2002-03-21', 5, 5, 5, '新疆人民出版社', '乌鲁木齐', '新疆', '乌鲁木齐解放南路348号')
2
水浒传3
25.00
2002-03-21
5
5
5
新疆人民出版社
乌鲁木齐
新疆
乌鲁木齐解放南路348号
2、基于ORM的单表操作(反向操作) |
核心:在另外一张表中,隐藏着一个字段,通过这个字段可以获取到一个出版社到底出版了哪些书(在这里有个疑问,为什么单独打印publisher.book_set的时候显示结果为None呢,不理解!)
代码示例:
"""
ORM:单表中进行反向查询
"""
publisher_list = models.Publisher.objects.all()
for publisher in publisher_list:
print(publisher.id)
print(publisher.name)
print(publisher.city)
print(publisher.state_province)
print(publisher.address)
#注意:在一对多的一表中,隐含着一个xxx_set的字段,通过这个字段可以
#获取到一个出版社出版了哪些书
print(publisher.book_set) #这行打印出来显示
for book in publisher.book_set.all():
print(book.title)
运行结果:(部分)
5
新疆人民出版社
乌鲁木齐
新疆
乌鲁木齐解放南路348号
app.Book.None
水浒传3
祥林嫂
奋斗
3、如何在总对象当中通过过滤获取到第一个对象 |
get的缺陷:返回个数大于2个会报错,返回个数为0会报错,只有当返回个数恰好为1的时候才不会报错。
错误示例:
obj = models.Book.objects.get(price=44)
错误日志:app.models.MultipleObjectsReturned: get() returned more than one Book -- it returned 2!
obj = models.Book.objects.get(price=20)
错误日志:app.models.DoesNotExist: Book matching query does not exist.
obj = models.Book.objects.get(price=34)
因为price价格的书籍只有一本,所以不会报错
因为get当中含有各种各样的缺陷,所以我们提倡使用filter:通过filter获取到列表之后,在通过下标获取到具体的对象。
"""
ORM:如果通过过滤获取第一个对象
"""
book_list = models.Book.objects.filter(price=44).all()
print(book_list)
"""
<QuerySet [<Book: Book object>, <Book: Book object>]>
"""
obj1 = models.Book.objects.filter(price=44).all().first()
print(obj1,obj1.title)
obj2 = models.Book.objects.filter(price=44).all()[1]
print(obj2, obj2.title)
运行结果:
<QuerySet [<Book: Book object>, <Book: Book object>]>
Book object 奋斗
Book object 西游记
4、基于ORM的多表操作(正向操作) |
示例1:获取西游记这本书对应的所有作者(all)
"""
ORM:通过m字段获取图书所对应的所有作者
"""
obj = models.Book.objects.filter(title="西游记").all()[0]
author_list = obj.m.all()
print(author_list)
for author in author_list:
print(author.id)
print(author.name)
print(author.sex)
print(author.birthday)
运行结果:
<QuerySet [<Author: Author object>, <Author: Author object>]>
1
巴金
男
1898-03-21
2
余华
男
1986-03-24
实例2:获取西游记这本书对应的所有作者,并通过values获取指定的信息。
"""
ORM:通过m字段获取图书所对应的所有作者,并通过values获取指定的信息
"""
obj = models.Book.objects.filter(title="西游记").all()[0]
author_list = obj.m.all().values('id','name','sex','birthday')
for author in author_list:
print(author)
print(author['id'])
print(author['name'])
print(author['sex'])
print(author['birthday'])
运行结果:
{'id': 1, 'birthday': '1898-03-21', 'sex': '男', 'name': '巴金'}
1
巴金
男
1898-03-21
{'id': 2, 'birthday': '1986-03-24', 'sex': '男', 'name': '余华'}
2
余华
男
1986-03-24
实例3:获取西游记这本书对应的所有作者,并通过values_list获取指定的信息。
"""
ORM:通过m字段获取图书所对应的所有作者,并通过values_list获取指定的信息
"""
obj = models.Book.objects.filter(title="西游记").all()[0]
author_list = obj.m.all().values_list('id','name','sex','birthday')
for author in author_list:
print(author)
print(author[0])
print(author[1])
print(author[2])
print(author[3])
运行结果:
(1, '巴金', '男', '1898-03-21')
1
巴金
男
1898-03-21
(2, '余华', '男', '1986-03-24')
2
余华
男
1986-03-24
5、基于ORM的多表操作(反向操作) |
在多对多当中,在另外一张表中实际上隐藏着一个字段:lower(表名)_set,这个字段的作用和显示的字段实际上是一样的。
示例1:获取钱钟书作者出版过的所有书籍
"""
ORM:通过book_set字段获取钱钟书出版的所有书籍:在图书表当中隐藏着一个字段
"""
obj = models.Author.objects.filter(name='钱钟书').all()[0]
book_list = obj.book_set.all()
print(book_list)
for book in book_list:
print(book)
print(book.id)
print(book.title)
print(book.price)
print(book.publication_date)
运行结果:
<QuerySet [<Book: Book object>, <Book: Book object>]>
Book object
5
活着
3.00
2017-08-24
Book object
6
你好
4.00
1898-03-21
示例2:获取钱钟书作者出版过的所有书籍,利用values字段
"""
ORM:通过book_set字段获取钱钟书出版的所有书籍values:在图书表当中隐藏着一个字段
"""
obj = models.Author.objects.filter(name='钱钟书').all()[0]
book_list = obj.book_set.all().values('id','title','price','publication_date')
print(book_list)
for book in book_list:
print(book)
print(book['id'])
print(book['title'])
print(book['price'])
print(book['publication_date'])
运行结果:
<QuerySet [{'title': '活着', 'id': 5, 'publication_date': '2017-08-24', 'price': Decimal('3.00')}, {'title': '你好', 'id': 6, 'publication_date': '1898-03-21', 'price': Decimal('4.00')}]>
{'title': '活着', 'id': 5, 'publication_date': '2017-08-24', 'price': Decimal('3.00')}
5
活着
3.00
2017-08-24
{'title': '你好', 'id': 6, 'publication_date': '1898-03-21', 'price': Decimal('4.00')}
6
你好
4.00
1898-03-21
示例3:获取钱钟书作者出版过的所有书籍,利用values_list字段
"""
ORM:通过book_set字段获取钱钟书出版的所有书籍values_list:在图书表当中隐藏着一个字段
"""
obj = models.Author.objects.filter(name='钱钟书').all()[0]
book_list = obj.book_set.all().values_list('id','title','price','publication_date')
print(book_list)
for book in book_list:
print(book)
print(book[0])
print(book[1])
print(book[2])
print(book[3])
运行结果:
<QuerySet [(5, '活着', Decimal('3.00'), '2017-08-24'), (6, '你好', Decimal('4.00'), '1898-03-21')]>
(5, '活着', Decimal('3.00'), '2017-08-24')
5
活着
3.00
2017-08-24
(6, '你好', Decimal('4.00'), '1898-03-21')
6
你好
4.00
1898-03-21
6、基于ORM的操作总结 |
1、凡是涉及到对ORM的all()操作,返回对象为QuerySet,实际上是一个列表[].
2、无论是单表操作还是多表操作,在另外一张表中都隐含着一个lower(表名)_set字段,返回对象类型为列表.
3、凡是涉及到all操作,后面都可以跟着values(字典)、values_list(元组)获取对象指定的字段信息。
4、外键实际上是一个对象。
7、看懂的话就测试一下吧(配答案) |
测试题目:
1、获取每一本书的id、title、price、publication_date、pub_id
2、获取每一本书的title、price、publication_date信息,用values
3、获取每一本书的publication_date、pub_id信息,用values_list
4、获取每一本书对应的出版社的name、city、address信息,用values或者values_list均可
5、获取每一个出版社出版过的书籍的title、price(难),用values
6、获取每一个出版社出版过的书籍的title、price(难),用values_list
7、获取每一本书对应的作者的姓名name、出生日期birthday,方法随意
8、获取每一个作者出版过的书籍的名字title、价格price,方法随意
答案:
1、答案:
book_list = models.Book.objects.all()
for book in book_list:
print(book.id)
print(book.title)
print(book.price)
print(book.publication_date)
print(book.pub_id)
2、答案:
book_list = models.Book.objects.all().values('title','price','publication_date')
print(book_list.__len__())
for book in book_list:
print(book['title'])
print(book['price'])
print(book['publication_date'])
3、答案
book_list = models.Book.objects.all().values_list('publication_date','pub_id')
print(book_list.__len__())
for book in book_list:
print(book[0])
print(book[1])
4、答案
book_list = models.Book.objects.all().values_list('publication_date','pub_id')
print(book_list.__len__())
for book in book_list:
print(book[0])
print(book[1])
5、答案
publisher_list = models.Publisher.objects.all()
for publisher in publisher_list:
for book in publisher.book_set.all():
print(book.title)
print(book.price)
或者:
for publisher in publisher_list:
for book in publisher.book_set.all().values('title','price'):
print(book['title'])
print(book['price'])
6、答案
publisher_list = models.Publisher.objects.all()
for publisher in publisher_list:
for book in publisher.book_set.all().values_list('title','price'):
print(book[0])
print(book[1])
或者:
publisher_list = models.Publisher.objects.all()
for publisher in publisher_list:
for book in publisher.book_set.all():
print(book.title)
print(book.price)
7、答案
book_list = models.Book.objects.all()
for book in book_list:
print(book.title+"对应的作者的信息:")
for author in book.m.all():
print(author.name)
print(author.birthday)
或者:
book_list = models.Book.objects.all()
for book in book_list:
print(book.title+"对应的作者的信息:")
for author in book.m.all().values('name','birthday'):
print(author['name'])
print(author['birthday'])
或者:
book_list = models.Book.objects.all()
for book in book_list:
print(book.title+"对应的作者的信息:")
for author in book.m.all().values_list('name','birthday'):
print(author)
print(author[0])
print(author[1])
8、答案
author_list = models.Author.objects.all()
for author in author_list:
print(author.name+"出版过的书籍是:")
for book in author.book_set.all():
print(book.title)
print(book.price)
或者:
author_list = models.Author.objects.all()
for author in author_list:
print(author.name+"出版过的书籍是:")
for book in author.book_set.all().values('title','price'):
print(book['title'])
print(book['price'])
或者:
author_list = models.Author.objects.all()
for author in author_list:
print(author.name+"出版过的书籍是:")
for book in author.book_set.all().values_list('title','price'):
print(book)
print(book[0])
print(book[1])
8、related_name字段的使用 |
class Book(models.Model):
title = models.CharField('书名',max_length=100)
price = models.DecimalField('图书价格',max_digits=6,decimal_places=2)
publication_date = models.CharField('出版日期',max_length=100)
#pub在这里充当外键:构造一对多的关系
pub = models.ForeignKey(to='Publisher',to_field='id')
# 构造多对多的表关系:作者与图书之间是多对多的关系
m = models.ManyToManyField('Author')
class Author(models.Model):
name = models.CharField('姓名',max_length=100)
sex = models.CharField('性别',max_length=5)
birthday = models.CharField('出生日期',max_length=100)
在上面的两种表中,对于Book表来说,正向查询我们使用的是:
book_obj.m.all()
对于Author表来说,反向查询我们使用的是:
author_obj.book_set.all()
如果我们使用了related_name语法,如下所示:
class Book(models.Model):
title = models.CharField('书名',max_length=100)
price = models.DecimalField('图书价格',max_digits=6,decimal_places=2)
publication_date = models.CharField('出版日期',max_length=100)
#pub在这里充当外键:构造一对多的关系
pub = models.ForeignKey(to='Publisher',to_field='id')
# 构造多对多的表关系:作者与图书之间是多对多的关系
m = models.ManyToManyField('Author',related_name='xxxx')
这个时候对于book表正向查询没有什么影响,但是反向查询的时候,变成了:
author_obj.xxxx.all()
related_name:用于定义反向关联的时候,使用的字段名称,常用场景:
publisher = models.ForeignKey(to='UserInfo',to_field='id',related_name='aa')
favor = models.ManyToManyField(to='UserInfo',through='FavorTable',through_fields=('news','user'))
这样第一个就变成了obj.aa.all(),第二个还是默认的obj.表名(lower)_set.all().