Python视频学习(十二、Django)
目录
- 0 背景
- 0.1 MVC框架
- 0.2 Django
- 1. 虚拟环境
- 2. ★第一个Django案例
- 2.1 创建项目
- a. 创建项目
- 项目目录说明
- b. 创建app
- 目录说明
- c. 安装应用
- d. 运行测试服务器
- 2.2 ORM操作
- a. 定义模型类——继承models.Model
- `on_delete`
- b. 数据迁移—— `manage.py makemigrations, migrate`
- 默认数据库
- 生成字段名
- 生成表名——app名_类名
- c. ★操作数据—— `manage.py shell`
- 操作关系字段
- 2.3 后台管理操作——`admin`
- a 界面本地化
- b 创建管理员—— `manage.py createsuperuser`
- c. 注册模型类
- d. 自定义管理页面
- 2.4 视图初级(MVC中的C)
- a. 定义视图函数
- b. ★配置url
- 页面url地址设置
- 2.5 模板初级(MVC中的V)
- a. 创建模板目录和文件
- b. 配置模板路径
- c. 模板文件内代码书写
- d. 视图中调用模板
- ★使用快捷方式
- 3. ★模型高级——ORM
- 3.1 配置MYSQL数据库
- a. 配置数据库信息
- b. 安装mysql数据库的包
- c. 添加install mysql
- 3.2 常用字段和参数
- a. 属性命名限制
- b. 字段类型
- c. 常用参数
- 3.3 ★条件查询
- a. 查看MySQL日志文件
- a. 查询函数
- b. ★条件运算符
- c. 排序——order_by
- d. ★Q对象——逻辑关系
- e. ★F对象——属性之间的比较
- f. 聚合函数——aggregate、count
- 3.4 ★查询集QuerySet
- a. 返回查询集的方法
- b. 查看查询集是否有数据——`exist`
- c. 查询集的特点
- d. 查询集切片
- 3.5 模型类关系——一对一、多对多、一对多
- 3.6 ★关联查询
- a. 查询关联对象
- b. ★关联查询写法
- c. 自关联查询 模型定义
- 3.7 ★管理器——models.Manager
- a. 自定义管理器类的应用场景
- b. 自定义管理器对象
- 3.8 元选项——指定表名
- 4. 视图高级
- 4.1 URL匹配过程
- 4.2 获取url参数
- a. 位置参数
- b. 关键字参数
- 4.3 ★错误视图
- 4.4 ★HttpRequest对象
- a. ★QueryDict对象
- 4.5 HttpResponse对象
- JsonResponse
- HttpResponseRedirect
- 5. ★cookie和session
- 5.1 cookie
- a.cookie的特点
- b. 设置cookie—— `response.set_cookie`
- c. 获取cookie —— `request.COOKIES`
- 5.2 session
- a. session的特点
- b. 启用Session
- c. 存储方式
- d. ★使用session —— `request.session`
- e. 配置Redis的Session
- 6. 模板高级
- 6.1 模板的原始使用
- 6.2 模板文件加载顺序
- 6.3 ★模板变量
- 6.4 ★模板标签 templatetag
- for 循环
- if 判断
- 6.5 ★过滤器
- 内建过滤器
- 自定义过滤器
- 6.6 模板注释
- 6.7 模板继承
- 6.8 HTML转义
- 关闭模板文中的转义
- 6.9 ★装饰器来显示必须登录才能访问
- 6.10 CSRF 攻击
- a. 攻击原理
- b. django防止CSRF的方法
- c. django的CSRF防御原理
- 6.10 验证码
- 看不清,换一个图片
- 6.11 ★URL反向解析
- a. 模板超链接使用 URL反向解析
- b. 视图中使用重定向反向解析url
- 7. 其他常用技术
- 7.1 使用静态文件
- a. ★动态获取静态文件路径
- b. 静态文件查找顺序
- 7.2 ★中间件
- a. 调用流程
- 案例——返回 请求的IP地址
- b. ★使用中间件
- 7.3 Admin后台管理
- a. 注册模型管理类
- b. 列表页选项
- b. 编辑页选项
- c. 综合代码
- d. 修改admin页面模板
- 7.4 上传文件
- a. 后台上传图片
- b. 客户端上传图片
- c. 解决无迁移问题
- 11.5 分页
0 背景
0.1 MVC框架
软件框架是由其中的各个模块组成的,每个模块负责特定的功能,模块与模块之间相互协作来完成软件开发。软件框架的设计,也是针对某一类软件问题而设计的,其目的主要是提高软件开发效率。
MVC框架的核心思想是:解耦,让不同的代码块之间降低耦合,增强代码的可扩展性和可移植性,实现向后兼容。
- M 全拼为Model,主要封装对数据库层的访问,对数据库中的数据进行增、删、改、查操作。
- V 全拼为View,用于封装结果,生成页面展示的html内容。
- C 全拼为Controller,用于接收请求,处理业务逻辑,与Model和View交互,返回结果。
0.2 Django
Django的主要目的是简便、快速的开发数据库驱动的网站。它强调代码复用,多个组件可以很方便的以"插件"形式服务于整个框架,Django有许多功能强大的第三方插件,你甚至可以很方便的开发出自己的工具包。这使得Django具有很强的可扩展性。它还强调快速开发和DRY(DoNotRepeatYourself)原则。
django官方网站
django源码
Django框架遵循MVC设计,并且有一个专有名词:MVT
- M:全拼为Model,与MVC中的M功能相同,负责和数据库交互,进行数据处理。
- V:全拼为View,与MVC中的C功能相同,接收请求,进行业务处理,返回应答。
- T:全拼为Template,与MVC中的V功能相同,负责封装构造要返回的html。
1. 虚拟环境
虚拟环境是真实python环境的复制版本。
在虚拟环境中使用的python是复制的python,安装python包也是安装在复制的python中。
安装好virtualenv后在.bashrc
中添加下面2行:
export WORKON_HOME=$HOME/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh
命令 | 含义 |
---|---|
sudo pip install virtualenv
|
安装虚拟环境 |
sudo pip install virtualenvwrapper
|
安装虚拟环境扩展包 |
export WORKON_HOME=$HOME/.virtualenvs
|
在配置文件中设置 WORKON_HOME
|
mkvirtualenv 虚拟环境名
|
创建虚拟环境 |
mkvirtualenv -p python3 环境名
|
创建指定python版本的虚拟环境 |
workon 虚拟环境名
|
进入虚拟环境 |
workon tab-tab
|
查看所有环境 |
deactivate
|
退出当前虚拟环境 |
rmvirtualenv 虚拟环境名
|
删除虚拟环境: |
pip install 包名
|
在当前虚拟环境中安装包 (注意不能加sudo,否则就是给系统环境安装) |
pip install django==1.8.2
|
指定版本安装包 |
pip freeze > requirements.txt
|
将当前python环境的包信息导出,为了让别的环境安装依赖时方便 |
注意:在虚拟环境中不可使用
sudo pip install 包名称
来安装python包,这样安装的包实际是安装在了真实的主机环境上。
2. ★第一个Django案例
安装django环境
创建django项目
设计模型类并利用模型类和数据库进行交互
使用django后台管理数据
编写视图函数,进行URL配置
模板的使用
图书-英雄案例完成
2.1 创建项目
在Django中,一个程序包含多个app
,每个app
负责不同的功能模块:
步骤:
- 创建项目
- 创建
app
- 注册app
- 运行服务器
a. 创建项目
django-admin startproject 项目名称
项目目录说明
目录/文件 | 作用 |
---|---|
manage.py
|
是项目管理文件,通过它管理项目。 |
与项目同名的目录,此处为test1。 | 主模块 |
__init__.py
|
是一个空文件,作用是这个目录test1可以被当作包使用。 |
settings.py
|
是项目的整体配置文件。 |
urls.py
|
是项目的URL配置文件。 |
wsgi.py
|
是项目与WSGI兼容的Web服务器入口,详细内容会在布署中讲到。 |
b. 创建app
python manage.py startapp booktest
目录说明
目录/文件 | 作用 |
---|---|
admin.py
|
文件跟网站的后台管理相关。 |
__init.py__
|
是一个空文件,表示当前目录booktest可以当作一个python包使用。 |
migrations 文件夹
|
数据库迁移相关 |
models.py
|
文件跟数据库操作相关。 |
tests.py
|
文件用于开发测试用例,在实际开发中会有专门的测试人员,这个事情不需要我们来做。 |
views.py
|
跟接收浏览器请求,进行处理,返回页面相关。相当于controller |
c. 安装应用
应用创建成功后,需要安装才可以使用,也就是建立应用和项目之间的关联。
在主模块的 settings.py
中INSTALLED_APPS
下添加应用的名称就可以完成安装。
d. 运行测试服务器
在开发阶段,为了能够快速预览到开发的效果,django提供了一个纯python编写的轻量级web服务器,仅在开发阶段使用。
python manage.py runserver ip:端口
例:
python manage.py runserver
可以不写IP和端口,默认IP是127.0.0.1,默认端口为8000。
如果增加、修改、删除文件,服务器会自动重启;
2.2 ORM操作
O是object,也就类对象的意思,R是relation,翻译成中文是关系,也就是关系数据库中数据表的意思,M是mapping,是映射的意思。在ORM框架中,它帮我们把类和数据表进行了一个映射,可以让我们通过类和类对象就能操作它所对应的表格中的数据。ORM框架还有一个功能,它可以根据我们设计的类自动帮我们生成数据库中的表格,省去了我们自己建表的过程。
django中内嵌了ORM框架,不需要直接面向数据库编程,而是定义模型类,通过模型类和对象完成数据表的增删改查操作。
步骤:
- 在models.py中定义模型类
- 执行数据迁移
- 通过类和对象完成数据增删改查操作
a. 定义模型类——继承models.Model
在每个app
的model.py
中定义模型类,继承自models.Model
:
说明:不需要定义主键列,在生成时会自动添加,并且值为自动增长。
from django.db import models# Create your models here.
class BookInfo(models.Model):btitle = models.CharField(max_length= 20)bpub_date = models.DateField()class HeroInfo(models.Model):hname = models.CharField(max_length=20)hgender = models.BooleanField()hcomment = models.CharField(max_length=100)hbook = models.ForeignKey('BookInfo',on_delete = models.CASCADE)
on_delete
Django2以上,ForeignKey
字段一定要写on_delete
参数,可选的如下(都在django.db.models
内):
参数 | 说明 |
---|---|
CASCADE | 级联删除 |
PROTECT |
阻止引用对象删除,会抛出异常ProtectedError
|
SET_NULL |
设置为NULL, 只有当null 参数为True 时才可以
|
SET_DEFAULT |
设置成默认值,所以一定要传递参数default
|
SET |
on_delete=models.SET(get_sentinel_user),
|
b. 数据迁移—— manage.py makemigrations, migrate
迁移由两步完成:
生成迁移文件:根据模型类生成创建表的迁移文件。
python manage.py makemigrations
执行迁移:根据第一步生成的迁移文件在数据库中创建表。
python manage.py migrate
Django框架根据我们设计的模型类生成了迁移文件,在迁移文件中我们可以看到fields列表中每一个元素跟BookInfo类属性名以及属性的类型是一致的。同时我们发现多了一个id项,这一项是Django框架帮我们自动生成的,在创建表的时候id就会作为对应表的主键列,并且主键列自动增长。
默认数据库
Django默认采用sqlite3数据库,上图中的db.sqlite3就是Django框架帮我们自动生成的数据库文件。
sudo apt-get install sqliteman
数据库的设置在settings.py
中:
生成字段名
生成的列名和自己定义的列名相同,并且多了一个id项,这一项是Django框架帮我们自动生成的,在创建表的时候id就会作为对应表的主键列,并且主键列自动增长。
关系属性生成的字段名为: 关系属性名_id
生成表名——app名_类名
应用名_model名
<app_name>_<model_name>
c. ★操作数据—— manage.py shell
python manage.py shell
完成数据表的迁移之后,下面就可以通过进入项目的shell,进行简单的API操作。如果需要退出项目,可以使用ctrl+d快捷键或输入quit()。
基本查询命令 | 说明 |
---|---|
BookInfo.objects.all()
|
查询所有图书 |
图书对象.save()
|
保存当前图书信息到数据库/ 修改图书信息 |
b=BookInfo.objects.get(id=1)
|
根据主键查询图书 |
图书对象.delete()
|
删除图书信息 |
关联对象查询命令 | 说明 |
---|---|
b.heroinfo_set.all()
|
返回该图书关联的所有英雄信息 |
h.hbook_id
|
获取外键值 |
h.hbook
|
获取外键引用对象 |
多的一方可以直接使用属性值来访问一 的一方, 而一的一方获取多的一方时,需要使用
xxx_set
from booktest.models import BookInfo,HeroInfo # 引入类
from datetime import dateb1 = BookInfo()
b1.btitle= "金庸新著"
b1.bpub_date = date(1991,1,1)
b1.save() # 保存b2 = BookInfo()
b2.btitle= "屠龙宝刀"
b2.bpub_date = date(1995,5,6)
b2.save() # 保存BookInfo.objects.all() # 获取所有
BookInfo.objects.get(id=1) # 根据id获取
BookInfo.objects.get(pk=1) # 根据主键获取b1.btitle="点击就送"
b1.save() # 修改b.delete() # 删除
操作关系字段
b1 = BookInfo.objects.get(id=1)h = HeroInfo()
h.hname = "张无忌"
h.hgender = True
h.hbook = b1h.save()h.hbook_id # 获取外键值
h.hbook # 获取引用对象b1.heroinfo_set.all() # 反向获取对象
2.3 后台管理操作——admin
步骤:
- 管理界面本地化
- 创建管理员
- 注册模型类
- 自定义管理页面
a 界面本地化
在主模块的settings.py
中,设置:
LANGUAGE_CODE = 'zh-hans' #使用中国语言
TIME_ZONE = 'Asia/Shanghai' #使用中国上海时间
b 创建管理员—— manage.py createsuperuser
python manage.py createsuperuser
然后启动:
python manage.py runserver
进入URL:
http://127.0.0.1:8000/admin/
c. 注册模型类
要让自己创建的模型类,可以被admin页面管理,需要对他们进行注册:
进入主模块的admin.py
:
from django.contrib import admin
from booktest.models import BookInfo,HeroInfo
# 后台管理相关文件
# Register your models here.# 注册模型类
admin.site.register(BookInfo)
admin.site.register(HeroInfo)
再刷新
d. 自定义管理页面
Django提供了自定义管理页面的功能,比如列表页要显示哪些值。
进入主模块的admin.py
,创建自己的ModelAdmin
类,然后在里面的list_display
类属性决定了显示哪些 属性:
from django.contrib import admin
from booktest.models import BookInfo,HeroInfo
# 后台管理相关文件
# Register your models here.
# 自定义模型管理类
class BookInfoAdmin(admin.ModelAdmin):'''图书模型管理类'''list_display = ['id', 'btitle', 'bpub_date']class HeroInfoAdmin(admin.ModelAdmin):'''英雄人物模型管理类'''list_display = ['id', 'hname', 'hcomment']# 注册模型类
# admin.site.register(BookInfo)
admin.site.register(BookInfo, BookInfoAdmin)
admin.site.register(HeroInfo, HeroInfoAdmin)
2.4 视图初级(MVC中的C)
步骤:
- 定义视图函数
- 配置URLconf
a. 定义视图函数
- 视图函数就是普通的Python函数
- 定义在每个app中的
views.py
中 - 函数接收一个参数
request
- 函数返回
django.http.HttpResponse对象
django.shortcuts
中有快捷方式render、 redirect
from django.shortcuts import render
from django.http import HttpResponse
import time
# Create your views here.
def index(request):currenttime = str(time.localtime().tm_min) +":"+ str(time.localtime().tm_sec)return HttpResponse(currenttime )
b. ★配置url
https://docs.djangoproject.com/en/2.1/topics/http/urls/
django查找URL的顺序是这样子的:
- Django查看root URLconf module. 默认的,会查看
settings.py
中的ROOT_URLCONF
, 但是如果发送来的HttpRequest object
中有urlconf
属性(set by middleware), 那么这个值就会覆盖ROOT_URLCONF
设置 - Django 读取root URLconf module这个模块中的变量名为
urlpatterns
的内容,它应该是一个list
,并且都是django.urls.path()
或者django.urls.re_path()
的实例。 - Django 遍历所有URL pattern, 找到第一个匹配的URL
- 一旦匹配成功,Django就会引入对应的
view
来调用,which is a simple Python function (or a class-based view). The view gets passed the following arguments:- An instance of HttpRequest.
- If the matched URL pattern returned no named groups, then the matches from the regular expression are provided as positional arguments.
- The keyword arguments are made up of any named parts matched by the path expression, overridden by any arguments specified in the optional kwargs argument to django.urls.path() or django.urls.re_path().
- 如果没有匹配成功,或者匹配过程有任何错误,那么Django invokes an appropriate error-handling view. See Error handling below.
主模块的urls.py
中:
from django.contrib import admin
from django.urls import path
from django.urls import includeurlpatterns = [path('admin/', admin.site.urls),path('', include('booktest.urls'))
]
booktest应用中的urls.py
(需要自己创建):
from django.conf.urls import url
from django.urls import re_path
from .views import indexurlpatterns = [re_path(r'.*', index),# url(r'index', index),# url('^',index)
]
页面url地址设置
习惯统一以/
开头,这样就会从host开始拼接,如果不写/
,则会当成相对地址
<a href="/create">新增</a>
2.5 模板初级(MVC中的V)
步骤:
- 创建模板文件夹和模板文件
- 在
settings.py
中配置模板路径 - 在
view
中加载模板文件对象 - 给模板传递数据,生成上下文
- 渲染上下文,得到html
- 返回html
a. 创建模板目录和文件
直接在项目名底下建立目录templates
, 然后在该目录中,为每个app建立同名文件夹:
b. 配置模板路径
在settings.py
中,找到TEMPLATES
的DIR
, 加上模板路径:
'DIRS': [os.path.join(BASE_DIR, 'templates')],
c. 模板文件内代码书写
{{变量名}}{%代码段%}
比如:
{% for i in data %}循环内部代码
{% empty %}如果循环列表长度为0则运行这部分
{% endfor %}
d. 视图中调用模板
- 找到模板
- 定义上下文
- 渲染模板
from django.http import HttpResponse
from django.template import loader,RequestContextdef index(request):'''使用模板文件'''# 使用模板文件# 1.加载模板文件, 模板对象temp = loader.get_template('booktest/index.html')# 2.定义模板上下文:给模板文件传递数据context = RequestContext(request, {} )# 3.模板渲染:产生标准的html内容res_html = temp.render(context)# 4.返回给浏览器return HttpResponse(res_html)
★使用快捷方式
def index(request):# 进行处理,和M和T进行交互。。。# return HttpResponse('老铁,没毛病')# return my_render(request, 'booktest/index.html')return render(request, 'booktest/index.html', {'content':'hello world', 'list':list(range(1,10))})
3. ★模型高级——ORM
对象-关系映射ORM系统一般以中间件的形式存在
3.1 配置MYSQL数据库
a. 配置数据库信息
在settings.py
中:
DATABASES = {'default': {# 'ENGINE': 'django.db.backends.sqlite3','ENGINE': 'django.db.backends.mysql',# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),'NAME': 'test2', #数据库名字,'USER': 'root', #数据库登录用户名'PASSWORD': 'mysql', #数据库登录密码'HOST': 'localhost', #数据库所在主机'PORT': '3306', #数据库端口}
}
注意:数据库test2 Django框架不会自动生成,需要我们自己进入mysql数据库去创建。
b. 安装mysql数据库的包
pip install pymysql
c. 添加install mysql
在主模块的__init__.py
内写入:
import pymysql
pymysql.install_as_MySQLdb()
3.2 常用字段和参数
Django根据属性的类型确定以下信息:
- 当前选择的数据库支持字段的类型
- 渲染管理表单时使用的默认html控件
- 在管理站点最低限度的验证
django会为表创建自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后django不会再创建自动增长的主键列
a. 属性命名限制
- 不能是python的保留关键字。
- 不允许使用连续的下划线,这是由django的查询方式决定的
- 定义属性时需要指定字段类型,通过字段类型的参数指定选项
属性=models.字段类型(选项)
b. 字段类型
字段类型都在django.db.models
内
字段 | 描述 | 自己的属性及其作用 |
---|---|---|
AutoField
|
自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性。 | |
BooleanField
|
布尔字段,值为True或False | |
NullBooleanField
|
可空布尔型,支持Null、True、False三种值 | |
CharField
|
字符串 | 参数max_length表示最大字符个数 |
TextField
|
大文本字段,一般超过4000个字符时使用。 | |
IntegerField
|
整数 | |
DecimalField
|
十进制浮点数 |
(max_digits=None, decimal_places=None) 参数max_digits表示总位数。 参数decimal_places表示小数位数。 |
FloatField
|
浮点数 | |
DateField
|
日期 |
[auto_now=False, auto_now_add=False] 参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false。 参数auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false。 参数auto_now_add和auto_now是相互排斥的,组合将会发生错误。 |
TimeField
|
时间 | 参数同DateField。 |
DateTimeField
|
日期时间 | 参数同DateField。 |
FileField
|
上传文件字段。 | |
ImageField
|
继承于FileField,对上传的内容进行校验,确保是有效的图片。 |
c. 常用参数
参数名 | 含义 |
---|---|
default
|
默认值。设置默认值。 |
primary_key
|
若为True,则该字段会成为模型的主键字段,默认值是False,一般作为AutoField的选项使用。 |
unique
|
如果为True, 这个字段在表中必须有唯一值,默认值是False。 |
db_index
|
若值为True, 则在表中会为此字段创建索引,默认值是False。 |
db_column
|
字段的名称,如果未指定,则使用属性的名称。 |
null
|
如果为True,表示允许为空,默认值是False。 |
blank
|
如果为True,则该字段允许为空白,默认值是False。 |
- null是数据库范畴的概念,blank是后台管理页面表单验证范畴的。
- 默认值不是数据库的默认值,而是在创建django对象时的默认值
- 当修改模型类之后,如果添加的选项不影响表的结构,则不需要重新做迁移,商品的选项中
default
和blank
不影响表结构。
3.3 ★条件查询
a. 查看MySQL日志文件
默认情况下mysql的日志文件没有产生,需要修改mysql的配置文件
修改配置文件
sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf
将下面2行的注释去掉
重启mysql
sudo service mysql restart
查看日志文件
sudo tail -f /var/log/mysql/mysql.log #可以实时查看数据库的日志内容
a. 查询函数
所有的查询都是使用的 对象.objects
里面的方法:
函数名 | 功能 | 返回值 | 说明 |
---|---|---|---|
get
|
返回表中满足条件的一条且只能有一条数据。 | 返回值是一个模型类对象。 |
参数中写查询条件。 1) 如果查到多条数据,则抛异常 MultipleObjectsReturned 。2)查询不到数据,则抛异常: DoesNotExist 。
|
all
|
返回模型类对应表格中的所有数据。 |
返回值是QuerySet 类型
|
查询集 |
filter
|
返回满足条件的数据。 |
返回值是QuerySet 类型
|
参数写查询条件。 |
exclude
|
返回不满足条件的数据。 |
返回值是QuerySet 类型
|
参数写查询条件。 |
order_by
|
对查询结果进行排序。 |
返回值是QuerySet 类型
|
参数中写根据哪些字段进行排序。 |
b. ★条件运算符
条件格式:模型类属性名__条件名=值
条件运算 | 说明 | 例子 |
---|---|---|
exact
|
是否全等, 区分大小写 |
.filter(id__exact=1)
|
contains
|
是否包含,区分大小写 |
filter(btitle__contains='传')
|
endswith , startswith
|
是否以xx开始、结束,区分大小写 |
.filter(btitle__endswith='部')
|
isnull
|
是否为空 |
.filter(btitle__isnull=False)
|
in
|
是否在范围内 |
.filter(id__in=[1, 3, 5])
|
gt、gte、lt、lte
|
大于小于等等 |
.filter(id__gt=3)
|
日期类型比较… |
.filter(bpub_date__year=1980) .filter(bpub_date__gt=date(1990, 1, 1))
|
- 判断是否相等:
exact
或者直接写=
BookInfo.objects.get(id=1)BookInfo.objects.filter(id__exact=1)
- 模糊查询:
contains
,endswith
,startswith
BookInfo.objects.filter(btitle__contains='传')
BookInfo.objects.filter(btitle__endswith='部')
以上运算符都区分大小写,在这些运算符前加上i表示不区分大小写,如iexact、icontains、istartswith、iendswith.
- 空查询
isnull
BookInfo.objects.filter(btitle__isnull=False)
- 范围查询
in
BookInfo.objects.filter(id__in = [1,3,5])
- 比较查询:
gt,lt,gte, lte
BookInfo.objects.filter(id__gt=3)
- 日期查询:年月日属性
BookInfo.objects.filter(bpub_date__year=1980)from datetime import date
BookInfo.objects.filter(bpub_date__gt=date(1980,1,1))
c. 排序——order_by
order
方法内加上 字段名,如果多个字段,使用,
隔开; 默认是从小到大排序,如果逆序,需要在字段名前加上-
。
# 查询所有图书的信息,按照id从小到大进行排序。
BookInfo.objects.all().order_by('id')
# 查询所有图书的信息,按照id从大到小进行排序。
BookInfo.objects.all().order_by('-id')
# 把id大于3的图书信息按阅读量从大到小排序显示。
BookInfo.objects.filter(id__gt=3).order_by('-bread')
d. ★Q对象——逻辑关系
filter
等函数可以传入多个参数,用于指定多个条件,不过这些条件都是 and
方式:
BookInfo.objects.filter(btitle__exact="abc", bread__gt = 10)
而Q对象可以用来与或非:&|~
from django.db.models import QBookInfo.objects.filter(Q(id__gt=3)&Q(bread__gt=30))
BookInfo.objects.filter(Q(id__gt=3)|Q(bread__gt=30))
BookInfo.objects.filter(~Q(id=3))
e. ★F对象——属性之间的比较
用于类属性之间的比较
from django.db.models import FBookInfo.objects.filter(bread__gt=F('bcomment')) # 阅读量大于评论
BookInfo.objects.filter(bread__gt=F('bcomment')*2) # 还可以进行直接计算
f. 聚合函数——aggregate、count
对查询结果进行聚合操作
2个方法
方法 | 含义 |
---|---|
aggregate
|
聚合的函数,配合聚合类来使用,返回字典 |
count
|
统计返回的数据个数,返回的是数字 |
from django.db.models import Sum,Count,Max,Min,Avg
聚合类 |
---|
Sum |
Count |
Max |
Min |
Avg |
BookInfo.objects.all().aggregate(Count('id'))
# {'id__count': 5}
BookInfo.objects.aggregate(Sum('bread')) # all()可以省略
# {'bread__sum': 126}BookInfo.objects.all().count()
BookInfo.objects.count()
BookInfo.objects.filter(id__gt=3).count()
aggregate
返回值是一个字典类型:
{'聚合类小写__属性名':值}如:{'sum__bread':3}
3.4 ★查询集QuerySet
a. 返回查询集的方法
返回查询集的过滤器:
- all():返回所有数据。
- filter():返回满足条件的数据。
- exclude():返回满足条件之外的数据,相当于sql语句中where部分的not关键字。
- order_by():对结果进行排序。
返回单个值的过滤器如下:
- get():返回单个满足条件的对象
- 如果未找到会引发"模型类.DoesNotExist"异常。
- 如果多条被返回,会引发"模型类.MultipleObjectsReturned"异常。
- count():返回当前查询结果的总条数。
- aggregate():聚合,返回一个字典。
b. 查看查询集是否有数据——exist
查询集对象.exists()
返回值为True/False
c. 查询集的特点
- 惰性查询:只有在实际使用查询集中的数据的时候才会发生对数据库的真正查询。
调用数据的情况包括迭代、序列化、与if合用。 - 缓存:当使用的是同一个查询集时,第一次使用的时候会发生实际数据库的查询,然后把结果缓存起来,之后再使用这个查询集时,使用的是缓存中的结果。
每个查询集都包含一个缓存来最小化对数据库的访问。在新建的查询集中,缓存为空,首次对查询集求值时,会发生数据库查询,django会将查询的结果存在查询集的缓存中,并返回请求的结果,接下来对查询集求值将重用缓存中的结果。
d. 查询集切片
- 可以对一个查询集进行取下标或者切片操作来限制查询集的结果。
- 对一个查询集进行切片操作会产生一个新的查询集,下标 不允许 为负数。
- 返回的新查询集也由缓存,只要不用数据,就不会去数据库查询
- 取出查询集第一条数据的两种方式:
方式 | 说明 |
---|---|
b[0] |
如果b[0]不存在,会抛出IndexError 异常
|
b[0:1].get() |
如果b[0:1].get()不存在,会抛出DoesNotExist 异常。
|
3.5 模型类关系——一对一、多对多、一对多
- 一对多关系
例:图书类-英雄类
models.ForeignKey()
定义在多的类中。 - 多对多关系
例:新闻类-新闻类型类 体育新闻 国际新闻
models.ManyToManyField
定义在哪个类中都可以。 - 一对一关系
例:员工基本信息类-员工详细信息类. 员工工号
models.OneToOneField
定义在哪个类中都可以
3.6 ★关联查询
a. 查询关联对象
由一类的对象查询多类的时候:
一类的对象.多类名小写_set.all() #查询所用数据
比如:b.heroinfo_set.all()
由多类的对象查询一类的时候:
多类的对象.关联属性 #查询多类的对象对应的一类的对象
比如:h.hbook
由多类的对象查询一类对象的id时候:
多类的对象. 关联属性_id
比如:h.hbook_id
b. ★关联查询写法
- 通过多类的条件查询一类的数据:
一类名.objects.filter(多类名小写__多类属性名__条件)
- 通过一类的条件查询多类的数据:
多类名.objects.filter(关联属性__一类属性名__条件)
例:查询图书信息,要求图书关联的英雄的描述包含'八'。
BookInfo.objects.filter(heroinfo__hcomment__contains='八')
例:查询图书信息,要求图书中的英雄的id大于3.
BookInfo.objects.filter(heroinfo__id__gt=3)
例:查询书名为“天龙八部”的所有英雄。
HeroInfo.objects.filter(hbook__btitle='天龙八部')
c. 自关联查询 模型定义
也是使用ForeignKey
,只不过里面参数是写self
class CityInfo(models.Model):cname = models.CharField(max_length=50)cparent = models.ForeignKey(to="self", on_delete=models.CASCADE, blank=True, null=True)
3.7 ★管理器——models.Manager
每个模型类 都以一个类属性叫做objects
,它的类型是django.db.models.Manager
。 它是Django帮我自动生成的管理器对象,通过这个管理器可以实现对数据的查询。
a. 自定义管理器类的应用场景
- 改变查询的结果集。
比如调用BookInfo.books.all()返回的是没有删除的图书的数据。 - 添加额外的方法。——比如增删改查的方法
管理器类中定义一个方法帮我们操作模型类对应的数据表。
可以在模型类中自己增加一个Manager
字段,如果自己增加了,那么默认的就失效了:
class BookInfo(models.Model):book = models.Manager()
b. 自定义管理器对象
小提示:
- 自定义管理器对象中使用
super().xxx()
调用原来的方法 - 自定义管理器对象中可以使用
self.model()
创建对应模型类的对象
自己定义一个类,继承自 models.Manager
,可以就写在models.py
中:
在管理器对象中使用self.model()
就可以创建一个跟自定义管理器对应的模型类对象。
from django.db import models# Create your models here.
class BookInfoManager(models.Manager):'''图书模型管理器类'''# 1.改变原有查询的结果集def all(self):# 1.调用父类的all方法,获取所有数据books = super().all() # QuerySet# 2.对books中的数据进行过滤books = books.filter(isDelete=False)# 返回booksreturn books# 2.封装方法,操作模型类对应的数据表(增删改查)def create_book(self, btitle, bpub_date):'''添加一本图书'''# 1.创建一个图书对象# 获取self所在的模型类model_class = self.modelbook = model_class()# book = BookInfo()book.btitle = btitlebook.bpub_date = bpub_date# 2.添加进数据库book.save()# 3.返回bookreturn book
class BookInfo(models.Model):...objects = BookInfoManager() # 自定义一个BookInfoManager类的对象
默认的objects管理器对象中已经有
create
方法,传参的时候必须使用关键字参数来指定列名
3.8 元选项——指定表名
因为django默认生成的表名为appname_modelname
的小写名字, 如果app的名字改变了,那么表名也会失效。 为了防止这种情况,可以自定义表名:
- 元选项:
需要在模型类中定义一个元类Meta
,在里面定义一个类属性db_table
就可以指定表名。
class BookInfo(models.Model):...class Meta:db_table = 'bookinfo' # 指定模型类对应表名
4. 视图高级
4.1 URL匹配过程
- 在项目的urls文件中包含具体应用的urls文件,在具体应用的urls文件中包含具体url和视图的对应关系。
- url配置项是定义在一个名叫urlpatterns的列表中,其中的每一个元素就是一个配置项,每一个配置项都调用
path
或者re_path
函数。 - urlpatterns中的每个正则表达式在第一次访问它们时被编译,这使得运行很快。
- 不能在开始加反斜杠,推荐在结束加反斜杠。
正确:index/ 正确:index 错误:/index 错误:/index/
- URL匹配的时候不包括域名、GET参数
4.2 获取url参数
进行url匹配时,把所需要的捕获的部分设置成一个正则表达式组,这样django框架就会自动把匹配成功后相应组的内容作为参数传递给视图函数。
注意:两种参数的方式不要混合使用,在一个正则表达式中只能使用一种参数方式。
a. 位置参数
位置参数,参数名可以随意指定
url(r'^delete(\d+)/$',views.show_arg),
b. 关键字参数
在位置参数的基础上给正则表达式组命名即可。
?P<组名>
关键字参数,视图中参数名必须和正则表达式组名一致.
re_path(r'index/(?P<num>\d+)'def index(request, num):pass
4.3 ★错误视图
网站开发完成后,要修改settings.py
配置:
- DEBUG=False ——— 关闭开发者模式
- ALLOWED_HOST=[
'*'
] ——— 配置可以访问的IP
如果此时出现错误,Django自己会返回标准的错误页面。 如果需要修改,则需要的templates目录下面自定义一个404.html文件, 或者 500.html 等等。
DEBUG模式下看不到错误视图,只能看到调试信息
- 404.html会收到一个参数叫做
request_path
<html>
<head><title></title>
</head>
<body>
找不到了
<hr/>
{{request_path}}
</body>
</html>
4.4 ★HttpRequest对象
属性 | 说明 |
---|---|
request.POST
|
保存的是POST提交的参数(QueryDict 类型)
|
request.GET
|
保存的是GET提交的参数(QueryDict 类型)
|
request.method
|
返回请求方式字符串 |
request,path
|
返回请求路径字符串,不包含域名和url参数 |
request.encoding
|
请求方式,如果返回None,代表是浏览器默认encoding,一般是UTF-8 这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值。 |
request.FILES
|
一个类似于字典的对象,包含所有的上传文件。 |
request.COOKIES
|
一个标准的Python字典,包含所有的cookie,键和值都为字符串。 |
request.session
|
一个既可读又可写的类似于字典的对象,表示当前的会话,只有当Django 启用会话的支持时才可用,详细内容见"状态保持"。 |
a. ★QueryDict对象
django.http.QueryDict
类似于字典,和一般字典不同的是,它可以处理一个key带有多个value的情况。
方法 | 说明 |
---|---|
对象[key] | 没有值就报错,一个键同时拥有多个值将获取最后一个值 |
get(key) | 没有值就返回None,一个键同时拥有多个值将获取最后一个值 |
getlist(key) | 返回List |
from django.http.request import QueryDict
q = QueryDict('a=123&b=456`)
q['a'] # 获取值,没有值就报错
q.get('a') # 获取值,没有值就返回None
q.get('a', 'default') # 获取值,没有对应的key就返回默认值
q.getlist('a') # 获取一个key的多个值,返回类型为list
取消django防止跨域访问的保护:
将settings.py
中的'django.middleware.csrf.CsrfViewMiddleware',
注释掉
4.5 HttpResponse对象
django.http.HttpResponse
视图在接收请求并处理后,必须返回HttpResponse对象或子对象
属性 | 说明 |
---|---|
content | 表示返回的内容。 |
charset | 表示response采用的编码字符集,默认为utf-8。 |
status_code | 返回的HTTP响应状态码。 |
content-type |
指定返回数据的的MIME类型,默认为’text/html ’。
|
方法 | 说明 |
---|---|
__init__
|
创建HttpResponse对象后完成返回内容的初始化。 |
set_cookie
|
设置Cookie信息。set_cookie(key, value='', max_age=None, expires=None)
|
delete_cookie(key)
|
删除指定的key的Cookie,如果key不存在则什么也不发生。 |
write
|
向响应体中写数据。 |
JsonResponse
JsonResponse继承自HttpResponse,它的 content-type为 application/json
,创建对象时接收字典作为参数
return JsonResponse({'h1':'hello','h2':'world'})
HttpResponseRedirect
继承自 HttpResponse,状态码为302
return HttpResponseRedirect('/')
5. ★cookie和session
实现状态保持主要有两种方式:
- 在客户端存储信息使用Cookie。
- 在服务器端存储信息使用Session。
cookie和session的应用场景
- cookie:记住用户名。安全性要求不高。
- session:涉及到安全性要求比较高的数据。银行卡账户,密码
5.1 cookie
Cookie是由服务器端生成,发送给User-Agent(一般是浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器。
Cookies最典型记住用户名。
Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,因为电脑上的浏览器可能被其它人使用
a.cookie的特点
- Cookie以键值对的格式进行信息的存储。
- Cookie基于域名安全,不同域名的Cookie是不能互相访问的,如访问itcast.cn时向浏览器中写了Cookie信息,使用同一浏览器访问baidu.com时,无法访问到itcast.cn写的Cookie信息。
- 当浏览器请求某网站时,会将浏览器存储的跟网站相关的所有Cookie信息提交给网站服务器。
- cookie是有过期时间的,如果不指定,默认是浏览器关闭后就没了。
b. 设置cookie—— response.set_cookie
设置cookie是使用一个HttpResponse对象,或者它的子类对象, 里面的set_cookie
方法,是以键值对保存的
response.set_cookie(key,value, max_age, expires)
`max_age`是一个整数,表示在指定秒数后过期。
`expires`是一个datetime或timedelta对象,会话将在这个指定的日期/时间过期。
max_age与expires二选一。
如果不指定过期时间,在关闭浏览器时cookie会过期。
例子:
response = HttpResponse('这是响应')
response.set_cookie('mykey1', 1123415)
return responseresponse.set_cookie( 'num', 1, max_age = 秒数) #
c. 获取cookie —— request.COOKIES
def cookie_get(request):response = HttpResponse("读取Cookie,数据如下:<br>")if 'h1' in request.COOKIES:response.write('<h1>' + request.COOKIES['h1'] + '</h1>')return response
5.2 session
session就像是去健身房办卡,办好卡后,健身房那边保存了卡的信息和对应用户的信息,而用户只需要记住卡号就可以使用了。
在服务器内,session就是一张表, 里面是键值对的方式来存储: session_key和session_data
django的框架中,session叫做
django_session
,保存在request.session
中,设置也是使用这个属性,类似于使用字典django会在cookie中让客户端保存key为
sessionid
的cookie,用来维护session
cookie无论保存的是什么类型的数据,取出来的时候都是字符串,而 session数据因为是保存在服务器中,所以取出来的类型不变
a. session的特点
- session是以键值对进行存储的。
- session依赖于cookie。唯一的标识码保存在**
sessionid
** cookie中。 - session也是有过期时间,如果不指定,默认两周就会过期。
- 存储Session时,键与Cookie中的sessionid相同,值是开发人员设置的键值对信息,进行了base64编码,过期时间由开发人员设置。
b. 启用Session
默认是启用的。打开test3/settings.py文件,在项MIDDLEWARE_CLASSES中启用Session中间件。
c. 存储方式
在settings.py
文件,设置SESSION_ENGINE
项指定Session数据存储的方式,可以存储在数据库、缓存、Redis等。
存储在缓存中:存储在本机内存中,如果丢失则不能找回,比数据库的方式读写更快。
SESSION_ENGINE='django.contrib.sessions.backends.cache'
存储在数据库中,如下设置可以写,也可以不写,这是默认存储方式。
SESSION_ENGINE='django.contrib.sessions.backends.db'
如果存储在数据库中,需要在项INSTALLED_APPS中安装Session应用。
迁移后会在数据库中创建出存储Session的表。
表结构如下
混合存储:优先从本机内存中存取,如果没有则从数据库中存取。
SESSION_ENGINE='django.contrib.sessions.backends.cached_db'
d. ★使用session —— request.session
使用 | 说明 |
---|---|
request.session['键']=值
|
以键值对的格式写session。 |
request.session['键']
|
获取session |
request.session.get('键',默认值)
|
根据键读取值。 |
request.session.clear()
|
清除所有session,在存储中删除值部分。 |
request.session.flush()
|
清除session数据,在存储中删除session的整条数据。 |
del request.session['键']
|
删除session中的指定键及值,在存储中只删除某个键及对应的值。 |
request.session.set_expiry(value)
|
设置会话的超时时间,如果没有指定过期时间则两个星期后过期。 |
- 如果value是一个整数,会话将在value秒没有活动后过期。
- 如果value为0,那么用户会话的Cookie将在用户的浏览器关闭时过期。
- 如果value为None,那么会话永不过期。
session保存的值是有类型的
e. 配置Redis的Session
- 先安装包
pip install django-redis-sessions
- 配置settings.py
SESSION_ENGINE = 'redis_sessions.session'
SESSION_REDIS_HOST = 'localhost'
SESSION_REDIS_PORT = 6379
SESSION_REDIS_DB = 2
SESSION_REDIS_PASSWORD = ''
SESSION_REDIS_PREFIX = 'session'
6. 模板高级
模板文件包含两部分内容:
- 静态内容:css,js,html。
- 动态内容:用于动态去产生一些网页内容。通过模板语言来产生。
模板语言的使用都在django.template
中,settings.py
内定义了配置:
Django处理模板分为两个阶段:
- 加载:根据给定的路径找到模板文件,编译后放在内存中。
- 渲染:使用上下文数据对模板插值并返回生成的字符串。
6.1 模板的原始使用
- 加载模板文件,获取一个模板对象
- 定义模板上下文,给模板文件传数据
- 模板渲染,返回替换后的html
- 返回响应
# 1.加载模板文件,获取一个模板对象
temp = loader.get_template(template_path)
# 2.定义模板上下文,给模板文件传数据
context = RequestContext(request, context)
# 3.模板渲染,产生一个替换后的html内容
res_html = temp.render(context)
# 4.返回应答
return HttpResponse(res_html)
6.2 模板文件加载顺序
- 首先去配置的模板目录下面去找模板文件。
TEMPLATES = [{'BACKEND': 'django.template.backends.django.DjangoTemplates','DIRS': [os.path.join(BASE_DIR, 'templates')],'APP_DIRS': True,'OPTIONS': {'context_processors': ['django.template.context_processors.debug','django.template.context_processors.request','django.contrib.auth.context_processors.auth','django.contrib.messages.context_processors.messages',],},},
]
- 去INSTALLED_APPS下面的每个应用的
templates文件夹
去找模板文件,前提是应用中必须有templates文件夹。
INSTALLED_APPS = ('django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','booktest',
)
6.3 ★模板变量
模板语言包括4种类型,分别是:
* 变量
* 标签
* 过滤器
* 注释
- 模板变量名是由数字,字母,下划线和点组成的,不能以下划线开头。
- 使用模板变量:
{{模板变量名}}
- 模板变量的解析顺序:
{{ book.btitle }}
- 首先把book当成一个字典,把btitle当成键名,进行取值book[‘btitle’]
- 把book当成一个对象,把btitle当成属性,进行取值book.btitle
- 把book当成一个对象,把btitle当成对象的方法,进行取值book.btitle
{{book.0}}
- 首先把book当成一个字典,把0当成键名,进行取值book[0]
- 把book当成一个列表,把0当成下标,进行取值book[0]
★如果解析失败,则产生内容时用空字符串填充模板变量。
6.4 ★模板标签 templatetag
内建标签
for 循环
{% 代码段 %}for循环:
{% for x in 列表 %}# 列表不为空时执行
{% empty %}# 列表为空时执行
{% endfor %}
可以使用{{ forloop.counter }}
得到循环遍历了第几次
if 判断
{% if 条件 %}代码
{% elif 条件 %}代码
{% else %}代码
{% endif %}
- 可以使用的条件判断符号:
> < >= <= == !=
- 可以使用的逻辑运算:
and or not
- 注意:进行比较操作时,比较操作符两边必须有空格。
{% for book in books %}{% if book.id <= 2 %}<li class="red">{{ forloop.counter }}--{{ book.btitle }}</li>{% elif book.id <= 5 %}<li class="yellow">{{ forloop.counter }}--{{ book.btitle }}</li>{% else %}<li class="green">{{ forloop.counter }}--{{ book.btitle }}</li>{% endif %}
{% endfor %}
6.5 ★过滤器
语法如下:
- 使用管道符号
|
来应用过滤器,用于进行计算、转换操作,可以使用在变量、标签中。 - 如果过滤器需要参数,则使用冒号
:
传递参数。
变量|过滤器:参数
内建过滤器
官方文档
- 过滤器用于对模板变量进行操作。
- 举例
- length:求长度。字符串,列表.
- default:设置模板变量的默认值。
- date:改变日期的显示格式。
- Y表示年,格式为4位,y表示两位的年。
- m表示月,格式为01,02,12等。
- d表示日, 格式为01,02等。
- j表示日,格式为1,2等。
- H表示时,24进制,h表示12进制的时。
- i表示分,为0-59。
- s表示秒,为0-59。
- 格式:
模板变量|过滤器:参数
book | lengthdata|default:'默认值'value|date:"Y年m月j日 H时i分s秒"
自定义过滤器
自定义过滤器其实就是一个python的函数
官方文档
比如模板代码中不能使用%
取余,所以需要自定义过滤器:
步骤:
- 在项目根目录下创建目录
templatetags
, 里面要有__init__.py
- 在里面创建
py
文件,里面写方法 (文件名和方法名都不一定) - 按照下面写
from django.template import libraryregister = Library() # 自定义过滤器需要使用它@register.filter # 这个装饰必须要
def mod(num): # 方法名字不一定,参数就是过滤器可以接收的参数( | 之前)return num % 2 == 0@register.filter
def mod_val(num, val): # 定义一个带参数的过滤器pass
- 页面中先加载这个定义了 过滤器的文件,然后就可以使用了
# 页面中
{{ load.filters }} # filters 是那个py文件的名字
...
{{ if book.id | mod_val : 2 %}}
自定义过滤器的参数至少有一个,最多2个
templatetags也可以创建在app目录下
6.6 模板注释
django的注释代码不会被编译,不会输出到客户端
- 单行注释:
{# {% if book.id|mod %}#}
- 多行注释:
{% comment %}...
{% endcomment %}
6.7 模板继承
- 父模块中:
为了更好的可读性,建议给endblock
标签也写上名字,这个名字与对应的block名字相同。父模板中也可以使用上下文中传递过来的数据。
{% block 块名 %}
预留区域,可以编写默认内容,也可以没有默认内容
{% endblock 块名%}
子模板去继承父模板之后,可以重写父模板中的某一块的内容。
- 子模块中:
子模版不用填充父模版中的所有预留区域,如果子模版没有填充,则使用父模版定义的默认值。
首行写继承格式:{% extends 父模板文件路径%}
{% extends 父模板文件路径%}...
{% block 块名 %}{{ block.super}} #获取父模板中块的默认内容
重写的内容
{% endblock 块名%}
base.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>{% block title %}父模板文件{% endblock title %}</title>
</head>
<body>
<h1>导航条</h1>
{% block b1 %}<h1>这是父模板b1块中的内容</h1>
{% endblock b1 %}
{% block b2 %}<h1>这是父模板b2块中的内容</h1>
{% endblock b2 %}
<h1>版权信息</h1>
</body>
</html>
child.html
{% extends 'booktest/base.html' %}
{% block title %}子模板文件{% endblock title %}
{% block b1 %}{{ block.super }}<h1>这是子模板b1块中的内容</h1>
{% endblock b1 %}{% block b2 %}{{ block.super }}<h1>这是子模板b2块中的内容</h1>
{% endblock b2 %}
6.8 HTML转义
- 在模板上下文中的html标记默认是会被转义的。即内容都会被当成文本显示,而不会转换成HTML标签
一般的变量使用,默认是{{t1|escape}}
,所以 escape
可以不写。
关闭模板文中的转义
{{ 模板变量|safe}}
——只关闭这一个- 关闭一个代码段内的:
{% autoescape off %}模板语言代码
{% endautoescape %}
6.9 ★装饰器来显示必须登录才能访问
def login_required(view_func):'''登录判断装饰器'''def wrapper(request, *view_args, **view_kwargs):# 判断用户是否登录if request.session.has_key('islogin'):# 用户已登录,调用对应的视图return view_func(request, *view_args, **view_kwargs)else:# 用户未登录,跳转到登录页return redirect('/login')return wrapper
6.10 CSRF 攻击
CSRF全拼为Cross Site Request Forgery,译为跨站请求伪造。CSRF指攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账…造成的问题包括:个人隐私泄露以及财产安全。
a. 攻击原理
登录了的网站,保存了sessionid, 然后登录一个钓鱼网站的时候,它骗你点击一个地方,然后从它向你已登录的网站发送一个请求,用来装作是你来操作。
b. django防止CSRF的方法
- Django框架配置的中间件内要打开CSRF防护。
- CSRF防护只防止POST请求,对GET是不起作用的
- 自己的表单为了能够通过CSRF防护,需要在表单内加一句
{% csrf_token %}
c. django的CSRF防御原理
- 渲染模板文件时,会把
{% csrf_token %}
生成为一个名字叫做csrfmiddlewaretoken
的隐藏域(input:hidden)。 - 当启用中间件并加入标签csrf_token后, 服务器交给浏览器保存一个名字为csrftoken的cookie信息, 它的值和上面的隐藏域的值相同。
- 当提交请求的时候,django会检查这两个值是否都有,并且是否匹配;如果对比失败则返回403页面,而不会进行后续的处理。
6.10 验证码
将验证码的内容保存在session内,然后生成一张图片发送给用户,让它输入,之后和服务器session的内容对比。
代码不用自己背,网上有很多:
pip install Pillow==3.4.1
- 提示1:随机生成字符串后存入session中,用于后续判断。
- 提示2:视图返回mime-type为image/png。
from PIL import Image, ImageDraw, ImageFont
from django.utils.six import BytesIO
...
def verify_code(request):#引入随机函数模块import random#定义变量,用于画面的背景色、宽、高bgcolor = (random.randrange(20, 100), random.randrange(20, 100), 255)width = 100height = 25#创建画面对象im = Image.new('RGB', (width, height), bgcolor)#创建画笔对象draw = ImageDraw.Draw(im)#调用画笔的point()函数绘制噪点for i in range(0, 100):xy = (random.randrange(0, width), random.randrange(0, height))fill = (random.randrange(0, 255), 255, random.randrange(0, 255))draw.point(xy, fill=fill)#定义验证码的备选值str1 = 'ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0'#随机选取4个值作为验证码rand_str = ''for i in range(0, 4):rand_str += str1[random.randrange(0, len(str1))]#构造字体对象,ubuntu的字体路径为“/usr/share/fonts/truetype/freefont”font = ImageFont.truetype('FreeMono.ttf', 23)#构造字体颜色fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255))#绘制4个字draw.text((5, 2), rand_str[0], font=font, fill=fontcolor)draw.text((25, 2), rand_str[1], font=font, fill=fontcolor)draw.text((50, 2), rand_str[2], font=font, fill=fontcolor)draw.text((75, 2), rand_str[3], font=font, fill=fontcolor)#释放画笔del draw#存入session,用于做进一步验证request.session['verifycode'] = rand_str#内存文件操作buf = BytesIO()#将图片保存在内存中,文件类型为pngim.save(buf, 'png')#将内存中的图片数据返回给客户端,MIME类型为图片pngreturn HttpResponse(buf.getvalue(), 'image/png')
看不清,换一个图片
<script type="text/javascript" src="/static/jquery-1.12.4.min.js"></script>
<script type="text/javascript">$(function(){$('#change').css('cursor','pointer').click(function() {$('#yzm').attr('src',$('#yzm').attr('src')+1)});});
</script>
...
<img id="yzm" src="/verify_code/?1"/>
<span id="change">看不清,换一个</span>
6.11 ★URL反向解析
给一个自己配置的route URL命名,这样当URL改变时,其他跳转的连接如果是名字引用,那么就不需要在每个HTML页面中修改跳转地址。
- 反向解析应用在两个地方:
- 模板中的超链接
- 视图中的重定向。
步骤:
- url配置的时候,在
include
中指定参数namespace
- 在每个匹配view的路由中指定
name
参数
在模板中使用url标签
在视图中使用reverse函数
a. 模板超链接使用 URL反向解析
在模板文件中跳转的时候,书写:
<a href="{% url 'namespace:name' %}"> 跳转</a>普通链接:<a href="/fan2/">fan2</a>
<hr>
反向解析:<a href="{%url 'booktest:fan2'%}">fan2</a>
- 如果跳转的视图带有位置参数,那么传递参数的方式为—— 用空格隔开:
url(r'^show_args/(\d+)/(\d+)$', views.show_args, name='show_args'), # 捕获位置参数
<a href="{% url 'namespace:name' 1 2 %}"> 跳转</a>
- 如果跳转的视图带有关键字参数,那么传递方式为:—— 用空格隔开
url(r'^show_kwargs/(?P<c>\d+)/(?P<d>\d+)$', views.show_kwargs, name='show_kwargs'), # 捕获关键字参数
<a href="{% url 'namespace:name' c=3 d=4 %}"> 跳转</a>
b. 视图中使用重定向反向解析url
from django.core.urlresolvers import reverse...
def index(request):url = reverse('booktest:index')url = reverse('booktest:index', args=(1,2)) # 传递位置参数url = reverse('booktest:index', kwargs={'c':3, 'd':4}) # 传递关键字参数return redirect(url)# return redirect(reverse('booktest:fan2'))
- 传递位置参数
return redirect(reverse('booktest:fan2', args=(2,3)))
- 传递关键字参数
return redirect(reverse('booktest:fan2', kwargs={'id':100,'age':18}))
7. 其他常用技术
7.1 使用静态文件
项目中的CSS、图片、js都是静态文件。一般会将静态文件放到一个单独的目录中,以方便管理
静态文件可以放在项目根目录下,也可以放在应用的目录下,由于有些静态文件在项目中是通用的,所以推荐放在项目的根目录下,方便管理。
步骤:
在项目根目录下创建文件夹
static
,下面分别创建css, js, images
在配置文件中配置使用静态文件,并且指定路径:
STATIC_URL
设置访问静态文件对应的url。STATICFILES_DIRS
设置静态文件所在的物理目录。
- 在模板文件中引用
<script src="/static/img/a.jpg "></script>
a. ★动态获取静态文件路径
如果每次都在模板文件中写固定的路径,那么STATIC_URL
一改,维护起来就很麻烦。
步骤:
- 在模板文件中写上
<!DOCTYPE html>
{% load staticfiles %}
或者
{% load static from staticfiles %}...
下面使用动态的方式获取静态文件的路径
<img src ="{% static 'images/a.jpg' %}" --> 拿到 /static/images/a.jpg
说明:这种方案可以隐藏真实的静态文件路径,但是结合Nginx布署时,会将所有的静态文件都交给Nginx处理,而不用转到Django部分,所以这项配置就无效了。
b. 静态文件查找顺序
- 先去配置的
STATICFILES_DIRS
中查找 - 然后再去项目app中查找
static
文件夹
from django.conf import settingsprint(settings.STATICFILES_FINDERS)
# ('django.contrib.staticfiles.finders.FileSystemFinder', 这个负责在配置的静态目录下找
# 'django.contrib.staticfiles.finders.AppDirectoriesFinder') 这个负责在app下的static文件夹找
7.2 ★中间件
- 中间件函数是django框架给我们预留的函数接口,让我们可以干预请求和应答的过程。
- 中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健壮性。
- Django在中间件中预置了五个方法,这五个方法的区别在于不同的阶段执行,对输入或输出进行干预
中间件方法 | 作用 | 参数 | 返回值 |
---|---|---|---|
__init__
|
:服务器启动之后接收第一个请求的时候调用。 | self | 无 |
process_request
|
是对每个请求产生request对象之后,进行url匹配之前调用。 | self, request | None或者 HttpResponse |
process_view
|
是在url匹配之后,调用视图函数之前。 | self,request,view_func, *view_args, **view_kwargs | None或者 HttpResponse |
process_response
|
视图函数调用之后,内容返回给浏览器之前,要将response返回。 | self, request, response | HttpResponse |
process_exception
|
视图函数出现异常,会调用这个函数。 | self, request, exception | HttpResponse |
★注:
- 如果在
process_request
中返回了Response的话,那么之后的url匹配还有view就不会被调用了,直接调用process_response
返回结果 - 如果在
process_view
中返回了Response的话,那么之后的view就不会调用了,直接调用process_response
返回结果 - 如果注册了多个包含
process_exception
的中间件类,那么会先调用 后注册的异常处理
a. 调用流程
案例——返回 请求的IP地址
视图函数中
request.META['REMOTE_ADDR']
b. ★使用中间件
步骤:
在app中创建一个文件——
middleware.py
(文件名不是固定的,但是一般叫这个)
在文件中定义一个中间件类, 在内部定义中间件方法
class TestMiddleware(object):'''中间件类'''def __init__(self):'''服务器重启之后,接收第一个请求时调用'''print('----init----')def process_request(self, request):'''产生request对象之后,url匹配之前调用'''print('----process_request----')# return HttpResponse('process_request')def process_view(self, request, view_func, *view_args, **view_kwargs):'''url匹配之后,视图函数调用之前调用'''print('----process_view----')return HttpResponse('process_view')def process_response(self, request, response):'''视图函数调用之后,内容返回浏览器之前'''print('----process_response----')return response
- 注册中间件类
MIDDLEWARE_CLASSES = ('django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.auth.middleware.SessionAuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware','django.middleware.security.SecurityMiddleware',# 'booktest.middleware.BlockedIPSMiddleware', # 注册中间件类# 'booktest.middleware.TestMiddleware','booktest.middleware.ExceptionTest1Middleware','booktest.middleware.ExceptionTest2Middleware',
)
7.3 Admin后台管理
管理类可以定义在admin.py
中, 继承自models.AdminModel
管理类属性 | 含义 |
---|---|
list_per_page = 10 | 控制每页显示多少条 |
list_display = [] | 控制显示哪些列属性/方法 |
actions_on_bottom = True | |
actions_on_top = False | |
list_filter = [‘atitle’] # 列表页右侧过滤栏 | |
search_fields = [‘atitle’] # 列表页上方的搜索框 |
a. 注册模型管理类
管理类有两种使用方式:
- 注册参数
class AreaAdmin(admin.ModelAdmin):pass...admin.site.register(AreaInfo,AreaAdmin)
- 装饰器
@admin.register(AreaInfo)
class AreaAdmin(admin.ModelAdmin):pass
b. 列表页选项
class AreaAdmin(admin.ModelAdmin):list_per_page = 10 # 每页显示多少条actions_on_top=True # 操作选项的位置actions_on_bottom=Falselist_display=[模型字段1,模型字段2,...] # 显示的列字段list_display = ['id','atitle','title'] # 还能将 方法作为列list_filter=['atitle'] # 右侧过滤栏search_fields=['atitle'] # 搜索框class AreaInfo(models.Model):...def title(self):return self.atitle# 方法列是不能排序的,如果需要排序需要为方法指定排序依据。title.admin_order_field='atitle'# 指定列标题title.short_description='区域名称'# 访问关联对象# 无法直接访问关联对象的属性或方法,可以在模型类中封装方法,访问关联对象的成员。def parent(self):if self.aParent is None:return ''return self.aParent.atitleparent.short_description='父级区域名称'
b. 编辑页选项
class AreaAdmin(admin.ModelAdmin):...fields=['aParent','atitle'] # 可编辑字段fieldset=( # 分组显示, 和fields二选一使用('组1标题',{'fields':('字段1','字段2')}),('组2标题',{'fields':('字段3','字段4')}),)inlines = [AreaStackedInline] # 关联对象# inlines = [AreaTabularInline]class AreaStackedInline(admin.StackedInline):model = AreaInfo #关联子对象extra = 2#额外编辑2个子对象class AreaTabularInline(admin.TabularInline):model = AreaInfo#关联子对象extra = 2#额外编辑2个子对象
c. 综合代码
from django.db import modelsclass AreaInfo(models.Model):'''地址模型类'''# 地区名称atitle = models.CharField(verbose_name='标题', max_length=20)# 自关联属性aParent = models.ForeignKey('self', null=True, blank=True)def __str__(self):return self.atitledef title(self):return self.atitletitle.admin_order_field = 'atitle' # 控制这个方法,是按照哪个属性排序title.short_description = '地区名称' # 控制这个方法显示对应列名def parent(self):if self.aParent is None:return ''return self.aParent.atitleparent.short_description = '父级地区名称'class PicTest(models.Model):'''上传图片'''goods_pic = models.ImageField(upload_to='booktest')
from django.contrib import admin
from booktest.models import AreaInfo,PicTest
# Register your models here.class AreaStackedInline(admin.StackedInline):# 写多类的名字model = AreaInfoextra = 2class AreaTabularInline(admin.TabularInline):model = AreaInfoextra = 2class AreaInfoAdmin(admin.ModelAdmin):'''地区模型管理类'''list_per_page = 10 # 指定每页显示10条数据list_display = ['id', 'atitle', 'title', 'parent']actions_on_bottom = Trueactions_on_top = Falselist_filter = ['atitle'] # 列表页右侧过滤栏search_fields = ['atitle'] # 列表页上方的搜索框# fields = ['aParent', 'atitle'] 指定详细页面中字段顺序fieldsets = ( # 分组显示, 这个字段和 fields只能二选一使用('基本', {'fields':['atitle']}),('高级', {'fields':['aParent']}))# inlines = [AreaStackedInline]inlines = [AreaTabularInline]admin.site.register(AreaInfo, AreaInfoAdmin)admin.site.register(PicTest)
d. 修改admin页面模板
步骤:
- 在
templates
文件夹下创建admin
文件夹,里面创建base_site.html
- 在虚拟环境中找到原来的django模板文件:
/home/python/.virtualenvs/py_django/lib/python3.5/site-packages/django/contrib/admin/templates/admin
- 直接复制过来,在里面修改就可以了
7.4 上传文件
步骤:
1. 配置上传文件的保存目录
可以创建在静态文件目录下,也可以不。 创建一个media
文件夹
2. 配置上传文件保存目录
a. 后台上传图片
- 创建模型类
其中创建一个 ImageField
的字段,upload_to
属性指定的是文件夹名称, 这个名称是 配置的上传文件保存目录下的文件夹名称
迁移生成这个模型类对应的表格 —— 内部的这个
ImageField
字段就i变成一个列,用于存放图片保存到的地址信息,而不是完整图片内容。注册模型类,使得后台可以访问
b. 客户端上传图片
http://python.usyiyi.cn/documents/django_182/topics/http/file-uploads.html
http://python.usyiyi.cn/documents/django_182/ref/files/uploads.html#django.core.files.uploadedfile.UploadedFile
- 创建表单和文件上传控件
- 定义接收上传文件的视图函数,在内部来将图片写入文件
request.FILES[name属性]
可以访问到对应的上传文件处理器- 文件处理器有2种:
- <class ‘django.core.files.uploadedfile.InMemoryUploadedFile’> —— 文件小于2.5M时,保存在内存中
- <class ‘django.core.files.uploadedfile.TemporaryUploadedFile’> —— 文件大于2.5M时,保存在临时文件中
- 调用处理器的
chunks
方法,来遍历获取文件内容,然后自行保存在文件内
def upload_handle(request):'''上传图片处理'''# 1.获取上传文件的处理对象pic = request.FILES['pic']# 2.创建一个文件save_path = '%s/booktest/%s'%(settings.MEDIA_ROOT,pic.name)with open(save_path, 'wb') as f:# 3.获取上传文件的内容并写到创建的文件中for content in pic.chunks():f.write(content)# 4.在数据库中保存上传记录PicTest.objects.create(goods_pic='booktest/%s'%pic.name)# 5.返回return HttpResponse('ok')
- 再创建一个对应的模型类对象,将图片存储的位置写入,并且保存到数据库
c. 解决无迁移问题
如果之前在别的项目中使用的是同一个数据库,那么在执行迁移的时候,django是根据app名字+迁移文件名来执行迁移的,那么在之前的app+迁移文件名都相等的情况下,之后项目的迁移不会被执行。
解决办法:
- 删除对应数据库中管理迁移表格中,对应的条目
- 修改迁移文件名
11.5 分页
Paginator
类对象的属性
属性名 | 说明 |
---|---|
count
|
返回对象总数。 |
num_pages | 返回分页之后的总页数 |
page_range | 返回分页后页码的列表 |
Paginator
类对象的方法:
方法名 | 说明 |
---|---|
__init__(obj_list, int)
|
返回分页对象,第一个参数为列表数据,第二个参数为每页数据的条数 |
page(self, number) |
返回第number页的Page 类实例对象
|
Page
类对象的属性
属性名 | 说明 |
---|---|
number | 返回当前页的页码 |
object_list | 返回包含当前页的数据的查询集 |
paginator | 返回对应的Paginator类对象 |
Page
类对象的方法
属性名 | 说明 |
---|---|
has_previous | 判断当前页是否有前一页 |
has_next | 判断当前页是否有下一页 |
previous_page_number | 返回前一页的页码 |
next_page_number | 返回下一页的页码 |
from django.core.paginator import Paginator # 分页对象
paginator = Paginator(areas, 10) #按每页10条数据进行分页
currentPage = paginator.page( currentPageNumber)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>分页</title>
</head>
<body>
<ul>{# 遍历获取每一条数据 #}{# {% for area in page.object_list %}#}{% for area in page %}<li>{{ area.atitle }}</li>{% endfor %}
</ul>
{# 判断是否有上一页 #}
{% if page.has_previous %}<a href="/show_area{{ page.previous_page_number }}"><上一页</a>
{% endif %}{# 遍历显示页码的链接 #}
{% for pindex in page.paginator.page_range %}{# 判断是否是当前页 #}{% if pindex == page.number %}{{ pindex }}{% else %}<a href="/show_area{{ pindex }}">{{ pindex }}</a>{% endif %}
{% endfor %}{# 判断是否有下一页 #}
{% if page.has_next %}<a href="/show_area{{ page.next_page_number }}">下一页></a>
{% endif %}
</body>
</html>
Python视频学习(十二、Django)相关推荐
- 小甲鱼python视频解读_小甲鱼python视频弟十二讲(关于字符串的方法及注释下)...
1,ljust(width[,fillchar])width -- 指定字符串长度. fillchar -- 填充字符,默认为空格. 用法:返回一个原字符串左对齐,并使用空格填充至指定长度的新字符串. ...
- python图像处理笔记-十二-图像聚类
python图像处理笔记-十二-图像聚类 学习内容 这一章主要在学习的是聚类算法以及其在图像算法中的应用,主要学习的聚类方法有: KMeans 层次聚类 谱聚类 并将使用他们对字母数据及进行聚类处理, ...
- OpenCV与图像处理学习十二——图像形状特征之HOG特征
OpenCV与图像处理学习十二--图像形状特征之HOG特征 一.图像特征理解 1.1 颜色特征 1.2 纹理特征 1.3 形状特征 1.4 空间关系特征 二.形状特征描述 2.1 HOG特征 2.1. ...
- PyTorch框架学习十二——损失函数
PyTorch框架学习十二--损失函数 一.损失函数的作用 二.18种常见损失函数简述 1.L1Loss(MAE) 2.MSELoss 3.SmoothL1Loss 4.交叉熵CrossEntropy ...
- (转)SpringMVC学习(十二)——SpringMVC中的拦截器
http://blog.csdn.net/yerenyuan_pku/article/details/72567761 SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter, ...
- 【FastAPI 学习十二】定时任务篇 (移步博客园或个人网站 无广告,界面清爽整洁)
声明 目前个人放弃CSDN平台,文章只发布于个人网站和博客园 博客园地址 [FastAPI 学习十二]定时任务篇
- python二级第十二套答案
python二级第十二套答案 46.考生文件夹下存在三个Python源文件,分别对应三个问题,请按照文件内说明修改代码,实现以下功能: 法定节假日是根据各国.各名族的风俗习惯或纪念要求,由国家法律统一 ...
- C1认证学习十二(网络拓扑)
C1认证学习十二(网络拓扑) 任务背景 互联网是一个广义的概念,它泛指是一切通过网路连接在一起的计算机的集合,所以,若果只是局部观察,那就不能再说互联网是一个互联的了,那么,如果说对于一个公司来说,具 ...
- 跟着小甲鱼学python怎么样_跟着小甲鱼的python视频学习,小白能够接受吗?
查看: 3709|回复: 14 跟着小甲鱼的python视频学习,小白能够接受吗? 电梯直达 发表于 2018-4-29 16:57:27 | 只看该作者 |倒序浏览 |阅读模式 马上注册,结交更多好 ...
- Python基础学习(二)-条件,循环语句
Python基础学习(二)-条件,循环语句 一,条件语句 1,if else if 判断条件: 执行语句... e ...
最新文章
- base64的c语言实现方法
- VTK:PolyData之SmoothPolyDataFilter
- mysql数据类型优化
- 如何为报表服务器设置SQL Server数据库复制
- android 状态模式,Android编程设计模式之状态模式详解
- ffmpeg屏幕推流
- python的flask微服务-flask微服务框架的初步接触
- 最小上界sup(来自wiki)
- 楼梯计算机方法,怎么计算楼梯踏步方法是什么
- [QCTF2018]Xman-RSA
- 关于单片机电路中NPN三极管与PNP三极管的接法问题
- 高德地图自定义绘制园区区域,区域描边,并添加自定义内容maker标注
- oracle 实用记录
- unity2D小鸟飞过柱子小游戏
- 如何变更Win10系统电脑的锁屏壁纸?分享经验!怎样选择Win10电脑的锁屏壁纸?
- 02 NCC定时任务开发
- kvm安装ovmf,增加UEFI启动模式
- Android动画学习记录二(属性动画、估值器和插值器)
- 用火狐浏览器看中一段代码是复制外部html还是复制内部html,为什么PDF文件用某些浏览器读取就可以复制出其中的文字,而用WPS等办公软体就不可以复制出呢?...
- matlab计算不同时间步长,Matlab ODE求解器中的时间步长计算