Django

Python web 框架的简单使用

  • 简介

  • MVC

    1
    2
    3
    4
    5
    6
    7
    8
    django框架与传统的MVC框架不同,而是采用了MVT的架构。
    框架的核心思想是:解耦
    降低各功能模块之间的耦合性,方便变更,更容易重构代码,最大程度上实现代码的重用
    m表示model,主要用于对数据库层的封装
    v表示view,用于向用户展示结果
    c表示controller,是核心,用于处理请求、获取数据、返回结果
  • MVT

    1
    2
    3
    m表示model,负责与数据库交互
    v表示view,是核心,负责接收请求、获取数据、返回结果
    t表示template,负责呈现内容到浏览器

入门

环境搭建

ubuntu16.04
python虚拟环境搭建教程

查看虚拟环境中已经安装的包
pip list
pip freeze

安装

1
2
3
安装1.8.2版本,使用的人多,文档多,便于学习。
pip install django==1.8.2

djangoversion

创建项目

1
2
3
4
django-admin startproject test1
让我们看一下startproject生成了什么:

djangostart

设计数据库

1
本示例完成“图书-英雄”信息的维护,需要存储两种数据:图书、英雄
1
2
3
4
图书表结构设计:
表名:BookInfo
图书名称:btitle
图书发布时间:bpub_date
1
2
3
4
5
6
7
8
9
10
11
12
13
14
英雄表结构设计:
表名:HeroInfo
英雄姓名:hname
英雄性别:hgender
英雄简介:hcontent
所属图书:hbook
一本图书有多个英雄,
例如三国。
三国里面的英雄又只属于三国这一本书,不可能让诸葛亮跑去水浒传指点江山吧?
因此 图书-英雄的关系为一对多

数据库配置

1
2
3
4
5
在settings.py文件中,通过DATABASES项进行数据库设置
django支持的数据库包括:sqlite、mysql等主流数据库
Django默认使用SQLite数据库

djangosupportdb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
先安装pymysql
pip install pymysql
setting.py
mysql 配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME' : 'djangotest' ,
'USER' : 'root' ,
'PASSWORD' : 'root' ,
'HOST' : '127.0.0.1' ,
'PORT' : '3306' ,
}
}
配置完后需要在项目的__init__.py 加入如下代码。

mysqlinit

创建应用

1
2
3
4
5
6
在一个项目中可以创建一到多个应用,
每个应用进行一种业务处理
创建应用的命令:
python manage.py startapp appname

djangoapp

定义模型类

1
2
3
4
5
6
7
8
9
10
11
有一个数据表,就有一个模型类与之对应
打开models.py文件,定义模型类
引入包from django.db import models
模型类继承自models.Model类
说明:不需要定义主键列,在生成时会自动添加,并且值为自动增长
当输出对象时,会调用对象的str方法

modle

modleshuom

生成数据表

1
2
3
4
5
激活模型:
编辑settings.py文件,
将blog应用加入到
installed_apps中

djangoinstallapp

1
2
3
4
5
生成迁移文件:根据模型类生成sql语句
python manage.py makemigrations
迁移文件被生成到应用的migrations目录

makemigrayions

1
2
3
执行迁移:
执行sql语句在mysql数据库中生成相应的表
python manage.py migrate

migrate1

migrate2

测试数据操作

1
2
3
进入python shell,进行简单的模型API练习
python manage.py shell

djselect1

  • 关联对象的操作
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    对于HeroInfo可以按照上面的操作方式进行
    添加,注意添加关联对象
    h=HeroInfo()
    h.hname='郭靖'
    h.hgender=True
    h.hcontent='降龙十八掌'
    h.hBook=b
    h.save()
    hh=HeroInfo()
    hh.hname='黄蓉'
    hh.hgender=True
    hh.hcontent='降龙十九掌'
    hh.hBook=b
    hh.save()
    获得关联集合:返回当前book对象的所有hero
    b.heroinfo_set.all()
    有一个HeroInfo存在,必须要有一个BookInfo对象,提供了创建关联的数据:
    h=b.heroinfo_set.create(hname=u'黄蓉',hgender=False,hcontent=u'打狗棍法')

djselect2

管理站点

服务器

1
2
3
4
5
6
7
8
9
10
11
运行如下命令可以开启服务器
python manage.py runserver ip:port
不写 默认127.0.0.1:8000
可以修改端口
python manage.py runserver 8080
如果修改文件不需要重启服务器,如果增删文件需要重启服务器
这是一个纯python编写的轻量级web服务器,仅在开发阶段使用

管理操作

1
2
3
4
5
6
站点分为“内容发布”和“公共访问”两部分
“内容发布”的部分负责添加、修改、删除内容,
开发这些重复的功能是一件单调乏味、缺乏创造力的工作。
为此,Django会根据定义的模型类完全自动地生成管理模块
  • 使用django的管理
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    创建一个管理员用户
    python manage.py createsuperuser
    按提示输入用户名、邮箱、密码
    启动服务器,通过“127.0.0.1:8000/admin”访问,
    输入上面创建的用户名、密码完成登录
    进入管理站点,默认可以对groups、users进行管理

admin

  • 管理界面本地化
1
2
3
4
编辑settings.py文件,设置编码、时区
LANGUAGE_CODE = 'zh-Hans'
TIME_ZONE = 'Asia/Shanghai'

admin2

admin3

  • 向admin注册blog的模型
    1
    打开blog/admin.py文件,注册模型

register1

  • 自定义管理页面
    1
    2
    3
    4
    5
    6
    7
    Django提供了admin.ModelAdmin类
    通过定义ModelAdmin的子类,来定义模型在Admin界面的显示方式
    class QuestionAdmin(admin.ModelAdmin):
    ...
    admin.site.register(BookInfo, QuestionAdmin)

admin4

admin5

  • 关联对象
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    对于HeroInfo模型类,有两种注册方式
    方式一:与BookInfo模型类相同
    方式二:关联注册
    按照BookInfor的注册方式完成HeroInfo的注册
    接下来实现关联注册
    可以将内嵌的方式改为表格
    class HeroInfoInline(admin.TabularInline)

admin6

admin7

  • 布尔值的显示
    1
    2
    3
    4
    5
    6
    7
    8
    9
    发布性别的显示不是一个直观的结果,可以使用方法进行封装
    def gender(self):
    if (self.hgender):
    return '男'
    else:
    return '女'
    gender.short_description = '性别'

admin8

admin9

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from django.contrib import admin
from .models import BookInfo
from .models import HeroInfo
# Register your models here.
# class HeroInfoInline(admin.TabularInline)
class HeroInfoInline(admin.StackedInline):
model = HeroInfo
extra = 2
# 默认提供足够2个HeroInfo的空间。
class HeroInfoAdmin(admin.ModelAdmin):
list_display = ['id', 'hname', 'gender', 'hcontent']
admin.site.register(HeroInfo, HeroInfoAdmin)
class QuestionAdmin(admin.ModelAdmin):
"""
列表页属性:
list_display:显示字段,可以点击列头进行排序
list_filter:过滤字段,过滤框会出现在右侧
search_fields:搜索字段,搜索框会出现在上侧
list_per_page:分页,分页框会出现在下侧
添加、修改页属性:
fields:属性的先后顺序
fieldsets:属性分组
fields和fieldsets不能一起用
"""
list_display = ['pk', 'btitle', 'bpub_date']
inlines = [HeroInfoInline]
list_filter = ['btitle']
search_fields = ['btitle']
list_per_page = 10
# fields = ['bpub_date', 'btitle']
fieldsets = [
('basic',{'fields': ['btitle']}),
('more', {'fields': ['bpub_date']}),
]
admin.site.register(BookInfo, QuestionAdmin)

视图

1
2
3
4
5
在django中,视图对WEB请求进行回应
视图接收reqeust对象作为第一个参数,包含了请求的信息
视图就是一个Python函数,被定义在views.py中

djview

1
2
3
4
5
定义完成视图后,需要配置urlconf,否则无法处理请求
Django使用正则表达式匹配请求的URL,一旦匹配成功,则调用应用的视图
注意:只匹配路径部分,即除去域名、参数后的字符串

djurl1

djurl2

respon1

respon2

模板

1
2
模板是html页面,可以根据视图中传递的数据填充值
创建模板的目录如下图:

template1

1
2
3
4
5
6
7
修改settings.py文件,设置TEMPLATES的DIRS值
'DIRS': [os.path.join(BASE_DIR, 'templates')],
在模板中访问视图传递的数据
{{输出值,可以是变量,也可以是对象.属性}}
{%执行代码段%}

template2

template3

  • Render简写
    1
    2
    3
    Django提供了函数Render()简化视图调用模板、构造上下文
    request == <WSGIRequest: GET '/'>
    可以把request 输出到页面上就可以看到了。

template4

模型

1
2
3
4
5
6
7
8
MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,
即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库
ORM是“对象-关系-映射”的简称,主要任务是:
根据对象的类型生成表结构
将对象、列表的操作,转换为sql语句
将sql查询到的结果转换为对象、列表
  • 模型开发流程
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    在models.py中定义模型类,要求继承自models.Model
    把应用加入settings.py文件的installed_app项
    生成迁移文件
    执行迁移生成表
    使用模型类进行crud操作
    使用数据库生成模型类
    python manage.py inspectdb > blog/models.py

定义模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
在模型中定义属性,会生成表中的字段
django会为表增加自动增长的主键列,每个模型只能有一个主键列,
默认情况下,Django 会给每个模型添加下面这个字段:
id = models.AutoField(primary_key=True)
这是一个自增主键字段。
如果你想指定一个自定义主键字段,只要在某个字段上指定 primary_key=True 即可
如果使用选项设置某属性为主键列后,则django不会再生成默认的主键列
属性命名限制
不能是python的保留关键字
由于django的查询方式,字段名称中连续的下划线不能超过一个

定义属性

1
2
3
4
5
6
7
8
9
10
定义属性时,需要字段类型
使用方式
导入from django.db import models
通过models.Field创建字段类型的对象,赋值给属性
对于重要数据都做逻辑删除,不做物理删除,
实现方法是定义isDelete属性,类型为BooleanField,默认值为False

字段类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
AutoField:一个根据实际ID自动增长的IntegerField,通常不指定
- 如果不指定,一个主键字段将自动添加到模型中
BooleanField:true/false 字段,此字段的默认表单控制是CheckboxInput
NullBooleanField:支持null、true、false三种值
CharField(max_length=字符长度):字符串,默认的表单样式是 TextInput
TextField:大文本字段,一般超过4000使用,默认的表单控件是Textarea
IntegerField:整数
DecimalField(max_digits=None, decimal_places=None):使用python的Decimal实例表示的十进制浮点数
- DecimalField.max_digits:位数总数
- DecimalField.decimal_places:小数点后的数字位数
FloatField:用Python的float实例来表示的浮点数
DateField[auto_now=False, auto_now_add=False]):使用Python的datetime.date实例表示的日期
- 参数DateField.auto_now:每次保存对象时,自动设置该字段为当前时间,
用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false
-
- 参数DateField.auto_now_add:当对象第一次被创建时自动设置当前时间,
用于创建的时间戳,它总是使用当前日期,默认为false
-
- 该字段默认对应的表单控件是一个TextInput.
在管理员站点添加了一个JavaScript写的日历控件,
和一个“Today"的快捷按钮,包含了一个额外的invalid_date错误消息键
-
- auto_now_add, auto_now, and default 这些设置是相互排斥的,
他们之间的任何组合将会发生错误的结果
TimeField:使用Python的datetime.time实例表示的时间,参数同DateField
DateTimeField:使用Python的datetime.datetime实例表示的日期和时间,参数同DateField
FileField:一个上传文件的字段
ImageField:继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是个有效的image

字段选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
通过字段选项,可以实现对字段的约束
在字段对象时通过关键字参数指定
null:如果为True,Django 将空值以NULL 存储到数据库中,默认值是 False
blank:如果为True,则该字段允许为空值,默认值是 False
对比:
null是数据库范畴的概念,指数据库中字段内容是否允许为空,
blank是表单验证证范畴的
如果一个字段的blank=True,表单的验证将允许输入一个空值。如果字段的blank=False,该字段就是必填的
db_column:字段的名称,如果未指定,则使用属性的名称
db_index:若值为 True, 则在表中会为此字段创建索引
default:默认值
primary_key:若为 True, 则该字段会成为模型的主键字段
unique:如果为 True, 这个字段在表中必须有唯一值
以上都是常用字段的介绍

要了解详细内容请查看

关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
关系的类型包括
ForeignKey:一对多,将字段定义在多的端中
ManyToManyField:多对多,
在哪个模型中设置 ManyToManyField 并不重要,在两个模型中任选一个即可 —— 不要两个模型都设置。
OneToOneField:一对一,将字段定义在任意一端中
可以维护递归的关联关系,使用'self'指定,详见“自关联”
对象.模型类小写_set -> 找到所有外键为1的。
bookhtl = BookInfo.objects.get(pk=1)
aall = bookhtl.heroinfo_set.all()
访问外键所链接的主键。
hero = HeroInfo.objects.get(pk=1)
a = hero.hbook

多对多

元选项

1
2
3
4
在模型类中定义类Meta,用于设置元信息
元信息db_table:定义数据表名称,推荐使用小写字母,
数据表的默认名称:<app_name>_<model_name> 应用名字_模型类名
  • ordering
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    对象默认的顺序,获取一个对象的列表时使用:
    ordering = ['-order_date']
    它是一个字符串的列表或元组。
    每个字符串是一个字段名,
    前面带有可选的“-”前缀表示倒序。
    前面没有“-”的字段表示正序。
    使用"?"来表示随机排序。
    例如,要按照pub_date字段的正序排序,这样写:
    ordering = ['pub_date']
    按照pub_date字段的倒序排序,这样写:
    ordering = ['-pub_date']
    先按照pub_date的倒序排序,再按照 author 的正序排序,这样写:
    ordering = ['-pub_date', 'author']
    注意:排序会增加数据库的开销!!!!

djmodle1

  • 测试数据
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    模型BookInfo的测试数据
    insert into bookinfo(btitle,bpub_date,bread,bcommet,isDelete) values
    ('射雕英雄传','1980-5-1',12,34,0),
    ('天龙八部','1986-7-24',36,40,0),
    ('笑傲江湖','1995-12-24',20,80,0),
    ('雪山飞狐','1987-11-11',58,24,0);
    模型HeroInfo的测试数据
    insert into mondletest_heroinfo(hname,hgender,hbook_id,hcontent,isDelete) values
    ('郭靖',1,1,'降龙十八掌',0),
    ('黄蓉',0,1,'打狗棍法',0),
    ('黄药师',1,1,'弹指神通',0),
    ('欧阳锋',1,1,'蛤蟆功',0),
    ('梅超风',0,1,'九阴白骨爪',0),
    ('乔峰',1,2,'降龙十八掌',0),
    ('段誉',1,2,'六脉神剑',0),
    ('虚竹',1,2,'天山六阳掌',0),
    ('王语嫣',0,2,'神仙姐姐',0),
    ('令狐冲',1,3,'独孤九剑',0),
    ('任盈盈',0,3,'弹琴',0),
    ('岳不群',1,3,'华山剑法',0),
    ('东方不败',0,3,'葵花宝典',0),
    ('胡斐',1,4,'胡家刀法',0),
    ('苗若兰',0,4,'黄衣',0),
    ('程灵素',0,4,'医术',0),
    ('袁紫衣',0,4,'六合拳',0);

djmodle2

djmodle3

djmodle4

模型成员

类的属性

1
2
3
4
5
6
7
8
9
10
objects:是Manager类型的对象,用于与数据库进行交互
当定义模型类时没有指定管理器,则Django会为模型类提供一个名为objects的管理器
支持明确指定模型类的管理器
class BookInfo(models.Model):
books = models.Manager()
当为模型类指定管理器后,django不再为模型类生成名为objects的默认管理器

管理器Manager

1
2
3
4
5
6
管理器是Django的模型进行数据库的查询操作的接口,Django应用的每个模型都拥有至少一个管理器
自定义管理器类主要用于两种情况
情况一:向管理器类中添加额外的方法,在模型类写个类方法也可以实现,官方推荐使用管理器。
情况二:修改管理器返回的原始查询集:重写get_queryset()方法

源码中我们可以看到。
manage1

manage2

manage3

实例的属性

1
DoesNotExist:在进行单个查询时,模型的对象不存在时会引发此异常,结合try/except使用

实例的方法

1
2
3
save():将模型对象保存到数据表中
delete():将模型对象从数据表中删除

模型查询

简介

1
2
3
4
5
6
7
8
9
10
11
12
查询集表示从数据库中获取的对象集合
查询集可以含有零个、一个或多个过滤器
过滤器 基于所给的参数限制查询的结果
从Sql的角度,查询集和select语句等价,过滤器像where和limit子句
接下来主要讨论如下知识点
查询集
字段查询:比较运算符,F对象,Q对象

查询集

1
2
3
4
5
6
7
8
9
在管理器上调用过滤器方法会返回查询集
查询集经过过滤器筛选后返回新的查询集,因此可以写成链式过滤
惰性执行:创建查询集不会带来任何数据库的访问,直到调用数据时,才会访问数据库
何时对查询集求值:迭代,序列化,与if合用
查询的快捷方式:pk,pk表示primary key,默认的主键是id
  • 返回查询集的方法,称为过滤器
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    all()
    filter() 返回一个新的QuerySet,包含与给定的查询参数匹配的对象。
    exclude() 返回一个新的QuerySet,它包含不满足给定的查找参数的对象。
    order_by() 排序
    Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
    上面的结果将按照pub_date 降序排序,然后再按照headline 升序排序。
    values():一个对象构成一个字典,然后构成一个列表返回
    写法:
    filter(键1=值1,键2=值2)
    等价于
    filter(键1=值1).filter(键2=值2)

djselect

djselect111

  • 返回单个值的方法
    1
    2
    3
    4
    5
    6
    7
    8
    get():返回单个满足条件的对象
    如果未找到会引发"模型类.DoesNotExist"异常
    如果多条被返回,会引发"模型类.MultipleObjectsReturned"异常
    count():返回当前查询的总条数
    first():返回第一个对象
    last():返回最后一个对象
    exists():判断查询集中是否有数据,如果有则返回True

djselect222

限制查询集

1
2
3
4
5
6
7
8
查询集返回列表,可以使用下标的方式进行限制,等同于sql中的limit和offset子句
注意:不支持负数索引
使用下标后返回一个新的查询集,不会立即执行查询
如果获取一个对象,直接使用[0],等同于[0:1].get(),
但是如果没有数据,[0]引发IndexError异常,
[0:1].get()引发DoesNotExist异常

djselect3

查询集的缓存

1
2
3
4
5
每个查询集都包含一个缓存来最小化对数据库的访问
在新建的查询集中,缓存为空,
首次对查询集求值时,会发生数据库查询,
django会将查询的结果存在查询集的缓存中,并返回请求的结果,接下来对查询集求值将重用缓存的结果
1
2
3
4
情况一:这构成了两个查询集,无法重用缓存,每次查询都会与数据库进行一次交互,增加了数据库的负载
print([e.title for e in Entry.objects.all()])
print([e.title for e in Entry.objects.all()])
1
2
3
4
情况二:两次循环使用同一个查询集,第二次使用缓存中的数据
querylist=Entry.objects.all()
print([e.title for e in querylist])
print([e.title for e in querylist])

何时查询集不会被缓存

1
2
当只对查询集的部分进行求值时会检查缓存,但是如果这部分不在缓存中,那么接下来查询返回的记录将不会被缓存,
这意味着使用索引来限制查询集将不会填充缓存,如果这部分数据已经被缓存,则直接使用缓存中的数据
1
2
3
4
5
例如,重复获取查询集对象中一个特定的索引将每次都查询数据库:
>>> queryset = Entry.objects.all()
>>> print queryset[5] # Queries the database
>>> print queryset[5] # Queries the database again

1
2
3
4
5
6
然而,如果已经对全部查询集求值过,则将检查缓存:
>>> queryset = Entry.objects.all()
>>> [entry for entry in queryset] # Queries the database
>>> print queryset[5] # Uses cache
>>> print queryset[5] # Uses cache

字段查询

1
2
3
4
5
6
7
8
9
10
实现where子名,作为方法filter()、exclude()、get()的参数
语法:属性名称__比较运算符=值 - (模型类当中的属性)
表示两个下划线,左侧是属性名称,右侧是比较类型
对于外键,使用“属性名_id”表示外键的原始值
转义:like语句中使用了%与,匹配数据中的%与,在过滤器中直接写,例如:filter(title__contains="%")=>where title like '%\%%',表示查找标题中包含%的

比较运算符

1
2
3
4
5
6
7
8
9
exact:表示判等,大小写敏感;如果没有写“ 比较运算符”,表示判等
contains:是否包含,大小写敏感
startswith、endswith:以value开头或结尾,大小写敏感
isnull 值为 True 或 False, 相当于 SQL语句IS NULL和IS NOT NULL.
在前面加个i表示不区分大小写,如iexact、icontains、istarswith、iendswith

djselect5

djselect4

1
2
3
4
5
in:是否包含在范围内
gt、gte、lt、lte:大于、大于等于、小于、小于等于
year、month、day、week_day、hour、minute、second:对日期间类型的属性进行运算

djselect6

djselect7

跨关联关系的查询:处理join查询

1
2
3
4
语法:模型类名 <属性名> <比较>
注:可以没有__<比较>部分,表示等于,结果同inner join
可返向使用,即在关联的两个模型中都可以使用

djselect8

聚合函数

1
2
3
4
5
6
7
8
9
10
11
使用aggregate()函数返回聚合函数的值
函数:Avg,Count,Max,Min,Sum
from django.db.models import Max
a=BookInfo.books.aggregate(Max('pk'))
count的一般用法:
a=BookInfo.books.count()

djselect9

1
以上查询都是一个字段跟一个常量做比较,如果希望字段间进行比较,可以使用F对象

F对象

1
2
3
4
5
6
7
8
9
from django.db.models import F
django支持对F()对象使用算数运算
F()对象中还可以写作“模型类__列名”进行关联查询
对于date/time字段,可与timedelta()进行运算

djselect10

Q对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from django.db.models import Q
过滤器的方法中关键字参数查询,默认会合并为And进行
a=BookInfo.books.filter(pk__lt=3,bcommet__gt=100)
等同于
a=BookInfo.books.filter(Q(pk__lt=3)&Q(bcommet__gt=100))
主键小于10,并且评论数目大于10.
如果想要进行or 查询。必须使用Q()对象
a=BookInfo.books.filter(Q(pk__lt=3)|Q(bcommet__gt=100))
a=BookInfo.books.filter(Q(pk__lt=3)&Q(bcommet__gt=100))
这样就是and,默认就是and,没必要这样写。
使用~(not)操作符在Q对象前表示取反
a=BookInfo.books.filter(~Q(pk__lt=3)|Q(bcommet__gt=100))
过滤器函数可以混合使用Q对象和关键字参数,所有参数都将and在一起,Q对象必须位于关键字参数的前面

djselect11

自连接

1
2
3
4
5
6
7
8
新建模型AreaInfo,生成迁移,记得在setting.py注册应用
class AreaInfo(models.Model):
atitle = models.CharField(max_length=20)
aParent = models.ForeignKey('self', null=True, blank=True)
访问关联对象
上级对象:area.aParent
下级对象:area.areainfo_set.all()

加入测试数据

self0

self1

self2

self3

self4

视图

1
2
3
4
5
视图接受Web请求并且返回Web响应
视图就是一个python函数,被定义在views.py中
响应可以是一张网页的HTML内容,一个重定向,一个404错误等等
响应处理过程如下图:

djview1

URLconf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
在settings.py文件中通过ROOT_URLCONF指定根级url的配置
urlpatterns是一个url()实例的列表
编写URLconf的注意:
若要从url中捕获一个值,需要在它周围设置一对圆括号
不需要添加一个前导的反斜杠,如应该写作'test/',而不应该写作'/test/'
每个正则表达式前面的r表示字符串不转义
请求的url被看做是一个普通的python字符串,进行匹配时不包括get或post请求的参数及域名
http://www.lxhsec.com/python/django/?id=1
只匹配python/django/部分
  • 正则表达式非命名组,通过位置,按顺序将参数传递给视图
    viewtest1

viewtest2

viewtest3

  • 正则表达式命名组,通过关键字参数传递给视图,
    其他代码不变
    viewtask1
1
2
3
参数匹配规则:优先使用命名参数,如果没有命名参数则使用位置参数
每个捕获的参数都作为一个普通的python字符串传递给视图

定义视图

1
2
3
4
5
6
7
8
本质就是一个函数
视图的参数
一个HttpRequest实例
通过正则表达式组获取的位置参数
通过正则表达式组获得的关键字参数
如果处理功能过多,可以细化功能,分别写在不同的应用中。

自定义404视图

1
2
3
默认的404视图将传递一个变量给模板:request_path,它是导致错误的URL
如果Django在检测URLconf中的每个正则表达式后没有找到匹配的内容也将调用404视图

viewtest4

viewtest5

Request

  • HttpReqeust

    1
    2
    3
    4
    5
    浏览器输入url后,服务器接收到http协议的请求后,会根据报文创建HttpRequest对象
    视图函数的第一个参数是HttpRequest对象
    在django.http模块中定义了HttpRequest对象的API
  • 属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    下面除非特别说明,属性都是只读的
    path:一个字符串,表示请求的页面的完整路径,不包含域名
    method:一个字符串,表示请求使用的HTTP方法,常用值包括:'GET'、'POST'
    encoding:一个字符串,表示提交的数据的编码方式
    如果为None则表示使用浏览器的默认设置,一般为utf-8
    这个属性是可写的,
    可以通过修改它来修改访问表单数据使用的编码,
    接下来对属性的任何访问将使用新的encoding值
    GET:一个类似于字典的对象,包含get请求方式的所有参数
    POST:一个类似于字典的对象,包含post请求方式的所有参数
    FILES:一个类似于字典的对象,包含所有的上传文件
    COOKIES:一个标准的Python字典,包含所有的cookie,键和值都为字符串
    session:一个既可读又可写的类似于字典的对象,
    表示当前的会话,只有当Django 启用会话的支持时才可用,
    详细内容见“状态保持”
  • 方法

    1
    is_ajax():如果请求是通过XMLHttpRequest发起的,则返回True

QueryDict对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
一个类字典对象
python字典中键是唯一的。
而QueryDict对象 允许 相同的键,即同一个键带有多个值的情况
方法get():根据键获取值
只能获取键的一个值
如果一个键同时拥有多个值,获取最后一个值
dict.get('键',default)
或简写为
dict['键'] -> 如果没有那个键,则会报异常。推荐使用第一种
方法getlist():根据键获取值
将键的值以列表返回,可以获取一个键的多个值
dict.getlist('键',default)

GET

1
2
3
4
5
6
7
8
9
QueryDict类型的对象
包含get请求方式的所有参数
与url请求地址中的参数对应,位于?后面
参数的格式是键值对,如key1=value1
多个参数之间,使用&连接

djget1

djget2

djget3

djget4

djget5

POST

1
2
3
4
5
6
7
8
9
QueryDict类型的对象
包含post请求方式的所有参数
与form表单中的控件对应
控件name属性的值为键,value属性的值为值,构成键值对提交
对于checkbox控件,name属性一样为一组,当控件被选中后会被提交,存在一键多值的情况

djpost1

djpost2

djpost3

djpost4

djpost5

post6.gif

详细request

Response

1
2
3
4
5
在django.http模块中定义了HttpResponse对象的API
HttpRequest对象由Django自动创建,HttpResponse对象由程序员创建
不调用模板,直接返回数据

HttpResponse对象方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
write(content):以文件的方式写
flush():以文件的方式输出缓存区
set_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False)
:设置Cookie cookie就是存储在浏览器端的一段文本
key、value都是字符串类型
max_age是一个整数,表示在指定秒数后过期
expires 应该是一个 UTC "Wdy, DD-Mon-YY HH:MM:SS GMT" 格式的字符串,或者一个datetime.datetime 对象。
如果expires 是一个datetime 对象,则max_age 会通过计算得到。
如果你想
max_age与expires二选一
如果不指定过期时间,则两个星期后过期
如果你想设置一个跨域的Cookie,请使用domain 参数。例如,domain=".lawrence.com" 将设置一个www.lawrence.com、blogs.lawrence.com 和calendars.lawrence.com 都可读的Cookie。否则,Cookie 将只能被设置它的域读取。
如果你想阻止客服端的JavaScript 访问Cookie,可以设置httponly=True。
delete_cookie(key):删除指定的key的Cookie,如果key不存在则什么也不发生

从response对象中,设置cookie,
cookie

从request对象中,读取cookie
cookie2

详细response

HttpResponse的子类

子类HttpResponseRedirect

1
2
3
4
与 HttpResponse相同, 这些衍生类(子类)存在于django.http之中。
重定向,服务器端跳转
构造函数的第一个参数用来指定重定向的地址

redirect1.gif

redirect

direct

子类JsonResponse

1
2
3
4
返回json数据,一般用于异步请求
_init _(data)
参数data是字典对象
JsonResponse的默认Content-Type为application/json

repjson

repjson1

简写函数

render

1
2
3
4
5
6
7
8
render(request, template_name[, context])
结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的HttpResponse对象
request:该request用于生成response
template_name:要使用的模板的完整名称
context:添加到模板上下文的一个字典,视图将在渲染模板之前调用它
[]表示 可选参数

状态保持

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
http协议是无状态的:每次请求都是一次新的请求,不会记得之前通信的状态
若我们想记录这种通信状态,可以用session(会话),或cookie来保存。
客户端与服务器端的一次通信,就是一次会话
实现状态保持的方式:在客户端或服务器端存储与会话有关的数据
使用cookie,所有数据存储在客户端,注意不要存储敏感信息
推荐使用sesison方式,所有数据存储在服务器端,
在客户端cookie中存储session_id->session依赖于cookie,
状态保持的目的是在一段时间内跟踪请求者的状态,可以实现跨页面访问当前请求者的数据
注意:不同的请求者之间不会共享这个数据,与请求者一一对应
使用django-admin startproject创建的项目默认启用默认是启动session

session1

使用session

1
2
3
4
5
6
启用会话后,每个HttpRequest对象将具有一个session属性,它是一个类字典对象
get(key, default=None):根据键获取会话的值
clear():清除所有会话
flush():删除当前的会话数据并删除会话的Cookie
del request.session['member_id']:删除会话

session2.gif

djsession1

djsession2

djsession3

djsession4

会话过期时间

1
2
3
4
5
6
7
8
9
set_expiry(value):设置会话的超时时间
如果没有指定,则两个星期后过期
如果value是一个整数,会话将在values秒没有活动后过期
若果value是一个imedelta对象,会话将在当前时间加上这个指定的日期/时间过期
如果value为0,那么用户会话的Cookie将在用户的浏览器关闭时过期
如果value为None,那么会话永不过期
修改视图中login_handle函数,查看效果

sessionexpiry

session存在哪里

1
2
3
4
5
6
7
8
django默认的会话存储方式是存放在数据库。
因此需要迁移,使数据库中产生对应的session表
SESSION_ENGINE='django.contrib.sessions.backends.db'
SESSION_ENGINE='django.contrib.sessions.backends.cache'
SESSION_ENGINE='django.contrib.sessions.backends.cached_db'

session2

session3

使用Redis缓存session

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
安装包
pip install django-redis-sessions
修改settings中的配置,增加如下项,(根据自己配置的改,以下是默认配置)
SESSION_ENGINE = 'redis_sessions.session'
SESSION_REDIS_HOST = 'localhost'
SESSION_REDIS_PORT = 6379
SESSION_REDIS_DB = 0
SESSION_REDIS_PASSWORD = ''
SESSION_REDIS_PREFIX = 'session'
服务器上要安装有redis。
启动:sudo redis-server /etc/redis/redis.conf
停止:sudo redis-server stop
重启:sudo redis-server restart
redis-cli:使用客户端连接服务器
keys *:查看所有的键
get name:获取指定键的值
del name:删除指定名称的键

session5

服务端存储大量session 如何区分。

session4

session完整

模板

模板介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
作为Web框架,Django提供了模板,可以很便利的动态生成HTML
模版系统致力于表达外观,而不是程序逻辑
模板的设计实现了业务逻辑(view)与显示内容(template)的分离,一个视图可以使用任意一个模板,一个模板可以供多个视图使用
模板包含:
HTML的静态部分
动态插入内容部分
Django模板语言,简写DTL,定义在django.template包中
由startproject命令生成的settings.py定义关于模板的值:
DIRS定义了一个目录列表,模板引擎按列表顺序搜索这些目以查找模板源文件
APP_DIRS告诉模板引擎是否应该在每个已安装的应用中查找模板
常用方式:在项目的根目录下创建templates目录,设置DIRS值
DIRS=[os.path.join(BASE_DIR,"templates")]

template11

模板处理

1
2
3
4
5
6
7
8
9
10
11
12
Django处理模板分为两个阶段
Step1 加载:根据给定的标识找到模板然后预处理,通常会将它编译好放在内存中
Step2 渲染:使用Context数据对模板插值并返回生成的字符串
render(request,'模板',context)
Step3 返回给浏览器:
return render(request,'模板',context)
render是快捷函数,为了减少加载模板、渲染模板的重复代码,

定义模块

变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
语法:
{{ variable }}
当模版引擎遇到一个变量,将计算这个变量,然后将结果输出
变量名必须由字母、数字、下划线(不能以下划线开头)和点组成
如果变量不存在, 模版系统将插入'' (空字符串)
在模板中调用方法时不能传递参数
当模版引擎遇到点("."),会按照下列顺序查询:
字典查询,例如:foo["bar"]
属性或方法查询,例如:foo.bar
数字索引查询,例如:foo[bar]

djtmptest1

djtmptest2

djtmptest3

djtmptest4

标签

1
2
3
4
5
6
7
8
9
10
11
语法:{ % tag % }
作用
在输出中创建文本
控制循环或逻辑
加载外部信息到模板中供以后的变量使用
布尔标签:and、or,and比or的优先级高
  • for标签
    1
    2
    3
    4
    5
    6
    7
    {% for each in test1 %}
    循环逻辑
    {{ forloop.counter }} 表示当前是第几次循环
    {% empty %}
    当要遍历的test1不存在时,执行此处,可以给出一些错误信息
    {% endfor %}

djfor.git

  • if标签
1
2
3
4
5
6
7
{% if ... %}
逻辑1
{% elif ... %}
逻辑2
{% else %}
逻辑3
{% endif %}

djtmptest5

  • comment标签

    1
    2
    3
    4
    5
    6
    {% comment %}
    多行注释
    {% endcomment %}
    单行注释
    {#...#}
  • csrf_token

    1
    2
    这个标签用于跨站请求伪造保护
    {% csrf_token %}

过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
语法:{ { 变量|过滤器 }}
使用管道符号 (|)来应用过滤器
通过使用过滤器来改变变量的计算结果
可以在if标签中使用过滤器结合运算符
if list1|length > 1
过滤器能够被“串联”,构成过滤器链
name|lower|upper
join 使用字符串连接列表,
{{ value|join:" // " }}
如果value是列表['a', 'b', 'c'] ,输出将是字符串“a // b // c“。
default:如果一个变量没有被提供,或者值为false或空,则使用默认值,否则使用变量的值
value|default:"什么也没有
date:根据给定格式对一个date变量格式化
value|date:'Y-m-d'

过滤器

反向解析

1
2
3
4
5
6
7
8
9
返回一个绝对路径的引用(不包含域名的URL),该引用匹配一个给定的视图函数和一些可选的参数。
它可以避免在模板中硬编码链接路径。
{% url 'myapp:view-name' p1 p2 %}
警告
不要忘记在函数路径或模式名称周围加引号,否则值将被解释为上下文变量!

fanxiang1

fanxiang2

fanxiang3

fanxiang4

fanxiang5

fanxiang6

模板继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
模板继承可以减少页面内容的重复定义,实现页面内容的重用
典型应用:网站的头部、尾部是一样的,这些内容可以定义在父模板中,子模板不需要重复定义
block标签:在父模板中预留区域,在子模板中填充
{% block block_name %}
这里可以定义默认值
如果不定义默认值,则表示空字符串
{% endblock %}
extends继承:继承,写在模板文件的第一行
{% extends "base.html" %}
说明
如果在模版中使用extends标签,它必须是模版中的第一个标签
不能在一个模版中定义多个相同名字的block标签
子模版不必定义全部父模版中的blocks,如果子模版没有定义block,则使用了父模版中的默认值
如果发现在模板中大量的重复内容,那就应该把内容移动到父模板中
使用可以获取父模板中block的内容
为了更好的可读性,可以给endblock标签一个名字
{ % block block_name %}
区域内容
{ % endblock block_name %}

例子

HTML转义

1
2
3
防止恶意的js代码。
从视图当中传进来的字符串会被模板转义,
  • Django会将如下字符自动转义:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    < 会转换为&lt;
    > 会转换为&gt;
    ' (单引号) 会转换为&#39;
    " (双引号)会转换为 &quot;
    & 会转换为 &amp;

关闭转义

1
2
3
4
5
6
7
8
9
10
对于变量使用safe过滤器
{{ data|safe }}
对于代码块使用autoescape标签
{ % autoescape off %}
{{ body }}
{ % endautoescape %}
标签autoescape接受on或者off参数
自动转义标签在base模板中关闭,在child模板中也是关闭的

手动转义

1
2
3
4
手动转义
{ { data|default:"<b>123</b>" }}
应写为
{ { data|default:"&lt;b&gt;123&lt;/b&gt;" }}

htmlzhuanyi

csrf

1
全称Cross Site Request Forgery,跨站请求伪造

djview11

djview12

djview13


还有个视频。。晚点。

验证码

高级

1
2
3
4
5
6
7
8
高级知识点包括:
静态文件处理
中间件
上传图片
Admin站点
分页
使用jquery完成ajax

静态文件处理

第三方