图书信息系统

表结构设计

复制代码
# 书
class Book(models.Model):
    title = models.CharField(max_length=32)
    publish_date = models.DateField(auto_now_add=True)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    # 创建外键,关联publish
    publisher = models.ForeignKey(to="Publisher")
    # 创建多对多关联author
    author = models.ManyToManyField(to="Author")

    def __str__(self):
        return self.title


# 出版社
class Publisher(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)

    def __str__(self):
        return self.name


# 作者
class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    phone = models.IntegerField()
    detail = models.OneToOneField(to="AuthorDetail")

    def __str__(self):
        return self.name


# 作者详情
class AuthorDetail(models.Model):
    addr = models.CharField(max_length=64)
    email = models.EmailField()
复制代码

普通查询练习

查找所有书名里包含番茄的书
查找出版日期是2017年的书
查找出版日期是2017年的书名
查找价格大于10元的书
查找价格大于10元的书名和价格
查找memo字段是空的书

查找在北京的出版社
查找名字以沙河开头的出版社

查找作者名字里面带“小”字的作者
查找年龄大于30岁的作者
查找手机号是155开头的作者
查找手机号是155开头的作者的姓名和年龄

查找书名是“番茄物语”的书的出版社
查找书名是“番茄物语”的书的出版社所在的城市
查找书名是“番茄物语”的书的出版社的名称

查找书名是“番茄物语”的书的所有作者
查找书名是“番茄物语”的书的作者的年龄
查找书名是“番茄物语”的书的作者的手机号码

查找书名是“番茄物语”的书的作者的地址
查找书名是“番茄物语”的书的作者的邮箱

简单示例

注意:

1.只有object才能直接.属性   Queryset只能用.value(字段)

2.   关于表名_set 

      • 表名_set的前边必须是object才行
      • 表名_set得到的其实是一个queryset对象可以使用queryset方法

3.一对一查询反向不能用表名_set这种方法

单表查询

查询书名为番茄物语的书

>>> models.Book.objects.filter(title="番茄物语")
<QuerySet [<Book: 番茄物语>]>

一对多查询

查询id为1的书的出版社所在的城市(正向查找)

>>> models.Book.objects.get(id=1).publisher.city
'北京'

查询id为1的出版社的出版的所有书籍(反向查找) 

>>> models.Publisher.objects.get(id=1).book_set.all()
<QuerySet [<Book: 番茄物语>, <Book: 香蕉物语>]>

一对一查询

一对一反向查时,不能用表名_set

查询小精灵作者的邮箱

>>> models.Author.objects.get(name="小精灵").detail.email
'1@1.com'

查询邮箱为'1@1.com'的作者(反向查)

models.Author_detail.filter(email="1@1.com").values("author_name")

查询所有addr="快乐星球"的作者姓名  

>>> author_details = models.AuthorDetail.objects.filter(addr="快乐星球")
>>> for obj in author_details:
...     print(obj.author.name)
小仙女
小魔女

多对多查询

查询番茄物语所有作者的姓名和邮箱(正向查找)

复制代码
>>> models.Book.objects.get(title="番茄物语").author.all()
<QuerySet [<Author: 小精灵>, <Author: 小仙女>]>
>>> for obj in author_list:
...     print(obj.name, obj.detail.email)
... 
小精灵 1@1.com
小仙女 2@2.com
复制代码

查询小仙女出版的所有书籍

>>> models.Author.objects.get(name="小仙女").book_set.all()
<QuerySet [<Book: 番茄物语>, <Book: 橘子物语>]>

了不起的双下划线(跨表查询)

查询沙河出版社出版的所有书籍的名称和价格

(正向查)

>>> models.Book.objects.filter(publisher__name="沙河出版社").values_list("title", "price")
<QuerySet [('番茄物语', Decimal('9.90')), ('香蕉物语', Decimal('9.90'))]>

反向查

>>> models.Publisher.objects.get(name="沙河出版社").book_set.all().values_list("title", "price")
<QuerySet [('番茄物语', Decimal('9.90')), ('香蕉物语', Decimal('9.90'))]>

双下划线反查

>>> models.Publisher.objects.filter(name="沙河出版社").values_list("book__title", "book__price")
<QuerySet [('番茄物语', Decimal('9.90')), ('香蕉物语', Decimal('9.90'))]>

查询小仙女出版的所有书籍名称

正向查

>>> models.Book.objects.filter(author__name="小仙女").values_list("title")
<QuerySet [('番茄物语',), ('橘子物语',)]>

反向查

>>> models.Author.objects.get(name="小仙女").book_set.all().values_list("title")
<QuerySet [('番茄物语',), ('橘子物语',)]>

双下划线反查

>>> models.Author.objects.filter(name="小仙女").values_list("book__title")
<QuerySet [('番茄物语',), ('橘子物语',)]>

查询沙河出版社出版的书籍的书名和作者姓名

正向查

>>> models.Book.objects.filter(publisher__name="沙河出版社").values_list("title", "author__name")
<QuerySet [('番茄物语', '小精灵'), ('番茄物语', '小仙女'), ('香蕉物语', '小魔女')]>

反向查

>>> models.Publisher.objects.filter(name="沙河出版社").values_list("book__title", "book__author__name")
<QuerySet [('番茄物语', '小精灵'), ('番茄物语', '小仙女'), ('香蕉物语', '小魔女')]>

双下划线反向查

>>> models.Publisher.objects.get(name="沙河出版社").book_set.all().values_list("title", "author__name")
<QuerySet [('番茄物语', '小精灵'), ('番茄物语', '小仙女'), ('香蕉物语', '小魔女')]>

补充

查询memo为空的所有书

>>> models.Book.objects.filter(memo__isnull=True)

YUAN老师讲的跨表查询

设计表格:

          关系图

 

from django.db import models

# Create your models here.
class Book(models.Model):
    title=models.CharField(max_length=32)
    publishs=models.ForeignKey(to='Publish') # to后边跟的表名要跟大写
    authors=models.ManyToManyField(to="Author")
    
class Publish(models.Model):
    name=models.CharField(max_length=32)
class Author(models.Model):
    name=models.CharField(max_length=32)
    details=models.OneToOneField(to="Author_detail")
class Author_detail(models.Model):
    email=models.EmailField()

得到的表格主要的

发现了没?  manytomany 建立的第三张表的名是 book和authors字段建立的,而并不是和author表建立的

 author 表和author_detail表一对一后,在author表中添加了一个字段 details_id 在自己定义的字段的基础上加了一个_id

 book表和publish表建立onetomany 关系后在book表中生成的字段是publishs_id, 在自己定义的字段基础长加了id,

操作第三张表

增加:

我们知道我们是无法直接给给多对多创造的第三张表添加记录的. orm为我们提供了一个很好的接口add()

#步骤1首先查询到自己需要关联的对象和被关联的对象
 book_obj=models.Book.objects.get(title="")
  # book_obj.authors.all() 这是manytomany提供的方法,与这本书关联的所有作者的queryset
  auththor1=models.Author.objects.get(name="韩信")
  auththor2=models.Author.objects.get(name="李白")
#步骤2 根据对象.字段用add的方法把要关联的对象添加进去
  方法1: book_obj.authors.add(auththor1,auththor2) 
方法2: 你要把所有的作者关联给这本书就可以用Queryset来做
author_list=models.authors.objects.all
book_obj.authors.add(*authors) #其实这里是用列表打散的方式进行传递的

删除:

#步骤1首先查询到自己需要关联的对象和被关联的对象
 book_obj=models.Book.objects.get(title="")
  # book_obj.authors.all() 这是manytomany提供的方法,与这本书关联的所有作者的queryset
  auththor1=models.Author.objects.get(name="韩信")
  auththor2=models.Author.objects.get(name="李白")
#步骤2 根据对象.字段用add的方法把要关联的对象移除
  方法1: book_obj.authors.remove(auththor1,auththor2) 
方法2: 你要把所有的作者关联给这本书就可以用Queryset来做
   author_list=models.authors.objects.all
  book_obj.authors.remove(*authors) #其实这里是用列表打散的方式进行传递的

清除:

clear()

book_obj.authors.clear()

重置(修改)

set()

先清空,在设置,编辑书籍时即可用到

注意

对于所有类型的关联字段,add()、create()、remove()和clear(),set()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用save()方法。

 

直接赋值:

通过赋值一个新的可迭代的对象,关联对象集可以被整体替换掉。

1
2
>>> new_list = [obj1, obj2, obj3]
>>> e.related_set = new_list

如果外键关系满足null=True,关联管理器会在添加new_list中的内容之前,首先调用clear()方法来解除关联集中一切已存在对象的关联。否则, new_list中的对象会在已存在的关联的基础上被添加。  

 

进行跨表查询

基于对象查询(本质在SQL语句中使用的子查询)

总结:

  • 正向查询: 对象.关联字段.字段
  • 反向查询:对象.关联的表名__set ,但是一对一不能用表名set.直接 表名就可以了

一对多查询:    

#正向查询语法:对象.关联字段
  #查询金这本书的出版社的名称
  data = models.Book.objects.get(title="").publishs.name
#反向查询语法:对象.另一个表名_set
#乡村爱情出版社出版过所有的图书
  data = models.Publish.objects.get(name="乡村爱情出版社").book_set.values("title")
  

 多对多的关系

#正向查询语法:对象.关联字段
#金瓶mei这本书所有的作者
  data=models.Book.objects.get(title="").authors.values("name")
#反向查询语法(对象,另一个表名_set)
#韩信写过的所有书的名字
  data=models.Author.objects.get(name="韩信").book_set.values("title")

一对一关系:

#正向查询语法:对象.关联字段
#李白的email
data=models.Author.objects.get(name="李白").details.email
#反向查询语法: 对象.表名(为什么不用表名_set因为表名_set得到的是一个queryset是一个集合,但是一对一就是一个对象)
#email为2363@qq.com的作者
data=models.Author_detail.objects.get(email="2363@qq.com").author.name

 

基于Queryset和__查询(本质在SQL语句中使用的join查询)

总结:

  • 正向查询 Queryset.values("关联字段__字段)
  • 反向查询:Queryset.values("关联的表名__字段)

一对多查询:

#正向查询语法: Queryset.value("关联字段__字段")
#查询金瓶这本书的出版社的名称
data=models.Book.objects.filter(title="金瓶").values("publishs__name")
#反向查询语法: Queryset.value("关联的表名.字段")
#查询乡村爱情出版过的书
 data=models.Publish.objects.filter(name="乡村爱情出版社").values("book__title")

多对多查询:

#正向查询语法:Queryset.values("关联字段名__字段")
#金瓶mei这本书所有的作者
  data=models.Book.objects.filter(title="金瓶").values("authors__name")
#反向查询语法:Queryset.values("另一个表名__字段")
#韩信写过的所有书的名字
   data=models.Author.objects.filter(name="韩信").values("book__title")

一对一查询:

#正向查询语法:Queryset.value("关联字段__字段")
#李白的email
data=data=models.Author.objects.filter(name="李白").values("details__email")
#反向查询语法: Queryset.value("另一个表名__字段")
#email为2363@qq.com的作者
data=models.Author_detail.objects.filter(email="2363@qq.com").values("author__name")

 

扩展:

 

手机号以151开头的作者出版过的所有书籍名称以及出版社名称

Book.objects.filter(authors__details__telephone__startswith="151").values("title","publish__name")

 

related_name

 

这个名称用于让关联的对象反查到源对象。通常情况下 ,反查我们是不用这个属性的,基于对象我们会用表名_set的,如果是基于Queryset,我们是表名__这个属性用在什么情况呢? 

适用范围: 当一个表被多个表关联的时候,这时候反向查原对象时,就需要每个关联对象的relate_name,只有这样才能查到对应的值.

反向查询时,如果定义了related_name ,则用related_name替换表名,例如: publish = models.ForeignKey(Blog, related_name='bookList'): 反向查询时: Publish.booklist.all()

1
2
3
4
5
6
7
# 练习1:  查询人民出版社出版过的所有书籍的名字与价格(一对多)
 
    # 反向查询 不再按表名:book,而是related_name:bookList
 
    queryResult=Publish.objects
              .filter(name="人民出版社")
              .values_list("bookList__title","bookList__price")
posted on 2018-01-25 16:32  程序员一学徒  阅读(237)  评论(0)    收藏  举报