• ORM关于表那些事


    复制代码
    一、. ORM表和表之间的关系
        1、 一对多           --> 外键(ForeignKey)
        
        2、 多对多           --> 另外一张关系表(ManyToManyField)
            1. 三种方式
                1. 自己建立第三张关系表,外键分别关联两个表
                    1. 优点
                        1. 可以扩充第三张关系标的字段
                    2. 缺点
                        1. 自己做连表查询
                    3. 建表例子
                        class Book(models.Model):
                            title = models.CharField(max_length=12)
    
    
                        class Author(models.Model):
                            name = models.CharField(max_length=12)
    
    
                        # 1. 多对多第一种创建方式:自己创建第三张关系表
                        class Author2Book(models.Model):
                            id = models.AutoField(primary_key=True)
                            author_id = models.ForeignKey(to='Author')
                            book_id = models.ForeignKey(to='Book')
                            price = models.IntegerField()  # 可以自己扩充需要的字段
    
                2. 通过ORM内置的ManyToManyField,自动创建第三张关系表
                    1. 优点
                        1. 提供了很多连表操作的快捷方法--> all(), add(), set(), clear(), remove()
                    2. 缺点
                        1. 无法扩展第三张关系表
                    3. 建表例子
                        class Book(models.Model):
                            title = models.CharField(max_length=12)
    
    
                        class Author(models.Model):
                            name = models.CharField(max_length=12)
                            books = models.ManyToManyField(to='Book')  # 字段就这些,无法扩充其他字段
                
                3. 自己创建第三张关系表,通过ManyToManyField关联
                    1. 优点:
                        1. 既能够使用多对多查询的快捷方法all()(只能用all,不能使用add,set等),还能够自己扩展第三张关系表的字段
                    2. 建表例子
                        class Book(models.Model):
                            title = models.CharField(max_length=12)
    
    
                        class Author(models.Model):
                            name = models.CharField(max_length=12)
                            # 告诉ManyToManyField通过(through)Author2Book这张表进行关联,不使用ORM自动创建的第三张表,而是使用我自己创建的表
                            # through_fields告诉ORM通过哪几个字段进行多对多关联
                            books = models.ManyToManyField(to='Book', through='Author2Book', through_fields=('author', 'book'))
    
    
                        # 1. 多对多第三种创建方式:自己创建第三张关系表,此时外键不需要添加_id了,因为ORM会默认帮你在外键后面加_id
                        class Author2Book(models.Model):
                            id = models.AutoField(primary_key=True)
                            author = models.ForeignKey(to='Author')
                            book = models.ForeignKey(to='Book')
                            price = models.IntegerField(null=True)
    
                            # author_id和book_id要联合唯一
                            class Meta:
                                unique_together = (('author', 'book'),)
                        3. 操作例子
                            # 多对多的第三张方式也支持all查询
                            author_obj = Author.objects.first()
                            # 第一个作者的所有书籍
                            ret = author_obj.books.all()
    
                            # 给第一个作者添加一本书
                            # author_obj.books.add(4) # 报错
                            Author2Book.objects.create(author_id=1, book_id=4)
    
    
            2. 以后该用哪种?
                1. 当第三张关系表中不需要其他额外字段的时候,我们就用默认ManyToManyField就可以了
                2. 当第三张关系表中需要额外的字段时,我们就要用第三种方式,自己建立第三张关系表并且用ManyToManyField关联
            
            
        3、 一对一           --> OneToOneField    
            0. 用法和外键一样
            1. 当一张表里的字段非常多,并且某几个字段的查询频率远远大于其他字段的时候
            2. 把常用字段单独拆成一张表,查询的时候更快捷!
            3. 当两张表建立了一对一关系后,就不能再关联其他表了
            4. 建表例子
                class Author(models.Model):
                    name = models.CharField(max_length=12)  # 姓名
                    gender = models.SmallIntegerField(choices=((1, ''), (2, ''), (3, '保密')), default=3)  # 性别
                    phone = models.CharField(max_length=11, unique=True)  # 手机
                    email = models.EmailField()  # 邮箱
                    info = models.OneToOneField(to='AuthorInfo')  # 详细信息,一对一
    
    
                # 作者详细信息表
                class AuthorInfo(models.Model):
                    birthday = models.DateTimeField()  # 生日
                    city = models.CharField(max_length=12)  # 住址
                    is_marry = models.BooleanField()  # 婚否
                    income = models.BigIntegerField()  # 收入
    
            5. 查询例子
                    # 一对一查询,查询第一个作者的住址
                    author_obj = Author.objects.first()
                    ret = author_obj.info.city
    
    
    二、 ORM关联查询
    
    1、 基于对象的查询
        0. 建表
            class Publisher(models.Model):
                id = models.AutoField(primary_key=True)
                name = models.CharField(max_length=20)
                addr = models.TextField()
                date = models.DateField()  # 成立日期
    
                def __str__(self):
                    return self.name
    
    
            class Book(models.Model):
                id = models.AutoField(primary_key=True)
                title = models.CharField(max_length=20)
                price = models.DecimalField(max_digits=6, decimal_places=2)
                isbn = models.CharField(max_length=20, unique=True)  # 书籍的唯一编号
                publisher = models.ForeignKey(to='Publisher', on_delete=models.CASCADE)
    
                def __str__(self):
                    return self.title
    
    
            class Author(models.Model):
                name = models.CharField(max_length=12)  # 姓名
                gender = models.SmallIntegerField(choices=((1, ''), (2, ''), (3, '保密')), default=3)  # 性别
                phone = models.CharField(max_length=11, unique=True)  # 手机
                email = models.EmailField()  # 邮箱
                books = models.ManyToManyField(to='Book')  # 作品
                info = models.OneToOneField(to='AuthorInfo')  # 详细信息
    
    
            # 作者详细信息表
            class AuthorInfo(models.Model):
                birthday = models.DateTimeField()  # 生日
                city = models.CharField(max_length=12)  # 住址
                is_marry = models.BooleanField()  # 婚否
                income = models.BigIntegerField()  # 收入
        
        1. 正向查
            对象.关联字段.属性
                    # 查询第一本书关联的出版社名称
                    book_obj = Book.objects.first()
                    ret = book_obj.publisher.name
                    print(ret)
    
        2. 反向查
            1. 默认不设置related_name属性
                1. 查找的对象是多个的时候(一对多或多对多时)
                    publisher_obj.book_set.all()
    
                2. 查找的对象时一个的时候(一对一)
                    author_info_obj.author.name
    
                3. 例如
                    # 一对多查询(需要给反向查询的表加_set)
                    # 查询第一本书关联的出版社名称(正向查)
                    book_obj = Book.objects.first()
                    ret = book_obj.publisher.name
                    print(ret)
    
                    # 查询明哥出版社出版的所有书(反向查)
                    publisher_obj = Publisher.objects.get(name='明哥出版社')
                    # 反向查找(多个) .表名_set
                    ret = publisher_obj.book_set.all()
                    print(ret)
    
                    # 一对一查询(不需要给反向查询的表加_set)
                    # 查询id=1的作者婚否(正向查)
                    author_obj = Author.objects.first()
                    ret = author_obj.info.is_marry
                    print(ret)
    
                    # 查找住在深圳的那个作者姓名(反向查)
                    authorinfo_obj = AuthorInfo.objects.get(city='深圳')
                    ret = authorinfo_obj.author.name
                    print(ret)
    
    
            2. 设置related_name='books'属性(publisher = models.ForeignKey(to='Publisher', related_name='books'))
                # 查询明哥出版社出版的所有书
                publisher_obj = Publisher.objects.get(name='明哥出版社')
                publisher_obj.books.all()
    
    2、 基于QuerySet的查询(__表示跨表查询)
        1. 正向查
            Book.objects.filter(id=1).values_list('publisher__name')
    
        2. 反向查
            1. 默认不设置related_name属性,默认就用类名的小写
                Publisher.objects.filter(id=1).values_list('book__price')
            2. 设置related_name='books'属性
                Publisher.objects.filter(id=1).values_list('books__price')
        3. related_query_name = 'hello'
            在关联的字段参数设置了related_query_name = 'hello'后,反向查找就不需要使用表名,而是直接使用"hello"
    
        3. 例子
        # 热身:普通的values的使用
        # 查询第一本书的名称
        ret = Book.objects.filter(id=1).values('title')
        print(ret)
    
        # 使用:外键基于QuerySet跨表查询
        # 查询第一本书关联的出版社名称(__表示跨表查询)(正向查找)
        # valuse('publisher')表示通过外键找到了publisher表,__表示跨表取到publisher表的字段的值
        ret = Book.objects.filter(id=1).values('publisher__name')  
        print(ret)
    
        # 反向查找
        # 查询id=1的出版社的所有书的名称和价格
        ret = Publisher.objects.filter(id=1).values_list('book__title', 'book__price')
        print(ret)
    
        # 一对一基于QuerySet跨表查询
        # 查询id=1的作者婚否(正向查找)
        ret = Author.objects.filter(id=1).values('info__is_marry')
        print(ret)
    
        # 查找住在深圳的作者的姓名(反向查找)
        ret = AuthorInfo.objects.filter(city='深圳').values('author__name')
        print(ret)
    
         # 多对多基于QuerySet跨表查询
        # 查询id=1的作者关联的所有数据的名称和价格(正向查找)
        ret = Author.objects.filter(id=1).values('books__title', 'books__price')
        print(ret)
    
        # 查找id=1的作者的名字(反向查找)
        ret = Book.objects.filter(id=1).values('author__name')
        print(ret)
    
        # 链式查询
        # 查找id=1的书的作者的城市
        ret = Book.objects.filter(id=1).values('author__info__city')
        print(ret)
    复制代码
  • 相关阅读:
    19.2.15 [LeetCode 80] Remove Duplicates from Sorted Array II
    19.2.15 [LeetCode 79] Word Search
    19.2.15 [LeetCode 78] Subsets
    19.2.15 [LeetCode 77] Combinations
    19.2.15 [LeetCode 76] Minimum Window Substring
    19.2.13 [LeetCode 75] Sort Colors
    19.2.13 [LeetCode 74] Search a 2D Matrix
    19.2.13 [LeetCode 73] Set Matrix Zeroes
    19.2.13 [LeetCode 72] Edit Distance
    19.2.13 [LeetCode 71] Simplify Path
  • 原文地址:https://www.cnblogs.com/yidashi110/p/10091975.html
Copyright © 2020-2023  润新知