深入理解Django中的ORM数据库操作(Django系列1)

博客核心内容:


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().

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只懒得睁眼的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值