zoukankan      html  css  js  c++  java
  • 010---Django的模型层(2)

    确定模型关系:

    '''
    Publish  ----   Book              多对一:一个出版社对应多本书,在多的那张表添加关联字段
    Book     ----   Author            多对多:一个书对应多个作者,多个作者对应一本书  会自动创建第三张表
    Author   ----   AuthorDetail      一对一:一个作者对应一个作者信息
    
    注意:
    主键可不加,django会默认添加字段为id的主键
    Django2版本会强制要求在Foreignkey添加这条参数,django1版本默认添加
    on_delete = models.CASCADE
    '''

    模型建立如下:

     1 from django.db import models
     2 
     3 # 作者详情表
     4 class AuthorDetail(models.Model):
     5     nid = models.AutoField(primary_key=True)
     6     birthday = models.DateField(verbose_name='生日')
     7     telephone = models.BigIntegerField(verbose_name='手机号')
     8     address = models.CharField(max_length=64)
     9 
    10 
    11 # 出版社表
    12 class Publish(models.Model):
    13     nid = models.AutoField(primary_key=True)
    14     name = models.CharField(max_length=32, verbose_name="出版社名称")
    15     city = models.CharField(max_length=32, verbose_name='城市')
    16     email = models.EmailField(verbose_name='邮箱')
    17 
    18     def __str__(self):
    19         return self.name
    20 
    21 # 书籍表
    22 class Book(models.Model):
    23     nid = models.AutoField(primary_key=True)
    24     title = models.CharField(max_length=32, verbose_name="书籍名称")
    25     publish_date = models.DateField(verbose_name='出版日期')
    26     price = models.DecimalField(max_digits=5, decimal_places=2, verbose_name='价格')
    27     read_num = models.IntegerField(verbose_name='阅读数',default=0)
    28     comment_num = models.IntegerField(verbose_name='评论数',default=0)
    29 
    30     publish = models.ForeignKey(to='Publish', to_field='nid', verbose_name='出版社',on_delete=models.CASCADE)
    31     author = models.ManyToManyField(to='Author',verbose_name='作者')
    32 
    33     def __str__(self):
    34         return self.title
    35 
    36 # 作者表
    37 class Author(models.Model):
    38     nid = models.AutoField(primary_key=True)
    39     name = models.CharField(max_length=32, verbose_name="作者名称")
    40     age = models.IntegerField(verbose_name='作者年龄')
    41     author_detail = models.OneToOneField(to='AuthorDetail', to_field='nid', unique=True,on_delete=models.CASCADE)
    42 
    43     def __str__(self):
    44         return self.name

    会生成五张表:

    注意事项:

    •  表的名称:myapp_modelName,是根据 模型中的元数据自动生成的,也可以覆写为别的名称
    • id字段是自动添加的。主键也可以不自己写
    • 对于外键字段。django会在字段名上添加‘_id’来创建数据库的列名
    • 定义好模型之后,要告诉django使用这些模型,就要在settings.py文件中的INSTALL_APPS中设置,添加models.py文件所在应用的app名称
    • 外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None 

     添加表记录:

    首先添加一个出版社:

    1   pub = Publish.objects.create(name='人民出版社',email='123@qq.com',city='北京')

     然后就可以为书籍绑定关系:

     1     ===========================绑定一对多关系===========================
     2     为book表绑定关系: publish  ---  book
     3     方式1
     4     book_obj = Book.objects.create(title='红楼梦',price=100,publish_date='2018-08-08',publish_id=1)
     5     print(book_obj.title)
     6 
     7     方式2
     8     pub_obj = Publish.objects.filter(nid=1).first()
     9     book_obj = Book.objects.create(title='西游记',price=100,publish_date='2018-07-07',publish=pub_obj)
    10     print(book_obj.title)
    11     print(book_obj.publish_id)
    12     print(book_obj.publish)  # 与这本书籍关联的出版社对象
    13     print(book_obj.publish.name)
     1     ===========================绑定多对多关系===========================
     2     book_obj = Book.objects.create(title='金瓶子', price=100, publish_date='2018-07-07', publish_id=1)
     3     alex = Author.objects.get(name='alex')
     4     egon = Author.objects.get(name='egon')
     5     # 绑定多对多关系的API
     6 
     7     book_obj.author.add(egon,alex)
     8     book_obj.author.add(1,2)
     9     book_obj.author.add(*[1,2,3])
    10 
    11     解除多对多关系
    12     book = Book.objects.filter(title='金瓶子').first()
    13     book.author.remove(2)
    14     # 清除所有
    15     book.author.clear()
    16     # 获取所有
    17     # 查询主键为4的数据所有作者的名字
    18     print(book.author.all())  # <QuerySet [<Author: alex>]>
    19     print(book.author.all().values('name','age'))  # <QuerySet [{'name': 'alex', 'age': 33}]>

    跨表查询:

    1. 基于对象查询
    2. 基于双下划线查询
    3. 聚合和分组查询
    4. F 和 Q查询
     1      ------------------------------------1、基于对象查询(子查询)------------------------------------
     2 
     3      一对多的正向查询:查询金瓶子这本书的出版社的名字
     4     book_obj = Book.objects.filter(title='金瓶子').first()
     5     print(book_obj.publish)     # 与这本书关联的出版社对象
     6     print(book_obj.publish.name)
     7 
     8      一对多的反向查询:查询人民出版社出版的书
     9     publish = Publish.objects.filter(name='人民出版社').first()
    10     ret = publish.book_set.all()
    11     print(ret)
    12 
    13      多对多的正向查询:查询金瓶子这本书的所有作者名字
    14     book.author.all()
    15 
    16      多对多的反向查询:查询alex写的所有的书
    17     author = Author.objects.filter(name='alex').first()
    18     ret = author.book_set.all()
    19 
    20     一对一的正向查询:查询egon的作者信息
    21     author = Author.objects.filter(name='egon').first()
    22     ret = author.author_detail.telephone
    23 
    24     一对一的反向查询:查询手机号为110的作者的名字和年龄
    25     detail = AuthorDetail.objects.filter(telephone='110').first()
    26     ret = detail.author
    27     print(ret.name,ret.age)     # alex 33


    '''
    A--B
    关联属性在A表中
    正向查询: A--B
    反向查询: B--A

    # 一对多查询
    正向查询:按字段
    反向查询:按表名(小写)_set.all()

    # 多对多查询
    正向查询:按字段
    反向查询:按表名(小写)_set.all()

    # 一对一查询
    正向查询:按字段
    反向查询:按表名(小写) 因为一对一查询的只有单条,所以没有all set
    '''
     1     # ------------------------------------2、基于双下划线的跨表查询(join查询)------------------------------------
     2     #  一对多:查询金瓶子这本书的出版社的名字
     3 
     4     # 方式1:正向查询:
     5     # ret= Book.objects.filter(title='金瓶子').values('publish__name')
     6     # print(ret)  # <QuerySet [{'publish__name': '人民出版社'}]>
     7 
     8     # 方式2:反向查询:
     9     # Publish.objects.filter(book__title='金瓶子').values('name')
    10 
    11     # 多对多:查询西游记这本书的所有作者名字
    12 
    13     # 正向:按字段
    14     # ret = Book.objects.filter(title='西游记').values('author__name')
    15     # print(ret)
    16 
    17     # 反向:按表名
    18     # ret = Author.objects.filter(book__title='西游记').values('name')
    19     # print(ret)
    20 
    21     # 一对一查询 :查询alex的手机号
    22 
    23     # 正向
    24     # ret = Author.objects.filter(name='alex').values('author_detail__telephone')
    25     # print(ret)  # <QuerySet [{'author_detail__telephone': 110}]>
    26 
    27     # 反向
    28     # ret1 = AuthorDetail.objects.filter(author__name='alex').values('telephone')
    29     # print(ret1) # <QuerySet [{'telephone': 110}]>
    30 
    31     # 查询手机号以110开头的作者出版过的所有书籍名称以及书籍出版社名称
    32 
    33     # 正向
    34     # ret3 = Book.objects.filter(author__author_detail__telephone__startswith='110').values('title', 'publish__name')
    35     # print(ret3)  # <QuerySet [{'title': '西游记', 'publish__name': '人民出版社'}, {'title': '金瓶子', 'publish__name': '人民出版社'}]>
    36 
    37     # 反向
    38     # ret4 = Author.objects.filter(author_detail__telephone__startswith='110').values('book__title',
    39     #                                                                                 'book__publish__name')
    40     # print(ret4)  # <QuerySet [{'book__title': '金瓶子', 'book__publish__name': '人民出版社'}, {'book__title': '西游记', 'book__publish__name': '人民出版社'}]>
    1     # ------------------------------------3、聚合查询aggregate:返回的是一个字典,不再是queryset集合------------------------------------
    2     from django.db.models import Avg, Max, Min, Count
    3     # 查询所有书籍的平均价格
    4     # ret = Book.objects.all().aggregate(Avg('price'))
    5     # ret1 = Book.objects.all().aggregate(price=Avg('price'),max_price=Max('price'))
    6     # print(ret)  # {'price__avg': 97.0}
    7     # print(ret1) # {'price': 97.0, 'max_price': 100.0}
     1     # ------------------------------------3、分组查询 annotate 返回值依然是queryset------------------------------------
     2     # 单表分组查询:在单表下,按照主键分组没有任何意义
     3     
     4     # 查询每一个部门的名称及员工的平均薪水
     5     # select dep,Avg(salary) from emp group by dep
     6     # ret = Emp.objects.values('dep').annotate(avg_salary=Avg('salary'))
     7     # print(ret) # <QuerySet [{'dep': '销售部', 'avg_salary': 2000.0}, {'dep': '技术部', 'avg_salary': 3500.0}, {'dep': '人事部', 'avg_salary': 9000.0}]>
     8 
     9     # 查询每一个省份的名称及员工数
    10 
    11     # ret1 = Emp.objects.values('province').annotate(emp_count=Count('id'))
    12     # print(ret1) # <QuerySet [{'province': '江西', 'emp_count': 2}, {'province': '北京', 'emp_count': 1}, {'province': '南昌', 'emp_count': 1}]>
    13 
    14     # 查询每一个出版社的名字及出版的书的个数
    15     # ret = Publish.objects.values('name').annotate(Count('book'))
    16     # print(ret)  # <QuerySet [{'name': '人民出版社', 'book__count': 3}, {'name': '南京出版社', 'book__count': 1}]>
    17 
    18     # ret1 = Book.objects.values('publish__name').annotate(Count('nid'))
    19     # print(ret1) # <QuerySet [{'publish__name': '人民出版社', 'nid__count': 3}, {'publish__name': '南京出版社', 'nid__count': 1}]>
    20 
    21     # ret2 = Publish.objects.values('nid').annotate(c=Count('book__title')).values('name','c')
    22     # print(ret2)
    23 
    24 
    25     # 查询每个作者的名字及出版过的书籍的最高价格
    26     # ret3 = Author.objects.values('nid').annotate(m=Max('book__price')).values('name','m')
    27     # print(ret3)
    28 
    29     # 总结跨表的分组查询的模型
    30     # 每一个表的模型.objects.values('pk').annotate(聚合函数(关联表__字段)).values所有字段)
    31     # 每一个表的模型.objects.annotate(聚合函数(关联表__字段)).values(所有字段)
    32 
    33     # 查询每一个书籍的名称对应的作者个数
    34     # ret4 = Book.objects.values('pk').annotate(c=Count('author__name')).values('title','c')
    35     # print(ret4)
    36 
    37 
    38     # 统计每一本以py开头的书籍的作者个数:
    39     # ret5 = Book.objects.filter(title__startswith='py').annotate(c=Count('author__name')).values('title','c')
    40     # print(ret5)
    41 
    42     # 统计不止一个作者的书籍
    43     # ret6 = Book.objects.values('pk').annotate(c=Count('author__name')).filter(c__gt=1).values('title','c')
    44     # print(ret6)

    总结跨表的分组查询模型:

    1 每一个表的模型.objects.values('pk').annotate(聚合函数('关联表__字段').values('字段1',‘字段2’))
    2 
    3 每一个表的模型.objects.annotate(聚合函数(关联表__字段)).values(所有字段)

    练习:

     1     # 查询每一个书籍的名称对应的作者个数
     2 
     3     # ret4 = Book.objects.values('pk').annotate(c=Count('author__name')).values('title','c')
     4     # print(ret4)
     5 
     6 
     7     # 统计每一本以py开头的书籍的作者个数:
     8     # ret5 = Book.objects.filter(title__startswith='py').annotate(c=Count('author__name')).values('title','c')
     9     # print(ret5)
    10 
    11     # 统计不止一个作者的书籍
    12     # ret6 = Book.objects.values('pk').annotate(c=Count('author__name')).filter(c__gt=1).values('title','c')
    13     # print(ret6)
     1     # ------------------------------------F和Q查询------------------------------------
     2     from django.db.models import F,Q
     3 
     4     # 查询评论数大于阅读数的
     5     # ret = Book.objects.filter(read_num__gt=F('comment_num'))
     6     # print(ret)
     7 
     8     # 所有书籍的价格+10
     9     # ret = Book.objects.all().update(price=F('price')+1)
    10     # print(ret)
    11 
    12     # 复杂的条件查询
    13 
    14     # 查询书籍名称是红楼梦 且 价格是78的书籍
    15     ret = Book.objects.filter(Q(title='红楼梦')&Q(price=78))
    16     # 查询书籍名称是红楼梦 或 价格是78的书籍
    17     Book.objects.filter(Q(title='红楼梦')|Q(price=78))
    18     # 取反  非的意思 名称不是红楼梦或者价格等于78
    19     Book.objects.filter(~Q(title='红楼梦')|Q(price=78))
    20     print(ret)
  • 相关阅读:
    MySQL 基础 查询
    Mysql+keepalived双主
    Kubernetes(二)K8S基础架构
    Kubernetes(一)K8S入门
    Docker (五) 利用Dockerfile创建Nginx镜像
    Docker (四) 使用Dockerfile的方式构建镜像
    Docker (三) 使用commit创建Docker镜像
    Docker (二) Docker网络配置
    Ansible (四) 角色Roles
    Docker (一) Docker入门
  • 原文地址:https://www.cnblogs.com/xjmlove/p/9914275.html
Copyright © 2011-2022 走看看