# 第七節:查詢操作
# 查詢操作
查找是數據庫操作中一個非常重要的技術。查詢一般就是使用`filter`、`exclude`以及`get`三個方法來實現。我們可以在調用這些方法的時候傳遞不同的參數來實現查詢需求。在`ORM`層面,這些查詢條件都是使用`field`+`__`+`condition`的方式來使用的。以下將那些常用的查詢條件來一一解釋。
## 查詢條件
### exact:
使用精確的`=`進行查找。如果提供的是一個`None`,那么在`SQL`層面就是被解釋為`NULL`。示例代碼如下:
```
<pre class="calibre12">```
article = Article.objects.get(id__exact=<span class="hljs-params">14</span>)
article = Article.objects.get(id__exact=<span class="hljs-keyword">None</span>)
```
```
以上的兩個查找在翻譯為`SQL`語句為如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">select</span> ... <span class="hljs-keyword">from</span> article <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span>=<span class="hljs-params">14</span>;
<span class="hljs-keyword">select</span> ... <span class="hljs-keyword">from</span> article <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> <span class="hljs-keyword">IS</span> <span class="hljs-params">NULL</span>;
```
```
### iexact:
使用`like`進行查找。示例代碼如下:
```
<pre class="calibre12">```
article = Article.objects.filter(title__iexact='hello world')
```
```
那么以上的查詢就等價于以下的`SQL`語句:
```
<pre class="calibre12">```
<span class="hljs-keyword">select</span> ... <span class="hljs-keyword">from</span> article <span class="hljs-keyword">where</span> title <span class="hljs-keyword">like</span> <span class="hljs-string">'hello world'</span>;
```
```
注意上面這個`sql`語句,因為在`MySQL`中,沒有一個叫做`ilike`的。所以`exact`和`iexact`的區別實際上就是`LIKE`和`=`的區別,在大部分`collation=utf8_general_ci`情況下都是一樣的(`collation`是用來對字符串比較的)。
### contains:
大小寫敏感,判斷某個字段是否包含了某個數據。示例代碼如下:
```
<pre class="calibre12">```
articles = Article.objects.filter(title__contains=<span class="hljs-string">'hello'</span>)
```
```
在翻譯成`SQL`語句為如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">select</span> ... <span class="hljs-keyword">where</span> title <span class="hljs-keyword">like</span> <span class="hljs-params">binary</span> <span class="hljs-string">'%hello%'</span>;
```
```
要注意的是,在使用`contains`的時候,翻譯成的`sql`語句左右兩邊是有百分號的,意味著使用的是模糊查詢。而`exact`翻譯成`sql`語句左右兩邊是沒有百分號的,意味著使用的是精確的查詢。
### icontains:
大小寫不敏感的匹配查詢。示例代碼如下:
```
<pre class="calibre12">```
articles = Article.objects.filter(title__icontains=<span class="hljs-string">'hello'</span>)
```
```
在翻譯成`SQL`語句為如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">select</span> ... <span class="hljs-keyword">where</span> title <span class="hljs-keyword">like</span> <span class="hljs-string">'%hello%'</span>;
```
```
### in:
提取那些給定的`field`的值是否在給定的容器中。容器可以為`list`、`tuple`或者任何一個可以迭代的對象,包括`QuerySet`對象。示例代碼如下:
```
<pre class="calibre12">```
articles = Article.objects.filter(id__in=[<span class="hljs-params">1</span>,<span class="hljs-params">2</span>,<span class="hljs-params">3</span>])
```
```
以上代碼在翻譯成`SQL`語句為如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">select</span> ... <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> <span class="hljs-keyword">in</span> (<span class="hljs-params">1</span>,<span class="hljs-params">3</span>,<span class="hljs-params">4</span>)
```
```
當然也可以傳遞一個`QuerySet`對象進去。示例代碼如下:
```
<pre class="calibre12">```
inner_qs = Article.objects.filter(title__contains=<span class="hljs-string">'hello'</span>)
categories = Category.objects.filter(article__in=inner_qs)
```
```
以上代碼的意思是獲取那些文章標題包含`hello`的所有分類。
將翻譯成以下`SQL`語句,示例代碼如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">select</span> ...<span class="hljs-keyword">from</span> <span class="hljs-keyword">category</span> <span class="hljs-keyword">where</span> article.<span class="hljs-keyword">id</span> <span class="hljs-keyword">in</span> (<span class="hljs-keyword">select</span> <span class="hljs-keyword">id</span> <span class="hljs-keyword">from</span> article <span class="hljs-keyword">where</span> title <span class="hljs-keyword">like</span> <span class="hljs-string">'%hello%'</span>);
```
```
### gt:
某個`field`的值要大于給定的值。示例代碼如下:
```
<pre class="calibre12">```
articles = Article.objects.filter(id__gt=<span class="hljs-params">4</span>)
```
```
以上代碼的意思是將所有`id`大于4的文章全部都找出來。
將翻譯成以下`SQL`語句:
```
<pre class="calibre12">```
<span class="hljs-keyword">select</span> ... <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> > <span class="hljs-params">4</span>;
```
```
### gte:
類似于`gt`,是大于等于。
### lt:
類似于`gt`是小于。
### lte:
類似于`lt`,是小于等于。
### startswith:
判斷某個字段的值是否是以某個值開始的。大小寫敏感。示例代碼如下:
```
<pre class="calibre12">```
articles = Article.objects.filter(title__startswith=<span class="hljs-string">'hello'</span>)
```
```
以上代碼的意思是提取所有標題以`hello`字符串開頭的文章。
將翻譯成以下`SQL`語句:
```
<pre class="calibre12">```
<span class="hljs-keyword">select</span> ... <span class="hljs-keyword">where</span> title <span class="hljs-keyword">like</span> <span class="hljs-string">'hello%'</span>
```
```
### istartswith:
類似于`startswith`,但是大小寫是不敏感的。
### endswith:
判斷某個字段的值是否以某個值結束。大小寫敏感。示例代碼如下:
```
<pre class="calibre12">```
articles = Article.objects.filter(title__endswith=<span class="hljs-string">'world'</span>)
```
```
以上代碼的意思是提取所有標題以`world`結尾的文章。
將翻譯成以下`SQL`語句:
```
<pre class="calibre12">```
<span class="hljs-keyword">select</span> ... <span class="hljs-keyword">where</span> title <span class="hljs-keyword">like</span> <span class="hljs-string">'%world'</span>;
```
```
### iendswith:
類似于`endswith`,只不過大小寫不敏感。
### range:
判斷某個`field`的值是否在給定的區間中。示例代碼如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.utils.timezone <span class="hljs-keyword">import</span> make_aware
<span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime
start_date = make_aware(datetime(year=<span class="hljs-params">2018</span>,month=<span class="hljs-params">1</span>,day=<span class="hljs-params">1</span>))
end_date = make_aware(datetime(year=<span class="hljs-params">2018</span>,month=<span class="hljs-params">3</span>,day=<span class="hljs-params">29</span>,hour=<span class="hljs-params">16</span>))
articles = Article.objects.filter(pub_date__range=(start_date,end_date))
```
```
以上代碼的意思是提取所有發布時間在`2018/1/1`到`2018/12/12`之間的文章。
將翻譯成以下的`SQL`語句:
```
<pre class="calibre12">```
<span class="hljs-keyword">select</span> ... <span class="hljs-keyword">from</span> article <span class="hljs-keyword">where</span> pub_time <span class="hljs-keyword">between</span> <span class="hljs-string">'2018-01-01'</span> <span class="hljs-keyword">and</span> <span class="hljs-string">'2018-12-12'</span>。
```
```
需要注意的是,以上提取數據,不會包含最后一個值。也就是不會包含`2018/12/12`的文章。
而且另外一個重點,因為我們在`settings.py`中指定了`USE_TZ=True`,并且設置了`TIME_ZONE='Asia/Shanghai'`,因此我們在提取數據的時候要使用`django.utils.timezone.make_aware`先將`datetime.datetime`從`navie`時間轉換為`aware`時間。`make_aware`會將指定的時間轉換為`TIME_ZONE`中指定的時區的時間。
### date:
針對某些`date`或者`datetime`類型的字段。可以指定`date`的范圍。并且這個時間過濾,還可以使用鏈式調用。示例代碼如下:
```
<pre class="calibre12">```
articles = Article.objects.filter(pub_date__date=date(<span class="hljs-params">2018</span>,<span class="hljs-params">3</span>,<span class="hljs-params">29</span>))
```
```
以上代碼的意思是查找時間為`2018/3/29`這一天發表的所有文章。
將翻譯成以下的`sql`語句:
```
<pre class="calibre12">```
<span class="hljs-keyword">select</span> ... <span class="hljs-keyword">WHERE</span> <span class="hljs-params">DATE</span>(<span class="hljs-keyword">CONVERT_TZ</span>(<span class="hljs-string">`front_article`</span>.<span class="hljs-string">`pub_date`</span>, <span class="hljs-string">'UTC'</span>, <span class="hljs-string">'Asia/Shanghai'</span>)) = <span class="hljs-params">2018</span><span class="hljs-params">-03</span><span class="hljs-params">-29</span>
```
```
注意,因為默認情況下`MySQL`的表中是沒有存儲時區相關的信息的。因此我們需要下載一些時區表的文件,然后添加到`Mysql`的配置路徑中。如果你用的是`windows`操作系統。那么在`http://dev.mysql.com/downloads/timezones.html`下載`timezone_2018d_posix.zip - POSIX standard`。然后將下載下來的所有文件拷貝到`C:\ProgramData\MySQL\MySQL Server 5.7\Data\mysql`中,如果提示文件名重復,那么選擇覆蓋即可。
如果用的是`linux`或者`mac`系統,那么在命令行中執行以下命令:`mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -D mysql -u root -p`,然后輸入密碼,從系統中加載時區文件更新到`mysql`中。
### year:
根據年份進行查找。示例代碼如下:
```
<pre class="calibre12">```
articles = Article.objects.filter(pub_date__year=<span class="hljs-params">2018</span>)
articles = Article.objects.filter(pub_date__year__gte=<span class="hljs-params">2017</span>)
```
```
以上的代碼在翻譯成`SQL`語句為如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">select</span> ... <span class="hljs-keyword">where</span> pub_date <span class="hljs-keyword">between</span> <span class="hljs-string">'2018-01-01'</span> <span class="hljs-keyword">and</span> <span class="hljs-string">'2018-12-31'</span>;
<span class="hljs-keyword">select</span> ... <span class="hljs-keyword">where</span> pub_date >= <span class="hljs-string">'2017-01-01'</span>;
```
```
### month:
同`year`,根據月份進行查找。
### day:
同`year`,根據日期進行查找。
## week\_day:
`Django 1.11`新增的查找方式。同`year`,根據星期幾進行查找。1表示星期天,7表示星期六,`2-6`代表的是星期一到星期五。
### time:
根據時間進行查找。示例代碼如下:
```
<pre class="calibre12">```
articles = Article.objects.filter(pub_date__time=datetime.time(<span class="hljs-params">12</span>,<span class="hljs-params">12</span>,<span class="hljs-params">12</span>));
```
```
以上的代碼是獲取每一天中12點12分12秒發表的所有文章。
更多的關于時間的過濾,請參考`Django`官方文檔:`https://docs.djangoproject.com/en/2.0/ref/models/querysets/#range`。
### isnull:
根據值是否為空進行查找。示例代碼如下:
```
<pre class="calibre12">```
articles = Article.objects.filter(pub_date__isnull=<span class="hljs-keyword">False</span>)
```
```
以上的代碼的意思是獲取所有發布日期不為空的文章。
將來翻譯成`SQL`語句如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">select</span> ... <span class="hljs-keyword">where</span> pub_date <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-params">null</span>;
```
```
### regex和iregex:
大小寫敏感和大小寫不敏感的正則表達式。示例代碼如下:
```
<pre class="calibre12">```
articles = Article.objects.filter(title__regex=<span class="hljs-string">r'^hello'</span>)
```
```
以上代碼的意思是提取所有標題以`hello`字符串開頭的文章。
將翻譯成以下的`SQL`語句:
```
<pre class="calibre12">```
<span class="hljs-keyword">select</span> ... <span class="hljs-keyword">where</span> title regexp <span class="hljs-params">binary</span> <span class="hljs-string">'^hello'</span>;
```
```
`iregex`是大小寫不敏感的。
### 根據關聯的表進行查詢:
假如現在有兩個`ORM`模型,一個是`Article`,一個是`Category`。代碼如下:
```
<pre class="calibre12">```
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Category</span><span class="hljs-params">(models.Model)</span>:</span>
<span class="hljs-string">"""文章分類表"""</span>
name = 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>
<span class="hljs-string">"""文章表"""</span>
title = models.CharField(max_length=<span class="hljs-params">100</span>,null=<span class="hljs-keyword">True</span>)
category = models.ForeignKey(<span class="hljs-string">"Category"</span>,on_delete=models.CASCADE)
```
```
比如想要獲取文章標題中包含"hello"的所有的分類。那么可以通過以下代碼來實現:
```
<pre class="calibre12">```
categories = Category.object.filter(article__title__contains(<span class="hljs-string">"hello"</span>))
```
```
- - - - - -
## 聚合函數:
如果你用原生`SQL`,則可以使用聚合函數來提取數據。比如提取某個商品銷售的數量,那么可以使用`Count`,如果想要知道商品銷售的平均價格,那么可以使用`Avg`。
聚合函數是通過`aggregate`方法來實現的。在講解這些聚合函數的用法的時候,都是基于以下的模型對象來實現的。
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Author</span><span class="hljs-params">(models.Model)</span>:</span>
<span class="hljs-string">"""作者模型"""</span>
name = models.CharField(max_length=<span class="hljs-params">100</span>)
age = models.IntegerField()
email = models.EmailField()
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
db_table = <span class="hljs-string">'author'</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Publisher</span><span class="hljs-params">(models.Model)</span>:</span>
<span class="hljs-string">"""出版社模型"""</span>
name = models.CharField(max_length=<span class="hljs-params">300</span>)
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
db_table = <span class="hljs-string">'publisher'</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book</span><span class="hljs-params">(models.Model)</span>:</span>
<span class="hljs-string">"""圖書模型"""</span>
name = models.CharField(max_length=<span class="hljs-params">300</span>)
pages = models.IntegerField()
price = models.FloatField()
rating = models.FloatField()
author = models.ForeignKey(Author,on_delete=models.CASCADE)
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
db_table = <span class="hljs-string">'book'</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BookOrder</span><span class="hljs-params">(models.Model)</span>:</span>
<span class="hljs-string">"""圖書訂單模型"""</span>
book = models.ForeignKey(<span class="hljs-string">"Book"</span>,on_delete=models.CASCADE)
price = models.FloatField()
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
db_table = <span class="hljs-string">'book_order'</span>
```
```
1. `Avg`:求平均值。比如想要獲取所有圖書的價格平均值。那么可以使用以下代碼實現。
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.db.models <span class="hljs-keyword">import</span> Avg
result = Book.objects.aggregate(Avg(<span class="hljs-string">'price'</span>))
print(result)
```
```
以上的打印結果是:
```
<pre class="calibre12">```
{"price__avg":23.0}
```
```
其中`price__avg`的結構是根據`field__avg`規則構成的。如果想要修改默認的名字,那么可以將`Avg`賦值給一個關鍵字參數。示例代碼如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.db.models <span class="hljs-keyword">import</span> Avg
result = Book.objects.aggregate(my_avg=Avg(<span class="hljs-string">'price'</span>))
print(result)
```
```
那么以上的結果打印為:
```
<pre class="calibre12">```
{"my_avg":23}
```
```
2. `Count`:獲取指定的對象的個數。示例代碼如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.db.models <span class="hljs-keyword">import</span> Count
result = Book.objects.aggregate(book_num=Count(<span class="hljs-string">'id'</span>))
```
```
以上的`result`將返回`Book`表中總共有多少本圖書。
`Count`類中,還有另外一個參數叫做`distinct`,默認是等于`False`,如果是等于`True`,那么將去掉那些重復的值。比如要獲取作者表中所有的不重復的郵箱總共有多少個,那么可以通過以下代碼來實現:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> djang.db.models <span class="hljs-keyword">import</span> Count
result = Author.objects.aggregate(count=Count(<span class="hljs-string">'email'</span>,distinct=<span class="hljs-keyword">True</span>))
```
```
3. `Max`和`Min`:獲取指定對象的最大值和最小值。比如想要獲取`Author`表中,最大的年齡和最小的年齡分別是多少。那么可以通過以下代碼來實現:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.db.models <span class="hljs-keyword">import</span> Max,Min
result = Author.objects.aggregate(Max(<span class="hljs-string">'age'</span>),Min(<span class="hljs-string">'age'</span>))
```
```
如果最大的年齡是88,最小的年齡是18。那么以上的result將為:
```
<pre class="calibre12">```
{"age__max":88,"age__min":18}
```
```
4. `Sum`:求指定對象的總和。比如要求圖書的銷售總額。那么可以使用以下代碼實現:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> djang.db.models <span class="hljs-keyword">import</span> Sum
result = Book.objects.annotate(total=Sum(<span class="hljs-string">"bookstore__price"</span>)).values(<span class="hljs-string">"name"</span>,<span class="hljs-string">"total"</span>)
```
```
以上的代碼`annotate`的意思是給`Book`表在查詢的時候添加一個字段叫做`total`,這個字段的數據來源是從`BookStore`模型的`price`的總和而來。`values`方法是只提取`name`和`total`兩個字段的值。
更多的聚合函數請參考官方文檔:<https://docs.djangoproject.com/en/2.0/ref/models/querysets/#aggregation-functions>
## aggregate和annotate的區別:
1. `aggregate`:返回使用聚合函數后的字段和值。
2. `annotate`:在原來模型字段的基礎之上添加一個使用了聚合函數的字段,并且在使用聚合函數的時候,會使用當前這個模型的主鍵進行分組(group by)。
比如以上`Sum`的例子,如果使用的是`annotate`,那么將在每條圖書的數據上都添加一個字段叫做`total`,計算這本書的銷售總額。
而如果使用的是`aggregate`,那么將求所有圖書的銷售總額。
## F表達式和Q表達式:
### F表達式:
`F表達式`是用來優化`ORM`操作數據庫的。比如我們要將公司所有員工的薪水都增加1000元,如果按照正常的流程,應該是先從數據庫中提取所有的員工工資到Python內存中,然后使用Python代碼在員工工資的基礎之上增加1000元,最后再保存到數據庫中。這里面涉及的流程就是,首先從數據庫中提取數據到Python內存中,然后在Python內存中做完運算,之后再保存到數據庫中。示例代碼如下:
```
<pre class="calibre12">```
employees = Employee.objects.all()
<span class="hljs-keyword">for</span> employee <span class="hljs-keyword">in</span> employees:
employee.salary += <span class="hljs-params">1000</span>
employee.save()
```
```
而我們的`F表達式`就可以優化這個流程,他可以不需要先把數據從數據庫中提取出來,計算完成后再保存回去,他可以直接執行`SQL語句`,就將員工的工資增加1000元。示例代碼如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> djang.db.models <span class="hljs-keyword">import</span> F
Employee.object.update(salary=F(<span class="hljs-string">"salary"</span>)+<span class="hljs-params">1000</span>)
```
```
`F表達式`并不會馬上從數據庫中獲取數據,而是在生成`SQL`語句的時候,動態的獲取傳給`F表達式`的值。
比如如果想要獲取作者中,`name`和`email`相同的作者數據。如果不使用`F表達式`,那么需要使用以下代碼來完成:
```
<pre class="calibre12">```
authors = Author.objects.all()
<span class="hljs-keyword">for</span> author <span class="hljs-keyword">in</span> authors:
<span class="hljs-keyword">if</span> author.name == author.email:
print(author)
```
```
如果使用`F表達式`,那么一行代碼就可以搞定。示例代碼如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.db.models <span class="hljs-keyword">import</span> F
authors = Author.objects.filter(name=F(<span class="hljs-string">"email"</span>))
```
```
### Q表達式:
如果想要實現所有價格高于100元,并且評分達到9.0以上評分的圖書。那么可以通過以下代碼來實現:
```
<pre class="calibre12">```
books = Book.objects.filter(price__gte=<span class="hljs-params">100</span>,rating__gte=<span class="hljs-params">9</span>)
```
```
以上這個案例是一個并集查詢,可以簡單的通過傳遞多個條件進去來實現。
但是如果想要實現一些復雜的查詢語句,比如要查詢所有價格低于10元,或者是評分低于9分的圖書。那就沒有辦法通過傳遞多個條件進去實現了。這時候就需要使用`Q表達式`來實現了。示例代碼如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.db.models <span class="hljs-keyword">import</span> Q
books = Book.objects.filter(Q(price__lte=<span class="hljs-params">10</span>) | Q(rating__lte=<span class="hljs-params">9</span>))
```
```
以上是進行或運算,當然還可以進行其他的運算,比如有`&`和`~(非)`等。一些用`Q`表達式的例子如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.db.models <span class="hljs-keyword">import</span> Q
<span class="hljs-title"># 獲取id等于3的圖書</span>
books = Book.objects.filter(Q(id=<span class="hljs-params">3</span>))
<span class="hljs-title"># 獲取id等于3,或者名字中包含文字"記"的圖書</span>
books = Book.objects.filter(Q(id=<span class="hljs-params">3</span>)|Q(name__contains(<span class="hljs-string">"記"</span>)))
<span class="hljs-title"># 獲取價格大于100,并且書名中包含"記"的圖書</span>
books = Book.objects.filter(Q(price__gte=<span class="hljs-params">100</span>)&Q(name__contains(<span class="hljs-string">"記"</span>)))
<span class="hljs-title"># 獲取書名包含“記”,但是id不等于3的圖書</span>
books = Book.objects.filter(Q(name__contains=<span class="hljs-string">'記'</span>) & ~Q(id=<span class="hljs-params">3</span>))
```
```
- Introduction
- 第一章:學前準備
- 第一節:虛擬環境
- 第二節:準備工作
- 第三節:Django介紹
- 第四節:URL組成部分
- 第二章:URL與視圖
- 第一節:第一個Django項目
- 第二節:視圖與URL分發器
- 第三章:模板
- 第一節:模板介紹
- 第二節:模板變量
- 第三節:常用標簽
- 第四節:常用過濾器
- 第五節:自定義過濾器
- 第七節:模版結構優化
- 第八節:加載靜態文件
- 第四章:數據庫
- 第一節:MySQL相關軟件
- 第二節:數據庫操作
- 第三節:ORM模型
- 第四節:模型常用字段
- 第五節:外鍵和表關系
- 第六節:增刪改查操作
- 第七節:查詢操作
- 第八節:QuerySet API
- 第九節:ORM模型遷移
- 第十節:ORM作業
- 第十一節:ORM作業參考答案
- 第十二節:Pycharm連接數據庫
- 第五章:視圖高級
- 第一節:限制請求method
- 第二節:頁面重定向
- 第三節:HttpRequest對象
- 第四節:HttpResponse對象
- 第五節:生成CSV文件
- 第六節:類視圖
- 第七節:錯誤處理
- 第六章:表單
- 第一節:表單概述
- 第二節:用表單驗證數據
- 第三節:ModelForm
- 第四節:文件上傳
- 第七章:cookie和session
- 第八章:上下文處理器和中間件
- 第一節:上下文處理器
- 第二節:中間件
- 第九章:安全
- 第一節:CSRF攻擊
- 第二節:XSS攻擊
- 第三節:點擊劫持攻擊
- 第四節:SQL注入
- 第十章:信號
- 第一節:什么是信號
- 第十一章:驗證和授權
- 第一節:概述
- 第二節:用戶對象
- 第三節:權限和分組
- 第十二章:Admin系統
- 第十三章:Django的緩存
- 第十四章:memcached
- 第十五章:Redis