1. 程式人生 > >ORM關於表那些事

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了,因為ManyToManyField會預設幫你在外來鍵後面加_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)