# 第七节:查询操作
# 查询操作
查找是数据库操作中一个非常重要的技术。查询一般就是使用`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