<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 第五節:外鍵和表關系 # 外鍵和表關系 ## 外鍵: 在`MySQL`中,表有兩種引擎,一種是`InnoDB`,另外一種是`myisam`。如果使用的是`InnoDB`引擎,是支持外鍵約束的。外鍵的存在使得`ORM`框架在處理表關系的時候異常的強大。因此這里我們首先來介紹下外鍵在`Django`中的使用。 類定義為`class ForeignKey(to,on_delete,**options)`。第一個參數是引用的是哪個模型,第二個參數是在使用外鍵引用的模型數據被刪除了,這個字段該如何處理,比如有`CASCADE`、`SET_NULL`等。這里以一個實際案例來說明。比如有一個`User`和一個`Article`兩個模型。一個`User`可以發表多篇文章,一個`Article`只能有一個`Author`,并且通過外鍵進行引用。那么相關的示例代碼如下: ``` <pre class="calibre12">``` <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span><span class="hljs-params">(models.Model)</span>:</span> username = models.CharField(max_length=<span class="hljs-params">20</span>) password = models.CharField(max_length=<span class="hljs-params">100</span>) <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Article</span><span class="hljs-params">(models.Model)</span>:</span> title = models.CharField(max_length=<span class="hljs-params">100</span>) content = models.TextField() author = models.ForeignKey(<span class="hljs-string">"User"</span>,on_delete=models.CASCADE) ``` ``` 以上使用`ForeignKey`來定義模型之間的關系。即在`article`的實例中可以通過`author`屬性來操作對應的`User`模型。這樣使用起來非常的方便。示例代碼如下: ``` <pre class="calibre12">``` article = Article(title=<span class="hljs-string">'abc'</span>,content=<span class="hljs-string">'123'</span>) author = User(username=<span class="hljs-string">'張三'</span>,password=<span class="hljs-string">'111111'</span>) article.author = author article.save() <span class="hljs-title"># 修改article.author上的值</span> article.author.username = <span class="hljs-string">'李四'</span> article.save() ``` ``` 為什么使用了`ForeignKey`后,就能通過`author`訪問到對應的`user`對象呢。因此在底層,`Django`為`Article`表添加了一個`屬性名_id`的字段(比如author的字段名稱是author\_id),這個字段是一個外鍵,記錄著對應的作者的主鍵。以后通過`article.author`訪問的時候,實際上是先通過`author_id`找到對應的數據,然后再提取`User`表中的這條數據,形成一個模型。 如果想要引用另外一個`app`的模型,那么應該在傳遞`to`參數的時候,使用`app.model_name`進行指定。以上例為例,如果`User`和`Article`不是在同一個`app`中,那么在引用的時候的示例代碼如下: ``` <pre class="calibre12">``` <span class="hljs-title"># User模型在user這個app中</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span><span class="hljs-params">(models.Model)</span>:</span> username = models.CharField(max_length=<span class="hljs-params">20</span>) password = models.CharField(max_length=<span class="hljs-params">100</span>) <span class="hljs-title"># Article模型在article這個app中</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Article</span><span class="hljs-params">(models.Model)</span>:</span> title = models.CharField(max_length=<span class="hljs-params">100</span>) content = models.TextField() author = models.ForeignKey(<span class="hljs-string">"user.User"</span>,on_delete=models.CASCADE) ``` ``` 如果模型的外鍵引用的是本身自己這個模型,那么`to`參數可以為`'self'`,或者是這個模型的名字。在論壇開發中,一般評論都可以進行二級評論,即可以針對另外一個評論進行評論,那么在定義模型的時候就需要使用外鍵來引用自身。示例代碼如下: ``` <pre class="calibre12">``` <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Comment</span><span class="hljs-params">(models.Model)</span>:</span> content = models.TextField() origin_comment = models.ForeignKey(<span class="hljs-string">'self'</span>,on_delete=models.CASCADE,null=<span class="hljs-keyword">True</span>) <span class="hljs-title"># 或者</span> <span class="hljs-title"># origin_comment = models.ForeignKey('Comment',on_delete=models.CASCADE,null=True)</span> ``` ``` ### 外鍵刪除操作: 如果一個模型使用了外鍵。那么在對方那個模型被刪掉后,該進行什么樣的操作。可以通過`on_delete`來指定。可以指定的類型如下: 1. `CASCADE`:級聯操作。如果外鍵對應的那條數據被刪除了,那么這條數據也會被刪除。 2. `PROTECT`:受保護。即只要這條數據引用了外鍵的那條數據,那么就不能刪除外鍵的那條數據。 3. `SET_NULL`:設置為空。如果外鍵的那條數據被刪除了,那么在本條數據上就將這個字段設置為空。如果設置這個選項,前提是要指定這個字段可以為空。 4. `SET_DEFAULT`:設置默認值。如果外鍵的那條數據被刪除了,那么本條數據上就將這個字段設置為默認值。如果設置這個選項,前提是要指定這個字段一個默認值。 5. `SET()`:如果外鍵的那條數據被刪除了。那么將會獲取`SET`函數中的值來作為這個外鍵的值。`SET`函數可以接收一個可以調用的對象(比如函數或者方法),如果是可以調用的對象,那么會將這個對象調用后的結果作為值返回回去。 6. `DO_NOTHING`:不采取任何行為。一切全看數據庫級別的約束。 **以上這些選項只是Django級別的,數據級別依舊是RESTRICT!** - - - - - - ## 表關系: 表之間的關系都是通過外鍵來進行關聯的。而表之間的關系,無非就是三種關系:一對一、一對多(多對一)、多對多等。以下將討論一下三種關系的應用場景及其實現方式。 ### 一對多: 1. 應用場景:比如文章和作者之間的關系。一個文章只能由一個作者編寫,但是一個作者可以寫多篇文章。文章和作者之間的關系就是典型的多對一的關系。 2. 實現方式:一對多或者多對一,都是通過`ForeignKey`來實現的。還是以文章和作者的案例進行講解。 ``` <pre class="calibre12">``` <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span><span class="hljs-params">(models.Model)</span>:</span> username = models.CharField(max_length=<span class="hljs-params">20</span>) password = models.CharField(max_length=<span class="hljs-params">100</span>) <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Article</span><span class="hljs-params">(models.Model)</span>:</span> title = models.CharField(max_length=<span class="hljs-params">100</span>) content = models.TextField() author = models.ForeignKey(<span class="hljs-string">"User"</span>,on_delete=models.CASCADE) ``` ``` 那么以后在給`Article`對象指定`author`,就可以使用以下代碼來完成: ``` <pre class="calibre12">``` article = Article(title=<span class="hljs-string">'abc'</span>,content=<span class="hljs-string">'123'</span>) author = User(username=<span class="hljs-string">'zhiliao'</span>,password=<span class="hljs-string">'111111'</span>) <span class="hljs-title"># 要先保存到數據庫中</span> author.save() article.author = author article.save() ``` ``` 并且以后如果想要獲取某個用戶下所有的文章,可以通過`article_set`來實現。示例代碼如下: ``` <pre class="calibre12">``` user = User.objects.first() <span class="hljs-title"># 獲取第一個用戶寫的所有文章</span> articles = user.article_set.all() <span class="hljs-keyword">for</span> article <span class="hljs-keyword">in</span> articles: print(article) ``` ``` ### 一對一: 1. 應用場景:比如一個用戶表和一個用戶信息表。在實際網站中,可能需要保存用戶的許多信息,但是有些信息是不經常用的。如果把所有信息都存放到一張表中可能會影響查詢效率,因此可以把用戶的一些不常用的信息存放到另外一張表中我們叫做`UserExtension`。但是用戶表`User`和用戶信息表`UserExtension`就是典型的一對一了。 2. 實現方式:`Django`為一對一提供了一個專門的`Field`叫做`OneToOneField`來實現一對一操作。示例代碼如下: ``` <pre class="calibre12">``` <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span><span class="hljs-params">(models.Model)</span>:</span> username = models.CharField(max_length=<span class="hljs-params">20</span>) password = models.CharField(max_length=<span class="hljs-params">100</span>) <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserExtension</span><span class="hljs-params">(models.Model)</span>:</span> birthday = models.DateTimeField(null=<span class="hljs-keyword">True</span>) school = models.CharField(blank=<span class="hljs-keyword">True</span>,max_length=<span class="hljs-params">50</span>) user = models.OneToOneField(<span class="hljs-string">"User"</span>, on_delete=models.CASCADE) ``` ``` 在`UserExtension`模型上增加了一個一對一的關系映射。其實底層是在`UserExtension`這個表上增加了一個`user_id`,來和`user`表進行關聯,并且這個外鍵數據在表中必須是唯一的,來保證一對一。 ### 多對多: 1. 應用場景:比如文章和標簽的關系。一篇文章可以有多個標簽,一個標簽可以被多個文章所引用。因此標簽和文章的關系是典型的多對多的關系。 2. 實現方式:`Django`為這種多對多的實現提供了專門的`Field`。叫做`ManyToManyField`。還是拿文章和標簽為例進行講解。示例代碼如下: ``` <pre class="calibre12">``` <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Article</span><span class="hljs-params">(models.Model)</span>:</span> title = models.CharField(max_length=<span class="hljs-params">100</span>) content = models.TextField() tags = models.ManyToManyField(<span class="hljs-string">"Tag"</span>,related_name=<span class="hljs-string">"articles"</span>) <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Tag</span><span class="hljs-params">(models.Model)</span>:</span> name = models.CharField(max_length=<span class="hljs-params">50</span>) ``` ``` 在數據庫層面,實際上`Django`是為這種多對多的關系建立了一個中間表。這個中間表分別定義了兩個外鍵,引用到`article`和`tag`兩張表的主鍵。 - - - - - - ### related\_name和related\_query\_name: #### related\_name: 還是以`User`和`Article`為例來進行說明。如果一個`article`想要訪問對應的作者,那么可以通過`author`來進行訪問。但是如果有一個`user`對象,想要通過這個`user`對象獲取所有的文章,該如何做呢?這時候可以通過`user.article_set`來訪問,這個名字的規律是`模型名字小寫_set`。示例代碼如下: ``` <pre class="calibre12">``` user = User.objects.get(name=<span class="hljs-string">'張三'</span>) user.article_set.all() ``` ``` 如果不想使用`模型名字小寫_set`的方式,想要使用其他的名字,那么可以在定義模型的時候指定`related_name`。示例代碼如下: ``` <pre class="calibre12">``` <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Article</span><span class="hljs-params">(models.Model)</span>:</span> title = models.CharField(max_length=<span class="hljs-params">100</span>) content = models.TextField() <span class="hljs-title"># 傳遞related_name參數,以后在方向引用的時候使用articles進行訪問</span> author = models.ForeignKey(<span class="hljs-string">"User"</span>,on_delete=models.SET_NULL,null=<span class="hljs-keyword">True</span>,related_name=<span class="hljs-string">'articles'</span>) ``` ``` 以后在方向引用的時候。使用`articles`可以訪問到這個作者的文章模型。示例代碼如下: ``` <pre class="calibre12">``` user = User.objects.get(name=<span class="hljs-string">'張三'</span>) user.articles.all() ``` ``` 如果不想使用反向引用,那么可以指定`related_name='+'`。示例代碼如下: ``` <pre class="calibre12">``` <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Article</span><span class="hljs-params">(models.Model)</span>:</span> title = models.CharField(max_length=<span class="hljs-params">100</span>) content = models.TextField() <span class="hljs-title"># 傳遞related_name參數,以后在方向引用的時候使用articles進行訪問</span> author = models.ForeignKey(<span class="hljs-string">"User"</span>,on_delete=models.SET_NULL,null=<span class="hljs-keyword">True</span>,related_name=<span class="hljs-string">'+'</span>) ``` ``` 以后將不能通過`user.article_set`來訪問文章模型了。 #### related\_query\_name: 在查找數據的時候,可以使用`filter`進行過濾。使用`filter`過濾的時候,不僅僅可以指定本模型上的某個屬性要滿足什么條件,還可以指定相關聯的模型滿足什么屬性。比如現在想要獲取寫過標題為`abc`的所有用戶,那么可以這樣寫: ``` <pre class="calibre12">``` users = User.objects.filter(article__title=<span class="hljs-string">'abc'</span>) ``` ``` 如果你設置了`related_name`為`articles`,因為反轉的過濾器的名字將使用`related_name`的名字,那么上例代碼將改成如下: ``` <pre class="calibre12">``` users = User.objects.filter(articles__title=<span class="hljs-string">'abc'</span>) ``` ``` 可以通過`related_query_name`將查詢的反轉名字修改成其他的名字。比如`article`。示例代碼如下: ``` <pre class="calibre12">``` <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Article</span><span class="hljs-params">(models.Model)</span>:</span> title = models.CharField(max_length=<span class="hljs-params">100</span>) content = models.TextField() <span class="hljs-title"># 傳遞related_name參數,以后在方向引用的時候使用articles進行訪問</span> author = models.ForeignKey(<span class="hljs-string">"User"</span>,on_delete=models.SET_NULL,null=<span class="hljs-keyword">True</span>,related_name=<span class="hljs-string">'articles'</span>,related_query_name=<span class="hljs-string">'article'</span>) ``` ``` 那么在做反向過濾查找的時候就可以使用以下代碼: ``` <pre class="calibre12">``` users = User.objects.filter(article__title=<span class="hljs-string">'abc'</span>) ``` ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看