zoukankan      html  css  js  c++  java
  • django的模型层(二)

    django的模型层(二)

    一 创建模型

    from django.db import models
    
    # Create your models here.
    
    
    class Author(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        age = models.IntegerField()
    
        # 一对一
        authordetail = models.OneToOneField(to="AuthorDetail", to_field="nid", on_delete=models.CASCADE)
    
        def __str__(self):
            return self.name
    
    
    
    
    
    # 作者详情表
    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()
    
        def __str__(self):
            return self.name
    
    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)
    
        # 一对多关系
        publish = models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
    
        '''
               publish_id INT ,
               FOREIGN KEY (publish_id) REFERENCES publish(id)
    
       '''
    
        # 多对多
        authors = models.ManyToManyField(to="Author")
    
        '''
        CREATE  TABLE book_authors(
           id INT PRIMARY KEY auto_increment ,
           book_id INT ,
           author_id INT ,
           FOREIGN KEY (book_id) REFERENCES book(id),
           FOREIGN KEY (author_id) REFERENCES author(id)
            )
        '''
    
    # class Book2Author(models.Model):
    #
    #     nid = models.AutoField(primary_key=True)
    #     book=models.ForeignKey(to="Book")
    #     author=models.ForeignKey(to="Author")
    
        def __str__(self):
            return self.title

    二 添加表记录

    1 一对多

        # 方式 1
        book_obj = Book.objects.create(title="水浒传",publishDate="2018-01-01",price="100",publish_id=1)
    
        print(book_obj.title)  # 水浒传
    
        # 方式2
        pub_obj = Publish.objects.filter(nid=1).first()
        # print(pub_obj)
        book_obj = Book.objects.create(title="三国演义1", price=100, publishDate="2012-12-12", publish=pub_obj)
        print(book_obj.title)
        print(book_obj.price)
        print(book_obj.publishDate)
        print(book_obj.publish)  #与这本书籍关联的出版社对象
    
        print(book_obj.publish.name)
        print(book_obj.publish.email)
        print(book_obj.publish_id)
    
    
        # 查询水浒传的出版社对应的邮箱
        book_obj = Book.objects.filter(title="水浒传").first()
        print(book_obj.publish.email)

    2 多对多

        book_obj=Book.objects.create(title="gogo",price=100,publishDate="2012-12-12",publish_id=1)
    
        egon=Author.objects.get(name="egon")
        alex=Author.objects.get(name="alex")
    
        # #绑定多对多关系的API
        book_obj.authors.add(egon,alex)
        #
        book_obj.authors.add(1,2,3)
        book_obj.authors.add(*[1,2,3])
        #
        #
        #
        # #解除多对多关系
        #
        book=Book.objects.filter(nid=4).first()
        book.authors.remove(2)
        #book.authors.remove(*[1,2])
    
        book.authors.clear()

    三  基于对象的跨表查询

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

    1 一对多

    # 一对多查询的正向查询: 查询水浒传这本书的出版社名字
    book_obj = Book.objects.filter(title="水浒传").first()
    print(book_obj.publish.name)
    
    # 对应sql:
    #select publish_id from Book where title="水浒传"
    #select name from Publish where id=1
    
    # 一对多 反向查询  查询人民出版社出版过的书籍名称
    pub_obj = Publish.objects.filter(name="人民出版社").first()
    book_list = pub_obj.book_set.all()
    print(book_list)
    正向查询   A--------->B
    反向查询   B<---------A
    
    
    ===============================
    一对多查询
        正向查询: 按字段
        反向查询: 表名小写_set.all()
    
                                book_obj.publish
        Book(关联属性:publish)   ---------------------> Publish
                                <---------------------
                                publish_obj.book_set.all()    
     

    2 多对多

    #多对多正向查询: 查询水浒传这本书作者名字
    book_obj = Book.objects.filter(title="水浒传").last()
    author_list = book_obj.authors.all()
    
    for author in author_list:
         print(author.name)
    
    
    # 多对多反向查询    查询alex出版过的书籍
    
    alex_obj = Author.objects.filter(name="alex").last()
    book_list = alex_obj.book_set.all()
    # print(book_list)
    
    for book in book_list:
          print(book.title)
    正向查询   A--------->B
    反向查询   B<---------A
    
    
    ===============================
    
    
    多对多查询:
        正向查询: 按字段
        反向查询: 表名小写_set.all()
    
                                book_obj.anthors.all()
        Book(关联属性:publish)对象   ---------------------> Author
                                <---------------------
                                author_obj.book_set.all()  #quertset
        

    3 一对一

     # 一对一查询的正向查询 : 查询alex的手机号
    
    alex=Author.objects.filter(name="alex").first()
    print(alex.authordetail.telephone)
    
    
    # 一对一查询的反向查询 : 查询手机号为110的作者的名字和年龄
    ad=AuthorDetail.objects.filter(telephone="123").first()
    print(ad.author.name)
    # print(ad.author.age)
    一对一查询:
        正向查询: 按字段
        反向查询: 表名小写
            
                                        author.authordetail
        Author(关联属性:publish)对象   ---------------------> AuthorDetail 
                                     <---------------------
                                        authordetail_obj.author 
        

    四 基于双下划线的跨表查询

    SQL join

    1 一对多

    正向查询: 按字段
    反向查询: 表名小写
        '''
        正向查询按字段,反向查询按表名小写用来告诉ORM引擎join哪张表
        '''
    
        '''
        sql 语句
            
        SELECT app01_publish.name from app01_book INNER  JOIN app01_publish 
        on app01_book.publish_id = app01_publish.nid 
        where app01_book.title="水浒传";
        
        '''
    查询水浒传这本书的出版社的名字
    # 方式一
    book_obj = Book.objects.filter(title="水浒传").values("publish__name")
    print(book_obj)
    # <QuerySet [{'publish__name': '人民出版社'}]>
    
    
    # 方式二
    ret = Publish.objects.filter(book__title="水浒传").values("name")
    print(ret)
    # <QuerySet [{'name': '人民出版社'}]>

    2 多对多 

    SELECT app01_author.name from app01_book INNER JOIN  app01_book_authors 
    on app01_book.nid = app01_book_authors.book_id
    INNER JOIN  app01_author
    on app01_book_authors.author_id = app01_author.nid
    where app01_book.title="三国演义";
    查询三国演义这本书的所有作者的名字
    # 方式一
    # 需求: 通过Book表join与其关联的Author表,属于正向查询:按字段authors通知ORM引擎join book_authors与author
    ret = Book.objects.filter(title="三国演义").values("authors__name")
    print(ret)
    
    # 方式二
    # 需求: 通过Author表join与其关联的Book表,属于反向查询:按表名小写book通知ORM引擎join book_authors与book表
    ret = Author.objects.filter(book__title="三国演义").values("name")
    
    print(ret)
    # < QuerySet[{'name': 'alex'}, {'name': 'egon'}] >

    3 一对一

    查询alex的手机号

    # 方式一
    # 需求: 通过Author表join与其关联的AuthorDetail表,属于正向查询:按字段authordetail通知ORM引擎join Authordetail表
    ret = Author.objects.filter(name="alex").values("authordetail__telephone")
    print(ret )
    # <QuerySet [{'authordetail__telephone': 123}]>
    
    #  方式二
    # 需求: 通过AuthorDetail表join与其关联的Author表,属于反向查询:按表名小写author通知ORM引擎join Author表
    ret = AuthorDetail.objects.filter(author__name="alex").values("telephone")
    print(ret)
    # <QuerySet [{'telephone': 123}]>

    4 进阶练习

    手机号以112开头的作者出版过的所有书籍名称以及书籍出版社名称
    SELECT
        app01_book.title,
        app01_publish. NAME
    FROM app01_book
    INNER JOIN app01_book_authors ON app01_book.nid = app01_book_authors.book_id
    INNER JOIN app01_author ON app01_book_authors.author_id = app01_author.nid
    INNER JOIN app01_authordetail ON app01_author.authordetail_id = app01_authordetail.nid
    INNER JOIN app01_publish ON app01_book.publish_id = app01_publish.nid
    WHERE app01_authordetail.telephone = 112;
    # 方式一 
    #  需求: 通过Book表join AuthorDetail表, Book与AuthorDetail无关联,所以必需连续跨表
    ret =Book.objects.filter(authors__authordetail__telephone="112").values("title","publish__name")
    print(ret)
    
    # 方式二
    ret = Author.objects.filter(authordetail__telephone="112").values("book__title","book__publish__name")
    print(ret)

    五 聚合与分组查询

    聚合 aggregate:返回值是一个字典,不再是queryset

    1. 聚合查询

    查询所有书籍的平均价格

    from django.db.models import  Avg,Max,Min,Count
    # select count(price) from app01__book
    ret = Book.objects.all()..aggregate(price_agv = Avg("price"))
    print(ret)

    2. 分组查询-- 单表查询

    ① 查询每一个部门的名称以及员工的平均薪水
    from django.db.models import Avg, Max, Min, Count
    
    ret = Emp.objects.values("dep").annotate(salary_avg = Avg("salary")).values("dep","salary_avg")
    print(ret)
    # <QuerySet [{'dep': '销售部', 'salary_avg': 10000.0}, {'dep': '人事部', 'salary_avg': 3333.0}]>
    
    # 单表分组查询的ORM语法: 单表模型.objects.values("group by 的字段").annotate(聚合函数的统计字段)
    ② 查询每一个省份的名称以及员工数
    ret = Emp.objects.values("province").annotate(c = Count("id")).values("province","c")
    print(ret )
    # <QuerySet [{'province': '山东', 'c': 1}, {'province': '河北', 'c': 1}]>

     ③ 补充知识点

    ret = Emp.objects.all()
    print(ret)  # select * from emp
    
    ret = Emp.objects.values("name")
    print(ret) # select name from emp;
    
    # Emp.objects.all().annotate(avg_salary=Avg("salary"))
    # SELECT avg(salary) from app01_emp  GROUP BY id
    # 没有意义 单表

    2. 分组查询-- 多表查询

    ① 查询每一个出版社的名称以及出版的书籍个数
    SELECT
        app01_publish. NAME,
        count(app01_book.title)
    FROM
        app01_book
    INNER JOIN app01_publish ON app01_book.publish_id = app01_publish.nid
    from django.db.models import Avg, Max, Min, Count
    
    
    # ret = Publish.objects.values("nid").annotate(c=Count("book__title"))
    ret = Publish.objects.values("nid").annotate(c=Count("book__title")).values("name", "c")
    print(ret)
    ② 查询每一个作者的名字以及出版过的书籍的最高价格
    SELECT
        app01_author. NAME,
        MAX(app01_book.price)
    FROM
        app01_author
    INNER JOIN app01_authordetail ON app01_author.nid = app01_authordetail.nid
    INNER JOIN app01_book_authors ON app01_author.nid = app01_book_authors.author_id
    INNER JOIN app01_book ON app01_book_authors.book_id = app01_book.nid
    GROUP BY
        app01_author.nid
    ret = Author.objects.values("pk").annotate(max_price=Max("book__price")).values("name","max_price")
    print(ret)
    # <QuerySet [{'name': 'alex', 'max_price': Decimal('300.00')}, {'name': 'egon', 'max_price': Decimal('300.00')}]>
    ③ 查询每一个书籍的名称以及对应的作者个数
    SELECT DISTINCT
        `app01_book`.`title`,
        COUNT(`app01_author`.`name`) AS `c`
    FROM
        `app01_book`
    INNER JOIN  `app01_book_authors` ON (
        `app01_book`.`nid` = `app01_book_authors`.`book_id`
    )
    INNER JOIN `app01_author` ON (
        `app01_book_authors`.`author_id` = `app01_author`.`nid`
    )
    GROUP BY
        `app01_book`.`nid`
    ret = Book.objects.values("pk").values(c=Count("authors__name")).values("title","c").distinct()
    print(ret)
    # <QuerySet [{'title': '水浒传', 'c': 2}, {'title': '三国演义', 'c': 2}]>
  • 相关阅读:
    《剑指offer》— JavaScript(29)最小的K个数
    《剑指offer》— JavaScript(28)数组中出现次数超过一半的数字
    《剑指offer》— JavaScript(27)字符串的排列
    《剑指offer》— JavaScript(26)二叉搜索树与双向链表
    《剑指offer》— JavaScript(25)复杂链表的复制
    【备忘】接口
    【备忘】WPF基础
    UWP-动态磁贴
    UWP-磁贴初识
    【备忘】C#语言基础-2
  • 原文地址:https://www.cnblogs.com/augustyang/p/11837225.html
Copyright © 2011-2022 走看看