ORM操作 之 跨表查询和 分组查询实例

浏览目录

 

 

分析代码

 <1>  每个数据模型都是django.db.models.Model的子类,它的父类Model包含了所有必要的和数据库交互的方法。并提供了一个简介漂亮的定义数据库字段的语法。

       <2>  每个模型相当于单个数据库表(多对多关系例外,会多生成一张关系表),每个属性也是这个表中的字段。属性名就是字段名,它的类型(例如CharField)相当于数据库的字段类型(例如varchar)。大家可以留意下其它的类型都和数据库里的什么字段对应。

       <3>  模型之间的三种关系:一对一,一对多,多对多。

             一对一:实质就是在主外键(author_id就是foreign key)的关系基础上,给外键加了一个UNIQUE=True的属性;

             一对多:就是主外键关系;(foreign key)

             多对多:(ManyToManyField) 自动创建第三张表(当然我们也可以自己创建第三张表:两个foreign key)

创建表

作者模型:一个作者有姓名和年龄。

作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one)

出版商模型:出版商有名称,所在城市以及email。

书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。

模型建立如下:

#作者
class Author(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) age = models.IntegerField() # 与AuthorDetail建立一对一的关系 authorDetail = models.OneToOneField(to="AuthorDetail")
#作者详情
class AuthorDetail(models.Model):
    nid = models.AutoField(primary_key=True)
    birthday = models.DateField()
    telephone = models.BigIntegerField()
    addr = models.CharField(max_length=64)

#图书版 class Publish(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField() #书籍 class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=32) publishDate = models.DateField() price = models.DecimalField(max_digits=5, decimal_places=2) keepNum = models.IntegerField() commentNum = models.IntegerField() # 与Publish建立一对多的关系,外键字段建立在多的一方 publish = models.ForeignKey(to="Publish", to_field="nid",) # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表 authors = models.ManyToManyField(to='Author')

注意事项:

1、 表的名称myapp_modelName,是根据 模型中的元数据自动生成的,也可以覆写为别的名称  

2、id 字段是自动添加的

3、对于外键字段,Django 会在字段名上添加"_id" 来创建数据库中的列名

4、这个例子中的CREATE TABLE SQL 语句使用PostgreSQL 语法格式,要注意的是Django 会根据settings 中指定的数据库类型来使用相应的SQL 语句。

5、定义好模型之后,你需要告诉Django _使用_这些模型。你要做的就是修改配置文件中的INSTALL_APPSZ中设置,在其中添加models.py所在应用的名称。

6、外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None 。

基于对象的跨表查询(子查询)

一对多

'''
         正向查询按字段
    Book--------------->Publish
        <---------------
         反向查询按表名小写_set
    '''

 正向查找

查询id为2的书籍对应出版社的邮箱

obj = Book.objects.filter(nid=2).first()
print(obj.publish.email)  

反向查找 

橘子出版社出版过的所有的书籍的名字

obj = Publish.objects.filter(name="橘子出版社").first()
ret = obj.book_set.all().values("title")
print(ret)  

多对多

'''
            正向查询按字段
       Book--------------->Author
           <---------------
            反向查询按表名小写_set
            反向查询按xxx
    '''  

注意:有个relate_name可以为反向查找表名做命名,当做字段来用。

正向查找

查询十万个为什么所有作者的名字

obj = Book.objects.filter(title="十万个为什么").first()
ret = obj.authors.all().values("name")
print(ret)  

反向查找

查询alex出版的书籍个数

obj = Author.objects.filter(name="alex").first()
ret = obj.book_set.all().count()
print(ret)  

一对一

'''
                正向查询按字段
           Book--------------->Author
               <---------------
                反向查询按表名小写
    ''' 

正向查找

查询alex的手机号

obj = Author.objects.filter(name="alex").first()
ret = obj.authorDetail.telephone
print(ret)  

反向查找

住在烟台的作者的名字

obj_list = AuthorDetail.objects.filter(addr="烟台")
    for obj in obj_list:
        print(obj.author.name)

基于queryset和__的跨表查询(join查询)

'''
    正向查询安字段
    反向查询安表名
    '''

 '''
    Book.objects.filter(price=100).values("title","publish__email"):
    queryset=Book.objects.filter(price=100)
    temp=[]
    for obj in queryset:
        temp.append({
            "title":obj.title,
            "publish__email":obj.publish__email
        })

    temp

    '''

(1)查询id为2的书籍对应出版社的邮箱

ret = Book.objects.filter(price=100).values("publish__email")
print(ret)  # [{publish__email:123},{publish__email:456},{publish__email:456}] 

(2)橘子出版社出版过的所有的书籍的名字 

ret = Publish.objects.filter(name="橘子出版社").values("book__title")
print(ret)

(3)查询十万个为什么所有作者的名字

ret = Book.objects.filter(title="十万个为什么").values("authors__name")
print(ret)

(4)查询alex出版的书籍个数

Author.objects.filter(name="alex").values("book__title").count()

(5)查询alex的手机号

ret = Author.objects.filter(name="alex").values("authorDetail__telephone")
print(ret)

(6)住在烟台的作者的名字

ret = AuthorDetail.objects.filter(addr="烟台").values("author__name")
print(ret)  

分组查询

跨表查询

from django.db.models import Count, Avg

每一个出版社的名字以及对应出版书籍个数

ret = Publish.objects.all().annotate(book_count=Count("book__title")).values("name", "book_count")
print(ret)

查询每一个作者的名字以及对应书籍的平均价格

ret = Author.objects.all().annotate(books_avg=Avg("book__price")).values("name", "books_avg")
 print(ret)

查询每一本书 的名字以及作者的个数

ret = Book.objects.all().annotate(c=Count("authors")).values("title", "c")
print(ret)  

单表查询

 

posted @ 2018-04-16 20:57  高~雅  阅读(505)  评论(0编辑  收藏  举报