zoukankan      html  css  js  c++  java
  • Django ORM多表操作

    准备数据表

    models.py

    from django.db import models
    
    
    # 作者表
    class Author(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        # 一对一, to_field 关联字段不填默认是 id,
        # on_delete=models.CASCADE 级联删除 models.SET_NULL 不级联删除但是设置为空
        # 生成表字段之后,会字段变为authorDetail_id
        # django2.x中必须要写on_delete, 否则报错
        authorDetail = models.OneToOneField(to="AuthorDetail", to_field="id", on_delete=models.CASCADE)
    
        def __str__(self):
            return self.name
    
    
    
    # 作者详细信息表
    class AuthorDetail(models.Model):
        birthday = models.DateField()
        telephone = models.CharField(max_length=32)  # 设置为字符串,方便做模糊查询
        addr = models.CharField(max_length=64)
    
        def __str__(self):
            return self.addr
    
    
    # 出版社表
    class Publish(models.Model):
        name = models.CharField(max_length=32)
        city = models.CharField(max_length=32)
        email = models.EmailField()  			# 实际是charField
    
        def __str__(self):
            return self.name
    
    
    # 书籍表
    class Book(models.Model):
        title = models.CharField(max_length=32)
        publishDate = models.DateField()
        price = models.DecimalField(max_digits=5, decimal_places=2)
        # 一对多 related_name 代替反向查询表名
        publish = models.ForeignKey(
            to="Publish", 
            on_delete=models.CASCADE,
            # related_name='xx'				# 起别名
        )
        # 多对多
        authors = models.ManyToManyField(to='Author')
        # 点赞
        good = models.IntegerField(default=1)
        # 评论
        comment = models.IntegerField(default=1)
    
        def __str__(self):
            return f'{self.id:0>3}---{self.title}'
    

    视图

    views.py

    一对一

    # 方式1
    new_author_detail = models.AuthorDetail.objects.create(
        birthday='1979-08-08',
        telephone='1383838438',
        addr='北京市'
    )
    models.Author.objects.create(
        name='李四',
        age=40,
        authorDetail=new_author_detail
    )
    
    # 方式2
    obj = models.AuthorDetail.objects.filter(addr='武汉市').first()
    models.Author.objects.create(
        name='张三',
        age=20,    
        authorDetail_id=obj.id
    )
    

    # 级联删除
    models.AuthorDetail.objects.get(id=2).delete()
    # 单独删除
    models.Author.objects.get(id=4).delete()
    

    author_obj = models.Author.objects.filter(id=5).update(
        age = 10,
        authorDetail = models.AuthorDetail.objects.get(id=5)
        # authorDetail_id = models.AuthorDetail.objects.get(id=5).id
    )
    

    基于对象的查询
    # 1 正向查询,通过属性(字段)名
    author_obj = models.Author.objects.filter(name='alex').first()
    print(author_obj.authorDetail)              # authorDetail 对象
    print(author_obj.authorDetail.telephone)
    
    # 2 反向查询,通过小写的类(表)名
    author_detail_obj = models.AuthorDetail.objects.get(telephone='1383838438')
    print(author_detail_obj.author)             # author 对象
    print(author_detail_obj.author.name)
    
    基于双下划线的查询
    # 正向查询1
    obj = models.Author.objects.filter(name='alex').values('authorDetail__telephone')
    print(obj)
    print(obj.first()['authorDetail__telephone'])
    # 正向查询2
    obj = models.Author.objects.get(authorDetail__telephone='1383838438')
    print(obj.name)
    # 反向查询1
    obj = models.AuthorDetail.objects.filter(author__name='alex').first()
    print(obj.telephone)
    # 反向查询2
    obj = models.AuthorDetail.objects.filter(telephone='1383838438').values('author__name')
    print(obj)
    print(obj[0]['author__name'])
    

    一对多

    # 方式1
    models.Book.objects.create(
        title='床头故事',
        publishDate='2019-07-22',
        price=3,
        publish=models.Publish.objects.get(id=3),
    )
    # 方式2
    models.Book.objects.create(
        title='床头故事2',
        publishDate='2019-07-22',
        price=3.5,
        publish_id = models.Publish.objects.get(id=3).id,
    )
    

    # 级联删除
    models.Publish.objects.get(id=3).delete()
    # 单独删除
    models.Book.objects.get(id=5).delete()
    

    models.Book.objects.filter(pk=6)		# pk(primary key),不管字段名是什么,pk代表主键
    models.Book.objects.filter(id=6).update(
        publish = models.Publish.objects.get(id=5),
        # publish_id = models.Publish.objects.get(id=5).id
    )
    # ORM无级联更新(一对一, 一对多)
    # models.Publish.objects.filter(id=4).update(id=1)  # 报错
    

    基于对象的查询
    # 1 正向查询,通过属性(字段)名
    book_obj = models.Book.objects.filter(title='床头的故事').first()
    print(book_obj.publish)
    print(book_obj.publish.name)
    
    # 2 反向查询,通过小写的类(表)名_set
    publish_obj = models.Publish.objects.filter(name='太白出版社').first()
    # 类似控制器,可以调用 all, filter, get, exclude
    print(publish_obj.book_set.all())
    
    # 3 反向查询 使用 related_name
    # publish_obj = models.Publish.objects.filter(name='太白出版社').first()
    # print(publish_obj.xx.all())
    
    # 查询太白出版社出版了哪些书,及对应的作者名和作者地址
    objs  = models.Book.objects.filter(publish__name='太白出版社')
    lst = []
    for obj in objs:
        dic = {
            'title': obj.title,
            'author_info' : []
        }
        for author in obj.authors.all():
            ath = {
                'name': author.name,
                'addr': author.authorDetail.addr
            }
            dic['author_info'].append(ath)
        lst.append(dic)
    print(lst)
    
    基于双下划线的查询
    obj = models.Book.objects.filter(title='床头的故事').values('publish__name')
    print(obj)
    obj = models.Publish.objects.filter(book__title='床头的故事')
    print(obj.name)
    obj = models.Publish.objects.filter(xx__title='床头的故事')
    print(obj)
    
    obj = models.Publish.objects.filter(name='太白出版社').values('book__title', 'book__authors__name', 'book__authors__authorDetail__addr')
    print(obj)
    

    多对多

    # 方式1
    book_obj = models.Book.objects.get(id=4)
    # author_obj对应的id
    book_obj.authors.add(3, 4)
    # 方式2
    book_obj = models.Book.objects.get(id=5)
    author1 = models.Author.objects.get(id=1)
    author2 = models.Author.objects.get(id=2)
    book_obj.authors.add(author1,author2)
    

    # 方式1 remove(对应Author表的id字段)
    book_obj = models.Book.objects.get(id=6)
    book_obj.authors.remove(1)
    # 删除多个
    book_obj.authors.remove(3,5)
    
    # 方式2
    author = models.Author.objects.get(id=5)
    book_obj.authors.remove(author)
    book_obj.authors.clear()          # 删除所有
    book_obj.authors.set(['5','3'])   # 删除所有然后添加(更新)
    

    book_obj = models.Book.objects.get(id=6)
    book_obj.authors.set(['5','3'])   # 删除所有然后添加(更新)
    

    基于对象的查询
    # 1 正向查询
    book_obj = models.Book.objects.filter(title='床头的故事').first()
    print(book_obj.authors.all())
    
    # 2 反向查询
    author_obj = models.Author.objects.filter(name='alex').first()
    print(author_obj.book_set.all())
    
    基于双下划线的查询
    obj = models.Author.objects.filter(book__title='床头的故事')
    print(obj)
    
    obj = models.Book.objects.filter(title='床头的故事').values('authors__name')
    print(obj)
    
    obj = models.Book.objects.filter(authors__name='alex')
    print(obj)
    
    obj = models.Author.objects.filter(name='alex').values('book__title')
    print(obj)
    

    聚合、分组、F查询、Q查询

    from django.db.models import Avg, Max, Min, Sum, Count, F, Q
    

    聚合查询

    obj = models.Book.objects.all().aggregate(Avg('price'))
    print(obj)          # {'price__avg': Decimal('10.150000')}
    
    # 起别名,平均值
    obj = models.Book.objects.all().aggregate(a=Avg('price'))
    print(obj)          # {'a': Decimal('10.150000')}
    
    # 最大值
    obj = models.Book.objects.all().aggregate(Max('price'), Min('price'))
    print(obj)
    
    # 求和
    obj = models.Book.objects.all().aggregate(Sum('price'))
    print(obj)
    
    # 计数
    obj = models.Book.objects.all().aggregate(Count('id'))
    print(obj)
    

    分组查询

    #                                        分组条件               要统计的值
    obj = models.Book.objects.all().values('publish').annotate(Avg('price'))
    print(obj)
    
    obj = models.Publish.objects.annotate(Avg('book__price')).values()
    print(obj)
    
    ret = models.Book.objects.all().values('publish_id').annotate(Count('id'))
    print(ret)
    

    F 查询

    # 查询book表中点赞数大于评论数的书名
    obj = models.Book.objects.filter(good__gt=F('comment'))
    print(obj)
    
    # 支持4则运算
    obj = models.Book.objects.filter(good__gt=F('comment')*2)
    print(obj)
    
    # 让所有书籍价格+20
    models.Book.objects.all().update(price = F('price')+20)
    

    Q 查询

    # 查询点赞数小于80或者评论数大于80的书籍书籍
    ret = models.Book.objects.filter(~Q(good__gt=80)|Q(comment__gt=80))
    print(ret)
    # | 或, & 且 ~非
    
    # 方式2
    q_obj = Q()
    q_obj.connector='OR'
    q_obj.children.append(('good__gt', 80))
    q_obj.children.append(('comment__gt', 80))
    

    ORM执行原生SQL

    from django.db import connection
    
    
    ret = models.Publish.objects.raw('select * from app01_publish')
    for i in ret:
        print(i.name,i.city)
    
    cursor = connection.cursor()
    cursor.execute("select * from app01_book")
    ret = cursor.fetchall()
    print(ret)
    
    # 查看SQL语句
    print(connection.queries)
    
  • 相关阅读:
    vbox安装增强功能,实现宿主机文件夹共享并浏览器访问
    linux镜像下载
    linux命令之sed
    关于MySQL数据库的备份方案
    linux防火墙使用以及配置
    Jenkins安装部署(二)
    Jenkins安装部署(一)
    Centos7在虚拟机中扩展磁盘空间
    CentOS 7系统根目录分区扩容
    Linux下的SVN服务器搭建
  • 原文地址:https://www.cnblogs.com/xiasir/p/12960538.html
Copyright © 2011-2022 走看看