Model
到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞:
- 创建数据库,设计表结构和字段
- 使用 MySQLdb 来连接数据库,并编写数据访问层代码
- 业务逻辑层去调用数据访问层执行数据库操作
![](https://oscimg.oschina.net/oscnet/89dfdf3565a002148ad5a287d8ac95cb66c.gif)
django为使用一种新的方式,即:关系对象映射(Object Relational Mapping,简称ORM)。
PHP:activerecord
Java:Hibernate
C#:Entity Framework
django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表。
一、创建表
1、基本结构
1
2
3
4
5
6
|
from
django.db
import
models
class
userinfo(models.Model):
name
=
models.CharField(max_length
=
30
)
email
=
models.EmailField()
memo
=
models.TextField()
|
![](https://oscimg.oschina.net/oscnet/86afa19bf17898882623d0e6afa64c9bab7.gif)
![](https://oscimg.oschina.net/oscnet/fa7c9743bc37d067e64dade5b4a066b6909.gif)
![](https://oscimg.oschina.net/oscnet/b367a4c3e1e5f3ca06d2def4f67001752ed.gif)
![](https://oscimg.oschina.net/oscnet/ab07789e1bc953a4c39ba89119f856339a9.gif)
2、连表结构
- 一对多:models.ForeignKey(其他表)
- 多对多:models.ManyToManyField(其他表)
- 一对一:models.OneToOneField(其他表)
应用场景:
- 一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)
例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等。- 多对多:在某表中创建一行数据是,有一个可以多选的下拉框
例如:创建用户信息,需要为用户指定多个爱好- 一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了
例如:原有含10列数据的一张表保存相关信息,经过一段时间之后,10列无法满足需求,需要为原来的表再添加5列数据
![](https://oscimg.oschina.net/oscnet/6a3f26aad597b45bedc074a6aa344ecd3cc.gif)
二、操作表
1、基本操作
![](https://oscimg.oschina.net/oscnet/8bf11538908d9e369cce4decec93d6b09bb.gif)
2、进阶操作(了不起的双下划线)
利用双下划线将字段和对应的操作连接起来
![](https://oscimg.oschina.net/oscnet/6827aa30828ecb52bde78f1b798836da78f.gif)
3、其他操作
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
4、连表操作(了不起的双下划线)
利用双下划线和 _set 将表之间的操作连接起来
![](https://oscimg.oschina.net/oscnet/96571cc4abc378b83ad76dbf3fc1319930e.gif)
![](https://oscimg.oschina.net/oscnet/ce480d6e60f93a2cde8176f39d117a66308.gif)
![](https://oscimg.oschina.net/oscnet/a4179f39aee88bd5c8765709e7294869b4f.gif)
![](https://oscimg.oschina.net/oscnet/56f13a92ece9871f41d5ccdd0eb295c05eb.gif)
扩展:
a、自定义上传
![](https://oscimg.oschina.net/oscnet/faf400adf7c4d8f702cafa66e4e3ab4f078.gif)
b、Form上传文件实例
![](https://oscimg.oschina.net/oscnet/2261e340ed2425eb3c03ca06909d6006665.gif)
![](https://oscimg.oschina.net/oscnet/2558ae7cc0585f78a975bf431e8d8de5061.gif)
![](https://oscimg.oschina.net/oscnet/812d650cd85c435a282c83eff1a374291ae.gif)
Form
django中的Form一般有两种功能:
- 输入html
- 验证用户输入
![](https://oscimg.oschina.net/oscnet/ac265c650f2ceef4a8179d2336c93720675.gif)
![](https://oscimg.oschina.net/oscnet/65c1c656ed2c15dceb71653af1d4c6fa3cf.gif)
扩展:ModelForm
在使用Model和Form时,都需要对字段进行定义并指定类型,通过ModelForm则可以省去From中字段的定义
![](https://oscimg.oschina.net/oscnet/2403643d2e02402d9a876be1a2705f3b378.gif)
跨站请求伪造
一、简介
django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。
全局:
中间件 django.middleware.csrf.CsrfViewMiddleware
局部:
- @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
- @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
注:from django.views.decorators.csrf import csrf_exempt,csrf_protect
二、应用
1、普通表单
2、Ajax
对于传统的form,可以通过表单的方式将token再次发送到服务端,而对于ajax的话,使用如下方式。
view.py
text.html
更多:https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
Cookie
1、获取Cookie:
1
2
3
4
5
6
|
request.COOKIES[
'key'
]
request.get_signed_cookie(key, default
=
RAISE_ERROR, salt
=
'', max_age
=
None
)
参数:
default: 默认值
salt: 加密盐
max_age: 后台控制过期时间
|
2、设置Cookie:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
rep
=
HttpResponse(...) 或 rep = render(request, ...)
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt
=
'加密盐'
,...)
参数:
key, 键
value
=
'', 值
max_age
=
None
, 超时时间
expires
=
None
, 超时时间(IE requires expires, so
set
it
if
hasn't been already.)
path
=
'/'
, Cookie生效的路径,
/
表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问
domain
=
None
, Cookie生效的域名
secure
=
False
, https传输
httponly
=
False
只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
|
由于cookie保存在客户端的电脑上,所以,JavaScript和jquery也可以操作cookie。
1
2
|
<script src
=
'/static/js/jquery.cookie.js'
><
/
script>
$.cookie(
"list_pager_num"
,
30
,{ path:
'/'
});
|
Session
Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:
- 数据库(默认)
- 缓存
- 文件
- 缓存+数据库
- 加密cookie
1、数据库Session
2、缓存Session
3、文件Session
4、缓存+数据库Session
5、加密cookie Session
扩展:Session用户验证
1
2
3
4
5
6
7
|
def
login(func):
def
wrap(request,
*
args,
*
*
kwargs):
# 如果未登陆,跳转到指定页面
if
request.path
=
=
'/test/'
:
return
redirect(
'http://www.baidu.com'
)
return
func(request,
*
args,
*
*
kwargs)
return
wrap
|
分页
一、Django内置分页
![](https://oscimg.oschina.net/oscnet/be2d20b38fcb529d349408d5ca6b30c7825.gif)
![](https://oscimg.oschina.net/oscnet/1a59960011219c071e0e6256d79ccdfb465.gif)
![](https://oscimg.oschina.net/oscnet/b3c9dfbfd5c68fc5b299fb9326600802656.gif)
![](https://oscimg.oschina.net/oscnet/ff46ed331e657b9363262463b9c955d6e58.gif)
二、自定义分页
分页功能在每个网站都是必要的,对于分页来说,其实就是根据用户的输入计算出应该在数据库表中的起始位置。
1、设定每页显示数据条数
2、用户输入页码(第一页、第二页...)
3、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置
4、在数据表中根据起始位置取值,页面上输出数据
需求又来了,需要在页面上显示分页的页面。如:[上一页][1][2][3][4][5][下一页]
1、设定每页显示数据条数
2、用户输入页码(第一页、第二页...)
3、设定显示多少页号
4、获取当前数据总条数
5、根据设定显示多少页号和数据总条数计算出,总页数
6、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置
7、在数据表中根据起始位置取值,页面上输出数据
8、输出分页html,如:[上一页][1][2][3][4][5][下一页]
![](https://oscimg.oschina.net/oscnet/f6be236473663f16c4d2585d08fcb59b729.gif)
总结,分页时需要做三件事:
- 创建处理分页数据的类
- 根据分页数据获取数据
- 输出分页HTML,即:[上一页][1][2][3][4][5][下一页]
缓存
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。
Django中提供了6种缓存方式:
- 开发调试
- 内存
- 文件
- 数据库
- Memcache缓存(python-memcached模块)
- Memcache缓存(pylibmc模块)
1、配置
a、开发调试
![](https://oscimg.oschina.net/oscnet/9f341bfbc5171cd1bc0d7eabc1819e660c9.gif)
b、内存
![](https://oscimg.oschina.net/oscnet/32f99daab36d929e94a739f523e6b40bc1c.gif)
c、文件
![](https://oscimg.oschina.net/oscnet/5a6b9989d5b0dfb08146e12589e8be7665e.gif)
d、数据库
![](https://oscimg.oschina.net/oscnet/f731f8ad1d82d91498a8969e84f51f02596.gif)
e、Memcache缓存(python-memcached模块)
![](https://oscimg.oschina.net/oscnet/9707889fbd5ad0c7db246b2b0cdd89986ed.gif)
f、Memcache缓存(pylibmc模块)
![](https://oscimg.oschina.net/oscnet/835078952e1b0f66d273d974b1555762bc4.gif)
g. Redis缓存(依赖:pip3 install django-redis)
![](https://oscimg.oschina.net/oscnet/04683050b8211fd9b2dcbe5fc246a41d281.gif)
![](https://oscimg.oschina.net/oscnet/ea2cc2d614f3b0203208df492f71c6fe68f.gif)
2、应用
a. 全站使用
![](https://oscimg.oschina.net/oscnet/150c9755a08fb3031f1dfd9fa4dbf29b665.gif)
b. 单独视图缓存
![](https://oscimg.oschina.net/oscnet/416f07b9fb2823ae2aabe045fb428660f56.gif)
c、局部视图使用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
更多:猛击这里
序列化
关于Django中的序列化主要应用在将数据库中检索的数据返回给客户端用户,特别的Ajax请求一般返回的为Json格式。
1、serializers
1
2
3
4
5
|
from
django.core
import
serializers
ret
=
models.BookType.objects.
all
()
data
=
serializers.serialize(
"json"
, ret)
|
2、json.dumps
1
2
3
4
5
6
7
8
|
import
json
#ret = models.BookType.objects.all().values('caption')
ret
=
models.BookType.objects.
all
().values_list(
'caption'
)
ret
=
list
(ret)
result
=
json.dumps(ret)
|
由于json.dumps时无法处理datetime日期,所以可以通过自定义处理器来做扩展,如:
信号
Django中提供了“信号调度”,用于在框架执行操作时解耦。通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。
1、Django内置信号
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
Model signals
pre_init
# django的modal执行其构造方法前,自动触发
post_init
# django的modal执行其构造方法后,自动触发
pre_save
# django的modal对象保存前,自动触发
post_save
# django的modal对象保存后,自动触发
pre_delete
# django的modal对象删除前,自动触发
post_delete
# django的modal对象删除后,自动触发
m2m_changed
# django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
class_prepared
# 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
Management signals
pre_migrate
# 执行migrate命令前,自动触发
post_migrate
# 执行migrate命令后,自动触发
Request
/
response signals
request_started
# 请求到来前,自动触发
request_finished
# 请求结束后,自动触发
got_request_exception
# 请求异常后,自动触发
Test signals
setting_changed
# 使用test测试修改配置文件时,自动触发
template_rendered
# 使用test测试渲染模板时,自动触发
Database Wrappers
connection_created
# 创建数据库连接时,自动触发
|
对于Django内置的信号,仅需注册指定信号,当程序执行相应操作时,自动触发注册函数:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://oscimg.oschina.net/oscnet/206ff6c72d2fa30c18ab784f1d770d0cfd8.gif)
2、自定义信号
a. 定义信号
1
2
|
import
django.dispatch
pizza_done
=
django.dispatch.Signal(providing_args
=
[
"toppings"
,
"size"
])
|
b. 注册信号
1
2
3
4
5
|
def
callback(sender,
*
*
kwargs):
print
(
"callback"
)
print
(sender,kwargs)
pizza_done.connect(callback)
|
c. 触发信号
1
2
3
|
from
路径
import
pizza_done
pizza_done.send(sender
=
'seven'
,toppings
=
123
, size
=
456
)
|
来源:oschina
链接:https://my.oschina.net/u/4409224/blog/4088464