Django 系统
- 环境
- Python 3.6
- Django 1.8
- 参考资料
- [Django中文教程](https://yiyibooks.cn/xx/django_182/index.html)
- [Python 新手使用 - Django 架站的16堂课](实体书)
环境搭建
- anaconda + pycharm
- anaconda使用
- conda list : 显示当前环境安装的包
- conda env list : 显示安装的虚拟环境列表
- conda create -n env_name python=3.6 如:conda create -n tl_django python=3.6
- 激活conda的虚拟环境
- source activeate env_name (Linux下激活)
- conda activate env_name (Windows下激活) 如: conda activate tl_django
- 激活的含义是:进入某环境专用命令行界面, 并针对该环境进行设置
- Django安装:
- conda activate tl_django (首先激活Django的环境, PS:激活后命令行前面回带一个(tl_django)这样的前缀)
- pip install django==1.8
后台流程
创建第一个Django程序
- django-admin startproject tulingxueyuan (创建Django项目: tulingxueyuan)
命令行启动:
- cd tulingxueyuan
- python manage.py runserver (启动服务器)
PyCharm启动
- 1.配置python环境:
- 点击File菜单 -> Settings -> Project:Python -> Project Interpreter-> “小齿轮”图标 -> ADD -> Conda Environment -> Existing environment-> “...” 图标 ->
- Linux系统:
Anaconda安装路径下的/envs/相应的虚拟环境名称/bin/python.sh - Windows系统:
1、 C:\Users\用户名\Anaconda3\envs\相应的虚拟环境名称\python.exe
2、 C:\ProgramData\Anaconda3\envs\相应虚拟环境名称\python.exe
3、 C:\Users\rocka.conda\envs\相应虚拟环境名称\python.exe
Windows情况有点特殊,我分别在以上三个位置找到过。 - 注意:刚刚配置好的环境,PyCharm还会把各种包整理一下,当IDE主界面右下方有一条细细的进度条在跑的时候,说明环境还在Update中尚未准备就绪,程序中某些import 包的语句还会被语法提示器认为是错误语句,此时要耐心等待。
- Linux系统:
- 点击File菜单 -> Settings -> Project:Python -> Project Interpreter-> “小齿轮”图标 -> ADD -> Conda Environment -> Existing environment-> “...” 图标 ->
- 2.配置manage.py文件:
- 鼠标指向manage.py文件-> 直接点运行 -> 将会报错
- 此时需要点界面右上角下拉菜单(位于启动按钮左边) -> 选 Edit Configurations ->在Parameters输入参数: runserver -> 确定 -> 出来后点运行即可
路由系统 - urls
- 创建app
- app: 负责一个具体业务或者一类具体业务的模块
- python manage.py startapp teacher (在app根目录下执行,生成一个teacher的目录,即teacher路由)
- 路由
- 按照具体的请求url, 导入到相应的业务
- django的信息控制中枢
-
本质上就是接受URL和相应的处理模块的一个映射
- 在接受URL请求的匹配上使用了RE
- URL的具体内容在urls.py文件中 (阅读该文件的代码,发现内部是使用正则在处理URL和对应模块的对应关系)
- 需要关注的两点:
- 接受的URL是什么, 即如何用RE对传入的URL进行匹配
- 已知URL匹配到哪个处理模块
- URL匹配规则:
- 从上到下一个一个比对
- URL格式是分级格式,则按照级别一级一级往下比对,主要对应URL包含子URL的情况
- 子URL一旦被调用,则不会返回到主URL
- '/one/two/three/'
- 正则以r开头, 表示不需要转义, 注意尖号(^)和美元符号($)
- '/one/two/three' 配对正则: r'^one/'
- '/oo/one/two/three' 不配对正则: r'^one/'
- '/one/two/three/' 配对正则: r'^three/$
- '/oo/one/two/three/oo/' 不配对正则: r'three/$'
- 第一个反斜杠并不需要(系统自动忽略)
- 如果从上到下都没有找到合适的匹配内容,则报错
2. 正常映射
- 把某一个符合RE的URL映射到事务处理函数中去
- 举例如下:
from showeast import views as sv urlpatterns = [ url(r'admin/',adming.site.urls), url(r'^normalmap/', sv.normalmap), ]
3.URL 中带参数映射
在多事件处理代码中需要由URL传入参数,形如/myurl/param中的param
参数都是字符串形式,如果需要整数等形式需要自行传唤
-
统称的形式如下:
/search/page/432 中的432需要经常性变化内容,就是参数
-
一个较为复杂的例子:
url(r'^withparam/(?P<year>[0-9])/(?P<month>[0,1][0-9)',tv.withparam)
- 尖号表示从字符串左边第一个字符开始匹配
- 圆括号表示的是一个参数,里面的内容作为参数传递给被调用的函数
参数名称以问号加大写P开头吗,尖括号里面就是参数的名字
后面花括号表示出现的次数,此处的4 表示只能出现4个0-9的数字
4. URL在APP中处理
如果所有应用URL都集中在tulingxueyuan/urls.py中,可能导致文件臃肿
可以把urls具体功能逐渐分散到每个app中
- 从djanco.conf.urls导入include
- 注意此时RE部分的写法
- 添加include 导入
- 使用方法:
确保include被导入
- 在根目录的urls.py中写url (1个功能模块只对应1个url)
- 写子路由 (功能模块里的子模块,在各自的文件夹内的:模块名_url.py内添加)
- 编写各个功能模块的views函数,包括各个子路由的views函数
- 与直接在主urls.py中写理由一样,分散在各个模块文件夹下面写独立的子路由,同样可以使用参数
5. URL中嵌套参数
- 捕获某个参数的一部分
- 例如URL /index/page-3 , 需要捕获数字3作为参数
- url(r'index_1/(page-(\d+)/)?$, sv.myindex_1)
- url(r'index_2/(?:page-(?P<page_number>\d+)/)?$', sv.myindex_2)
- url(r'^book/page-(?P<pn>\d)/$', tv.do_param2)
- 以上就是指从一个参数中再提炼一个参数(我个人认为第三个正则更简单明了一些)
6. 传递额外的参数
- 参数不仅仅来自于URL, 还可能是我们自己定义的内容
url(r'extrem/$',sv.extremParam,{'name':'liuying'}), - 附加参数同样适用于include语句, 此时对include内所有都添加.
7.URL的反向解析 reverse
- 防止硬编码
- 本质上是对每一个URL进行命名
- 以后在编码代码中使用URL的值,原则上都应该使用反向解析
- reverse的好处是,只要给一个路由设好名字, 无论URL怎么变, 都可以用名字来引用,方便,主要用于模版
VIEWS 视图
1. 视图概述
- 视图即视图函数,接受WEB请求返回WEB相应的事务处理函数.
- 响应指符合http协议要求的任何内容,包括json, string, html等
- 本章忽略事务处理, 重点在如何返回处理结果上
2. 其他简单视图
- django.http为我们提供了很多和HttpResponse类似的简单视图,
通过查看django.http的源代码我们直到. - 此类视图使用方法基本类似,可以通过return语句直反馈给浏览器
- Http404为Exception子类, 所以需要用raise来显式调用
- Debug模式的关闭:
- 打开根路径下settings.py文件
- 将Debug = True 改为 False
- ALLOWED_HOSTS 改为 ["*"] (允许所有主机访问)
3. HttpResponse详解
- 方法:
- init : 使用页内容实例化HttpResponse对象
- write(content) : 以文件的方式写
- flush(): 以文件的方式输出缓存区
- set_cookie(key, value='', max_age = none,expires = None): 设置cookie
- key , value 是字符串类型
- max_age 是一个整数, 表示在指定秒数后过期
- expires 是一个datetime或timedelta对象, 会话将在这个指定的日期/时间过期
- max_age 和 expires , 二选一
- 如果不指定过期时间,则两个星期后过期
- delete_cookie(key): 删除指定的key的Cookie, 如果key不存在, 也不会报错
4. HttpRespnseRedirect
- 重定向, 服务器端跳转
- 构造函数的第一个参数用来指定重定向的地址
- 例子: ShowViews/views.py
- 在east/urls中添加以下内容:
url(r'^v10_1/', views.v10_1),
url(r'^v10_2/', views.v10_2),
url(r'^v11/"' views.v11, name = "v11"),
# /east/ShowViews/views 中添加以下内容
def v10_1(request):
return HttpRespnseRedirect("/v11")
def v10_2(request):
return HttpRespnseRedirect(reverse("v11"))
def v11(request):
return HttpRespnseRedirect(""这是v11 的返回值")
5.Request 对象
-
Request介绍
- 服务器接受到http协议的请求后,会根据报文创建HttpRequest对象
- 视图函数的第1个参数就是HttpRequest对象(在Python中,形参只跟位置相关,而跟具体的参数名无关,例如self亦是如此)
- 在django.http模块中定义了HttpRequest对象的API
-
属性
- 下面除非特别说明,属性都是只读的 (就像你给张三写一封信, 张三收到后就已经没有修改的意义了)
- path : 一个字符串, 表示请求页面的完整路径, 不包含域名
- method : 一个字符串,表示使用的HTTP方法,常用时包括:'GET'/'POST'
- encoding : 一个字符串,表示提交的数据的编码方式
- 如果为None则表示使用浏览器的默认设置,一般为utf-8
- 这个属性是可写的,可以通过修改他来修改访问表单数据使用的编码
- GET : 一个类似字典的对象, 包含get请求方式的所有参数
- POST : 一个类似字典的对象, 包含post请求方式的所有参数
- FILES : 一个类似字典的对象, 包含所有的上传文件
- COOKIES : 一个标准的Python字典, 包含所有cookie, 键和值都包含其中
- session: 一个即可独有可写的类似于字典的对象,表示当前会话.
- 只有当Django启用会话时才可用.
- 详细内容见"状态保持".
-
方法
- is_ajax() : 如果请求是通过XMLHttpRequest发起的,则返回True
-
QueryDict 对象 [这个是Django特设的对象,HTTP本身没有]
- 定义在django.http.QueryDict里
- request对象的属性GET, POST都是QueryDict类型的对象
- 与Python 字典不同,QueryDict类型的对象用来处理同一个键带多个值的情况.
- 方法get(): 根据键取值
- 只能获取键的一个值
- 如果一个键同时拥有多个值,获取最后一个值
- 方法getlist():根据键获取值
- 将键的值以列表返回,可以获取一个键的多个值
-
GET属性 [此对象对应http协议的GET操作]
- QueryDict类型的对象
- 包含get请求方式的所有参数
- 与url请求地址中的参数队形,位于?后面
- 参数的格式是键值对,如key1 = value1
- 多个参数之间,用&链接,如key1=value1&key2=value2
- 键是开发人员定下来的,值是可变的
- 例子: ShowViews/views/v8_get
-
POST 属性
- QueryDict类型的对象
- 包含post请求方式的所有参数
- 与form表单中的空间对应
- 表单中的控件必须有name属性,name为键,value为值
- checkbox存在一键多值的问题
- 键是开发人员定下来的,值是可变的
- 例子 ShowViews/views/v9_post
- setting中设置模版位置, 在根目录下建立一个templates文件夹,然后在setting.py里修改为:
*('DIRS': [os.path.join(BASE_DIR,"templates")],)
- setting中CRSF跨站攻击防护要关闭,此行需要注释掉)
> * django.middleware.csrf.CsrfViewMiddleware',
- 设置get页面的urls和参数
需要在路由文件中添加两个路由:
> * url(r'^v9_get/', v.v9_get),
> * url(r'^v9_post/', v.v9_post),
- setting中设置模版位置, 在根目录下建立一个templates文件夹,然后在setting.py里修改为:
-
手动编写视图
实验目的:
利用django快捷函数手动编写视图处理函数
编写过程中理解视图运行原理
VIEW的目的:
1.. 业务处理
2.. 返回Respongse子类步骤:
1. 拿到模版
2. 拿到数据
3. 环境变量(插入到HTML代码中,以此定位数据填充的位置)
4. 返回-
分析:
- django把所有请求信息封装入request
- django通过URLS模块把相应请求跟时间处理函数链接起来, 并把request作为参数传入.
- 在相应的处理函数中,我们需要完成两部分
- 处理业务
- 把结果封装并返回,我们可以使用简单HttpResponse, 同样也可以自己处理此功能
- 本例子不介绍业务处理, 把目光集中在如何渲染结果并返回
-
render(request, templater_name [,context][,context_omstamce][,content_type])
- 使用模版和一个戈丁的上下文环境,返回一个渲染后的HttpResponse对象
- request: django的传入请求
- templater_name : 模版名称
- content_instance : 上下文环境
- 参见例子: teacher_app/views/render_test
-
render_to_response
- 根据给定的上下文字典渲染给定模版,返回渲染后的HttpResponse
- 参见例子: teacher_app/views/render4_test
-
系统内建视图
- 系统内建视图,可以直接使用:
- 404
- default.page_not_found(request, template_name = '404.html')
- 系统引发Http404时触发
- 默认窗体request_path变量给模版,即导致错误的URL
- DEBUG = True则不会调用404, 取而代之是调试信息
- 404视图会被传递到一个RequestContext帝乡宁切可以访问模版上下文处理器提供的变量.
- 500
- default.server_error
- DEBUG = True 不触发
- 403
- default.permission_denied
- DEBUG = True 不触发
- 500
- default.bad_request
- DEBUG = True 不触发
Models 模型 (ORM)
- ORM
- Object Relation Map(对象关系映射) : 把面向对象思想转换成关系数据库思想.操作上把类等价于表格
- 类对应表格
- 类中的属性对应表中的字段
- 在应用中的models.py文件中定义class
- 所有需要使用ORM的class都必须是 models.Model 的子类
- class中的所有属性对应表格中的字段
- 字段的类型都必须使用 models.xxx 不能使用python中的类型
-
在django种,Models负责跟数据库交互
Django 链接数据库
- 自带默认数据库Sqllite3
- 关系型数据库
- 轻量级
- 建议开发用sqlite3, 部署用mysql之类数据库
- 切换数据库在settings中进行设置
-
用django 连接 mysql
DATABASES = [ 'default' = { 'ENGINE' : 'django.db.backends.mysql', 'NAME' : '数据库名', 'PASSWORD' : '数据库密码', 'HOST' : '127.0.0.1', 'PORT' : '3306', } ]
- django 连接 mysql需要在项目文件下的init文件中导入pymysql包
- import pymysql
- pymysql.install_as_MySQLdb()
models类的创建与使用
-
定义和数据库表映射的类
- 在应用中的models.py文件中定义class [每一个app下面都有这个文件]
- 所有需要使用ORM的class都必须是 models.Model 的子类
- class中的所有属性对应表格中的字段
- 字段的类型都必须使用 modles.xxx 不能使用python中的类型
-
字段常用参数
- max_length : 规定数值的最大长度
- blank : 是否允许字段为空,默认不允许
- null : 在DB中控制是否保存为null, 默认为false
- default : 默认值
- unique : 唯一
- verbose_name : 假名
-
数据库的迁移(在models里创建类后通知数据库)
- 在命令行中,生成数据迁移的语句(生成sql语句)
- python manage.py makemigrations
- 在命令行中,输入数据迁移的指令
- python manage.py migrate
- 如果迁移中没有变化或者报错,可以强制迁移
- python manage.py makemigrations 应用名
- python manage.py migrate 应用名
- 对于默认数据库,为了避免出现混乱,前提是数据库中没有数据,可以删除自定义app下的migrations文件夹和db.sqlites3数据库
- 如果报错,显示"App 'APP名字' could not be found. Is it in INSTALLED_APPS?", 说明没有在settings.py里注册:
INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'teacher', # 把自定义的app填进去 'orm', )
查看数据库中的数据
- 1.启动命令行:python manage.py shell
注意点:对orm的操作分为静态函数和非静态函数两种,静态函数是指在内存中类共用的,非静态函数是指每个实例掌握的 - 2.在命令行中导入对应的映射类
- from app名.models import 类名
- 一个完整的例子:
from teacher.models import Teacher
dana = Teacher()
dana.name = "Dana"
dana.age = 18
dana.address = "北京图灵学院"
dana.save() # 保存
ta = Teacher.objects.all() # 返回集合
ta[0].name # 访问name属性,显示: Dana
ta[0].age # 访问age属性,显示: 18
ta[0].address # 访问address属性,显示: '北京图灵学院'
ta[0].course # 访问course属性,显示为空
- 如上操作向Teacher表中增加几条记录之后,用for循环遍历:
for t in ta:
print("Name: {0}, Age{1},Address:{2},Course:{3}".format(t.name,t.age,t.address,t.course))
显示结果:
Name: Dana, Age18,Address:北京图灵学院,Course:
Name: Daozhang, Age45,Address:程度小北路,Course:
Name: WangGonh, Age29,Address:,Course:Java
- 查询age=45的记录
- ta = Teacher.objects.filter(age=45)
- ta <BR>
直接输入ta回车,显示ta的内容,age=45的记录只有一个就是daozhang, 显示为:<BR>[<Teacher: Daozhang>]
- 3.使用object属性操作数据库,object是模型中实际和数据进行交互的
- 4.查询命令
- 类名.objects.all()查询数据库表中的所有内容,返回的结果是一个QuerySet查询集合类型
- 类名.object.filter(条件)
- 常见查找方法
- 通用查找格式:属性名__条件符号=值
- 例如, 查找所有age大于18的记录:
ta = Teacher.objects.filter(age__gt > 18) - 条件符号有:
- gt:大于
- gte:大于等于
- lt:小于
- lte:小于等于
- range:范围
- year:年份
- isnull:是否为空
- 2、查找等于指定值的格式:属性名=值
- 3、模糊查找:属性名__查找方式=值
- 查找course中包含字母T的老师<BR>
ta = Teacher.objects.filter(course__contains = "T") - 查找方式有:
- exact:精确等于
- iexact:不区分大小写
- contains:包含
- startwith:以..开头
- endwith:以..结尾
数据库表关系
- 多表联查:利用多个多联合查找某一项信息或者多项信息
-
1:1 OneToOne
- 建立关系:在模型任意一边即可,使用OneToOneField
- add: (增)有两种方式:
- 实例化方法,直接实例化保存
- create方法,返回类型是<class 'rlt.models.Manager'>,推荐这种方法
- PS: 添加有关系的一边,使用create方法,或者使用实例创建
- 例如:
s = School() s.school_id = 2 s.school_name = "nanjingtulingxueyuan" s.save() #方法1:直接实例化 m =Manager() m.manager_id=10 m.manager_name = "dana" m.my_school=s m.save() #方法2:使用create m = Manager.objects.create(manager_id=20,manager_name="erna",my_school=s)`
- query: (查)
- 由子表查母表(定义关系的表叫子表),由子表的属性直接提取信息:
m = Manager.objects.get(manager_name="dana") m <Manager: dana> m.my_school <School: nanjing tulingxueyuan> m.my_school.school_name 'nanjing tulingxueyuan' # 查询成功
- 又或者可以把上述操作串起来一次性操作:
Manager.objects.get(manager_name="dana").my_school.school_name 'nanjing tulingxueyuan' # 查询成功
- 由母表查子表,使用双下划线:
s = School.objects.get(manager__manager_name="dana") s <School: nanjing tulingxueyuan> # 查询成功
- 由子表查母表(定义关系的表叫子表),由子表的属性直接提取信息:
- change:(改)
- 单个修改后使用save保存
s.school_name = "南京图灵学院" s.save() s <School: 南京图灵学院> # 修改成功
- 批量修改使用update
ss = School.objects.all() ss.update(school_name="图灵学院") ss [<School: 图灵学院>, <School: 图灵学院>] # 批量修改成功
- 无论是对子表还是母表修改方法都一样
- 单个修改后使用save保存
- delete:直接使用delete删除
-
1:N OneToMany
- 一个表格的一个数据项/对象等,可有很多个另一个表格的数据项
- 比如,一个学校可有很多个老师,一般一个老师只会在一个学校上课
- 使用上
- 使用ForeignKey
- 在多的那一边,比如上面的例子就是在Teacher表格里进行定义
- add: (增)
- 跟一对一方法类似,通过cerate和new来添加
- create:把属性都填满,然后不需要手动保存
- new(也就是实例化方法):可以属性或者参数为空,必须用save保存
- query:
- 以学校和老师举例
- 如果知道老师,查学校,则通过增加的关系属性,直接使用
- 例如:查找t1老师是哪个学校的:
t1.teacher_name '刘大拿' t1.my_school <School: 图灵学院>
- 反查
- 由学校,想查下这个学校所有老师,则在学校后跟老师这个类(类名称小写)接下划线set来表示
- 可以简单理解成teacher_set是School类里的一个隐藏属性
- 例如,查询1号学校下面有多少个老师:
ts = s1.teacher_set.all() ts [<Teacher: Teacher object>, <Teacher: Teacher object>] ts[0].teacher_name '刘大拿'
- 又或者精确查找:
t = s1.teacher_set.all().filter(teacher_name="刘大拿") t[0].teacher_name '刘大拿'
-
N:N ManyToMany
- 表示任意一个表的数据可以拥有对方表格多项数据,反之亦然
- 比如典型例子就是老师和学生,老师可以有多个学生,学生也可以有多个老师
- 使用上,在任意一方,使用ManyToMany定义,只需要定义一边
- add:
- 添加老师,则在Student实例.teachers.add(),也可以用create方法
- 注意,用实例添加多对多数据,需要两次save
s1 = Student() s1.student_name = "aoteng" s1.save() t1 = Teacher.objects.all()[0] s1.teachers.add(t1) s1.save() t = s1.teachers.all() t[0].teacher_name '刘大拿'
- 添加老师,则在Student实例.teachers.add(),也可以用create方法
- query:
- 跟一对多类似,使用隐含属性set查询
t1 = Teacher.objects.all()[0] ss = t1.student_set.all() ss[0].student_name 'aoteng'
- 注意:如果想实现双向互查,必须在类代码里面两边都相互添加一行:
models.ManyToManyField
s1 = Student.objects.all()[0] tt = s1.teacher_set.all() tt[0].teacher_name '刘大拿'
- 跟一对多类似,使用隐含属性set查询
-
模版(Template)
- 模板:一组相同或者相似的页面,在需要个性化的地方进行留白,需要的时候只是用相应数据进行填充
- 步骤
- 在settings.py中进行设置:TEMPLATES
- 在templates文件夹下编写模板并调用
一个最简单的完整的例子: 1. 激活环境: activate tl_django 2. 创建项目: django-admin startproject django_tpl 3. 创建app: python manage.py startapp mytpl 4. 在项目的根目录下建立一个templates的目录 5. 在templates目录下新建一个one.html文件,内容如下: <html> <body> <h1>Hello World!</h1> </body> </html> 6. 编辑Django系统自带的settings.py文件: 找到Templates下的DIR位置,修改为: 'DIRS': [os.path.join(BASE_DIR, "templates")], 7. 为manager.py添加启动变量runserver (仅限Pycharm环境) 8. 编辑Django系统自带的urls.py: 在头部添加包引用:import mytpl.views as v (如果这行Pycharm出红线,就选File菜单的Invalidate Caches/Restart, 重启后鼠标单击项目目录,Mark Directory As -> Sources Root 如果有很多个Sources Root(Root目录的颜色不同),取消其他的, 确保只有一个Root且必须是当前目录) 最后在下方依葫芦画瓢添加一个路由:url(r'^one/', v.one), 9. 打开mytpl下的views.py 在头部添加包引用:from django.http import HttpResponse 添加一个函数one: def one(request): return render(request,r"one.html") 10. 运行manage.py 11. 在浏览器输入:127.0.0.1:8000/one
- 步骤
模板-变量
- 变量的表示方法:{{var_name}}
- 在系统调用模板的时候,会有相应的数据查找相应的变量名称,如果找到,则填充也叫渲染,否则跳过
- 参见例子:two.html
模板-标签
-
for标签:
{% for .. in .. %} 循环语句 {% endfor %}
参见例子:three.html,显示班级成绩
-
if标签,用来判断条件
{% if 条件 %} 条件成立执行语句 {% elif 条件 %} 条件成立执行语句 {% else %} 以上条件都不成立执行语句 {% endif %}
参见例子:four.html
csrf标签,跨站请求伪造
- 在提交表单的时候,表单页面需要加上{% csrf_token %}
- 参见例子five_get请求表单地址, five_post发送表单信息地址
- 原理:
- 浏览器提交一个get请求到服务器,服务器返回一个带csrf_token的form回浏览器
- 此时浏览器正常提交form,隐含提交了csrf_token
- 服务器验证这个新提交上来的csrf_token是否刚才服务器自己生成的那个csrf_token?
- 如果csrf_token不一致,说明本次提交是伪造的
- 在settings.py:
- 'django.middleware.csrf.CsrfViewMiddleware', 是控制csrf_token的开关,
- 如果此选项关闭,则不对csrf_token进行检查,反之则一定会检查,如果打开了此设置但是在html代码里又不含{% csrf_token %},则将报错: CSRF token missing or incorrect.
SESSION
- 为了应对HTTP的无协议性
- 用来保存用户比较敏感的信息
- 他是属于request的一个属性
- 常用操作:
- request.session.get(key,defaultValue)
- request.session.clear():清除全部
- request.session[key] = value : 赋值
- request.session.flush() : 删除当前会话并清除会话的cookie
- del request.session[key]
分页
- django提供现成的分页器用来对结果进行分页
- from django.core.paginator import Paginator
Ajax
8. 基于类的视图
- 和基于函数的视图的优势和区别:
- http方法的methode可以有各自的方法,不需要使用条件分支来解决
- 可以使用OOP技术(例如Mixin)
- 概述
- 核心是允许使用不同的实例方法来响应不同的HTTP请求方法,而避开条件分支实现
- as_view函数作为类的可调用入库,该方法创建一个实例并调用dispatch方法,按照请求方法对请求进行分发,如果该方法没有定义,则引发HttpResponseNotAllowed
- 类属性使用
- 在类定义时直接覆盖
- 在调用as_view的时候直接作为参数使用,例如:
urlpatterns = [ url(r'^about/', GreetingView.as_view(greeting="Greetxxx")), ]
- 对基于类的视图的扩充大致有三种方法: Mixin, 装饰as_view, 装饰dispatch
- 使用Mixin
- 多继承的一种形式,来自弗雷的行为和属性组合在一起
- 解决多继承问题
- View的子类只能单继承,多继承会导致不可期问题
- 多继承带来的问题:
- 结构复杂
- 优先顺序模糊
- 功能冲突
- 解决方法
- 规格继承 # java interface
- 实现继承 # python,ruby
- 使用Mixin
- 在URLconf中装饰
from django.contrib.auth.decorators import login_required, permission_required
from django.views.generic import TemplateView
from .views import VoteView
urlpatterns = [
url(r'^about/', login_required(TemplateView.as_view(template_name="secret.html"))),
url(r'^vote/', permission_required('polls.can_vote')(VoteView.as_view())),
]
- 装饰类
- 类的方法和独立方法不同,不能直接运用装饰器,需要用methode_decorator进行装饰
from django.contrib.auth.decorators import login_required from django.utils.decorators import method_decorator from django.views.generic import TemplateView class ProtectedView(TemplateView): template_name = 'secret.html' @method_decorator(login_required) def dispatch(self, *args, **kwargs): return super(ProtectedView, self).dispatch(*args, **kwargs)
Admin管理模块 (可以理解为Django自带的可定制型phpMyAdmin)
- 首先进行数据迁移,然后创建一个超管帐号
python manage.py makemigrations python manage.py migrate python manage.py createsuperuser
- settings.py里面改为汉语:
LANGUAGE_CODE ='zh-Hans' #'en-us' TIME_ZONE = 'Asia/Shanghai' #'UTC'
- 最后在浏览器输入:127.0.0.1/admin
- 进入管理界面后,只有一个空的项目和User和Group表可以管理,
- 在模型建立完毕后,界面会增加很多内容,可以设置各个模型(也就是数据库的表,这里称为模型)
- 先在models.py里建立3个模型:ClassRoom、Teacher、Student
from django.db import models
# Create your models here.
class ClassRoom(models.Model):
roomID= models.IntegerField()
loc = models.CharField(max_length=20)
roomName = models.CharField(max_length=20)
def __str__(self):
return self.roomName
class Teacher(models.Model):
name = models.CharField(max_length=5)
course = models.CharField(max_length=20)
room = models.OneToOneField(ClassRoom)
def __str__(self):
return self.name
class Student(models.Model):
name = models.CharField(max_length=20)
age = models.IntegerField()
room = models.ForeignKey(ClassRoom)
def __str__(self):
return self.name
- 记得模型建立后,还需要进行一次完整的数据迁移才会真正在数据库中建表
2. 绑定管理模型
- 在app目录下修改admin.py:
admin.site.register(Student, StudentAdminInfo) admin.site.register(ClassRoom, ClassRoomAdminInfo) admin.site.register(Teacher, TeacherAdminInfo)
3. 设置admin管理类
-
实现方式(包括显示、增、删、改都集成在里面了)
- ModelAdmin
- 在admin.py里为每个模型添加管理类:
class ClassRoomAdminInfo(admin.ModelAdmin): pass class TeacherAdminInfo(admin.ModelAdmin): pass class StudentAdminInfo(admin.ModelAdmin): pass
- 装饰器
list_per_page : 修改页面显示数量:
actions_on_top/buttom :操作选项在屏幕上方还是下方
list_display=[] : 控制列表中显示的内容:
-
以上设置都在admin.py的管理类里面修改:
class TeacherAdminInfo(admin.ModelAdmin): list_per_page = 2 actions_on_top = False actions_on_bottom = True list_display = ["name","room"]
-
除了显示字段外,还可以将方法作为列显示:
- 函数必须有返回值
- short_description : 设置作为显示内容
- admin_order_field : 排序绑定
- PS:默认情况下,点击列的标题,可以以列为依据排序,但是以方法作为列是不能排序的,<BR>
这种情况下也可以为它绑定一个列,起到排序的功能 - 在Teacher类里面加入以下代码:
# 定义一个方法,这个方法可以作为列显示 def curTime(self): return time.time() curTime.short_description = "当前时间" # 如果不设此行,默认显示为类名curTime curTime.admin_order_field = "name" # 以字段名name为排序依据
-
关联对象(多表显示)
- 使用方法
- 在Teacher类里面加入以下代码:
def getRoomName(self): return self.room.roomName # 因为Teacher和ClassRoom是一对一关系,因此Teacher里可以访问ClassRoom的字段 getRoomName.short_description = "教室"
-
搜索功能 (search_fields)
- 在admin.py文件的TeacherAdminInfo里面增加:
search_fields = ["name"] # 搜索 name 列
- 界面将会出现一个搜索框,并以name列为条件搜索
-
字段屏蔽 - fields
- 默认情况下,字段是全部显示的,但是,也可以屏蔽
- 同样的,在TeacherAdminInfo里面增加:
fields = ["name","course"] # 只显示name和course,屏蔽了Room
-
分组设置 - fieldsets
- 为了方便管理和让显示效果更好,字段也可以分组:
- 在TeacherAdminInfo里面增加元组fieldsets:
# fields = ["name", "course"] fieldsets = ( ("基本信息", {"fields": ["name", ]}), ("其他信息", {"fields": ["room", "course"]}), )
- 特别注意:fields和fieldsets不能共存,否则报错。
-
其他设置 - admin.site
- 在admin.site下有许多设置,可以控制站点信息
admin.site.site_header = "这是站头" admin.site.site_title = "这是站标题" admin.site.index_title = "这是首页标语"