入门
MVC,MTV
- MVC 和 MTV都是框架。
- MVC:M:model,与数据库的增删改查相关的;V,View,视图:和页面呈现相关的,(js,css,html);c,controler,控制器,业务逻辑处理相关的,函数
- MTV:基于MVC的,将C的一部分 功能内置化,剩余的功能和V复合后再拆分,其中跟模板,数据库相关的就是MTV中的M,跟页面呈现相关的形成了MTV中的T,跟业务逻辑相关的就形成了MTV中的V。
- 简单的说,MTV中的M就是一大堆用来映射数据库表的类,T就是一堆CSS,JS,HTML文件,V,就是一大堆函数
创建一个简单的Django服务器的流程
- 进入虚拟环境
sorurce ~/virtualenvs/py3_Django/bin/activate
- 创建项目
cd ~/Desktop/Django_review/
django-admin startproject michael
- 创建应用
cd michael
python manage.py startapp helloworld
- 注册应用
vim michael/settings
INSTALL_APP = [ 。。。 'helloworld', ]
- view,url配置
vim helloworld/views.py
from django.shortcuts import render from django.http import HttpResponse # Create your views here. def hello(resquest): return HttpResponse("hello world")
vim micheal/urls.py
from test1.views import * urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^hello/$', hello), ]
- 启动django
cd michael
python manage.py runserver
在浏览器输入:127.0.0.1:8000/hello 可验证
模型
当前的项目开发,都是数据驱动的。django中,可以利用ORM框架,在代码中,使用模型类的方式,定义表,表的字段(约束)甚至完成数据库的CRUD,不需要直接面向数据库编程。
ORM框架
- 对象关系映射。在Django框架中,使用模型类映射数据库中的表结构。一个模型类,映射数据库中的一张表。
- 利用模型类和类对象,可以完成面向对象的建表及数据库的增删改查操作。
使用步骤:
1.在mondel.py中定义模型类 2.迁移 3.通过类和对象完成数据的增删改查操作
后台管理
- 用Django做web,会内置一个后台管理的平台。
- 作用是让专门的人员来维护数据库。如方便的添加,删除商品的sku数据
- 使用步骤
- 1.管理页面本地化
- 2.创建管理员
- 3.注册模型类
- 4.自定义管理页面
- 1.管理页面本地化
setting.py:
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
- 2.创建管理员
终端:
python manage.py createsuperuser
- 3.注册模型类
helloworld.admin.py:
from booktest.models import BookInfo,HeroInfo
admin.site.register(BookInfo)
admin.site.register(HeroInfo)
- 4.自定义管理页面
class BookInfoAdmin(admin.ModelAdmin):
list_display = ['id', 'btitle', 'bpub_date']
admin.site.register(BookInfo, BookInfoAdmin)
视图
- 当在浏览器输入一个url,服务器会接收到这个url,并进行相应的逻辑处理后,返回结果给浏览器,这个逻辑处理的过程,就在视图模块中完成
视图模块是MTV中的中枢,请求从这里进入,也会从这里返回
使用步骤
- 定义视图函数
- 配置urlconf
# 定义应用里的视图函数
helloworld.views.py:
from django.http import HttpResponse
def hello(resquest):
return HttpResponse("hello world")
# 配置url
michael.urls.py:
...
from helloworld.views import *
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^hello/$',hello),
]
模板
- 是生成显示页面的模块
有 css代码,js,HTML代码
定义模板步骤
- 在项目目录下新建templates文件夹
- templates里新建与应用同名的文件夹helloworld
- 在helloworld文件夹里新建index.html文件
- 编写html文件
<!DOCTYPE html>
<html>
<head>
<title>图书列表</title>
</head>
<body>
<h1>{{title}}</h1>
{%for i in list%}
{{i}}<br>
{%endfor%}
<div>这是一段文字</div>
</body>
</html>
- 在settings.py里将templates文件夹加入到环境变量里
# 在settings.py里将templates文件夹加入到环境变量里
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
...
views.py 调用模板 步骤
- 获取模板文件
- 定义上下文
- 渲染模板并将模板返还给浏览器
... from django.template import loader, RequestContext def index(request): # 1.获取模板 template = loader.get_template('helloworld/index.html') # 2.定义上下文 context = RequestContext(request, {'title': '图书列表', 'list': range(10)}) # 3.渲染模板 index_html = template.render(context) # 4.将模板返还给浏览器 return HttpResponse(index_html)
模型
- orm
- 对象关系映射技术,在django框架和关系型数据库之间建立一层转换层。使得django中mondels.py的模型类与关系型数据库中的表一一映射,在modles.py的类对象调用的一些方法,也会在ORM层转换为sql语句对数据库进行操作。
- 好处是框架使用者只需要面向对象编程即可,配置好数据后不需要再去关心数据库
- 实现了数据模型与数据库的解耦,当需要更改数据库的时候,只需要简单的配置即可,不需要大量修改代码
定义属性
- 模型类的属性在ORM之后映射为数据库表结构的字段
属性命名格式
- 需要先导入django.db.models包
属性 = models.字段类型(选项)
字段类型有:
- AutoField:自动增长的integerField,通常不指定,不指定时Django会自动创建属性名位id的自动增长属性
- BooleanField:布尔字段,值为True,False
- NullBooleanField:支持Null,True,False
- CharField(max_length=字符长度):字符串
- TextField:大文本字段,一般超过4000个字符时使用
- IntergerField:(max_digits=None,decimal_places=None):10进制,浮点数
- FloatFiled:浮点数
- DateFiled([auto_now=False,auto_now_add=False]):日期
- TimeField:时间
- DateTimeField:日期时间
- FileField:上传文件字段
- ImageField:继承与FileField,对上传的内容进行校验,确保是有效的图片
选项有:
- null:如果为True,表示允许为空,默认是False
- blank:如果为True,表示允许为空白,默认值是False
- db_column:字段的名称,如果未指定,则使用属性的名称
- db_index:若为True,则在表中会为此字段创建索引,默认为False
- default:默认值
- primary_key:若为True,则该字段会成为模型的主键字段,默认为False,一般作为AutoField的选项使用
- unique:如果为True,这个字段在表中必须有唯一值,默认值为False
字段查询
实现SQL中的where功能
方法
- filter()
- exclude()
- get()
条件查询,就需要对字段信息进行判断
- 属性字段查询判断格式 :
属性名__比较运算符=值
常用的运算符
- exact:表示判等
- contains:表示包含,模糊查询
- startwith,endwith:以指定值开头或者结尾
- isnull:是否为null
- in:是否包含在范围内
- gt,gte,lt,lte:大于,大于等于,小于,小于等于
- exclude:取反
- year,month,day,week_day,hour,minute,second:对时间进行判断
- F对象:上面的都是属性与常量值比较。如果两个属性比较,就是用F对象
示例: from django.db.models import F ... list = BookInfo.objects.filter(bread_gte=F('bcoment'))
- Q对象:当需要使用逻辑表达式的时候,使用Q对象,能不用,就不用,有时候用了,反而更麻烦
&,|,~(与或非) from django.db.models import Q #查询阅读量大于20,或编号小于3的图书 BookInfo.objects.filter(Q(bread__gt=20)|Q(id__lt=30)) #查询编号不等于3的图书 BookInfo.objects.filter(~Q(id=3)) 也可以使用 BookInfo.objects.exclude(id=3)
聚合函数查询
- 使用aggregate()调用聚合函数
- 格式:
类名.objects.aggrehate(函数(字段))
- 其中,函数有
Avg():取平均值 Count():求总数 Max():求最大值 Min():求最小值 Sum():求总数
- 示例
# 查询图书的总阅读量 from ddjango.db.models import Sum list = BookInfo.objects.aggragate(Sum('bread'))
- 注意,aggregate返回的是一个字典类型
{'bread_sum':3}
- 使用count时一般不适用aggragate()过滤器
- 如,查询图书总数:
list = BookInfo.objects.count()
查询集
- 表示从数据库中获取对象的集合,等同于sql中的select
- 通过在管理器上调用某些过滤器,会返回查询的结果集
过滤器:
- 返回单个值的过滤器
get():返回满足条件的对象,只返回第一个 count:返回当前查询结果的总条数 aggregate():聚合查询,返回一个字典
- 返回多个值的过滤器
all():返回所有值 filter():返回满足条件的值 exclude():返回不满足条件的所有值,取反 order_by():对结果进行排序,默认由小到大,如果要由大到小,加’-‘
判断一个查询集是否有数据
- exists()
两大特性
- 惰性查询:创建查询集,不会访问数据库,直到调用数据时,才会访问数据库。调用数据库的情况包括,迭代,序列化,与if合用
- 缓存:使用一个查询集,第一次使用会发生数据库的查询,然后会把结果缓存下来,再次使用这个查询集时,会使用缓存数据
限制查询集
- 可以对查询集进行取下标或者切片的操作,相当于SQL中的limit,offset语句
list = BookInfo.objects.all()[0:2]
关联查询
模型类关系
模型类关系,等同于数据库表的关系
- ForeignKey:一对多,将字段定义在多的一方
- ManyToManyField:多对多,将字段定义在任意一段
- OneToOneField:一对一,将字段定义在任意一方
关联查询
- 相当于sql中的join
- 一对多中
# 由一到多的访问,如1:图书,多:英雄 b = BookInfo.objects.get(id=1) b.heroinfo_set.all() # 由多到一的访问,如,多:英雄,1:图书 h = HeroInfo.object.get(id=1) book_object = h.hbook #hbook为HeroInfo里定义的一个外键字段 # 想获得所属图书的id book_id = h.hbook_id
由多模型类 查询 1模型类的数据 数据集
- 格式:
模型类名小写__属性名__条件运算符=值
# 查询图书,要求图书中英雄的描述包含'八' list = BookInfo.objects.filter(heroinfo__hcontet__contains=’八‘)
- 格式:
由1模型类 查询 多模型类的数据 数据集
- 格式:
模型类名小写__属性名__条件运算符=值
# 在英雄信息类里,查询书名为“天龙八部”的所有英雄。 list = HeroInfo.objects.filter(hbook__btitile="天龙八部")
- 格式:
自关联
- 地区信息的查询,将省市区信息放在同一张表里进行自己查询自己的形式
为了充分利用数据表的信息
使用流程
#1.定义地区模型类,存储省、市、区县信息 class AreaInfo(models.Model) atitle = models.charField(max_length=30) aparent = models.Foreignkey('self', null=True, blank=True)
- 2.导入数据
# 3.定义视图函数 from booktest.models import AreaInfo ... #查询广州市的信息 def area(request): area = AreaInfo.objects.get(atitle='广州市') return render(request, 'booktest/area.html', {'area': area})
- 4.在模板中,使用自关联查询
<html> <head> <title>地区</title> </head> <body> 当前地区:{{area.atitle}} <hr/> 上级地区:{{area.aParent.atitle}} <hr/> 下级地区: <ul> {%for a in area.areainfo_set.all%} <li>{{a.atitle}}</li> {%endfor%} </ul> </body> </html>
拓展
管理器:models.Manager类的对象
- objects是管理器,是models.Manager类型的对象
用于与数据库的交互
- 自定义管理器
- 当没有为模型类定义管理器的时候,Django会为每一个模型生成一个名为objects的管理器
当需要自定义管理器的时候,可以新建一个管理器类,继承子models.Model
- 什么时候需要自定义管理器
1.增加额外的方法,如默认管理器不可以给数据库添加新数据,那么,自定义管理器可以增加这个方法
# 自定义管理器,增加create_book方法,完成增加数据的任务 class BookInfoManager(models.Manager): ... #创建模型类,接收参数为属性赋值 def create_book(self, title, pub_date): #创建模型类对象self.model可以获得模型类 book = self.model() book.btitle = title book.bpub_date = pub_date book.bread=0 book.bcommet=0 book.isDelete = False # 将数据插入进数据表 book.save() return book # 在模型类中实例化自定义管理器对象 class BookInfo(models.Model): ... books = BookInfoManager() # 调用 book=BookInfo.books.create_book("abc",date(1980,1,1))
2.修改原始的查询集 方法,满足一些默认情况下满足不了的需求
# 图书信息表管理器 class BookInfoManager(models.Manager): def get_queryset(self): # 默认查询未删除的图书信息 # 调用父类的成员语法:super(子类型,self).成员 return super(BookInfoManager, self).get_queryset().filter(isDelete=False) # 在模型类BookInfo中定义管理器 class BookInfo(models. Model): ... books = BookInfoManager() # 这个就相当于 objects # 调用 books_have = BookInfo.books.filter(isDelete=False)
原选项
- 在模型类中定义类Meta,如使用db_table自动以表的名字
- 示例:指定BookInfo模型类生成的数据表名为bookinfo
# 定义图书类型类BookInfo
class BookInfo(models.Model):
...
# 定义元选项
class Meta:
db_table = ’bookinfo‘ # 指定BookInfo生成的数据表名为bookinfo
视图
- 视图就是一个函数,所以常说视图函数
- 视图负责接受Web请求的HttpRequest,进行逻辑处理,返回WebResponse给请求者
- 响应可以是一张网页的HTML页面,一个重定向,一个404(页面未找到)的错误
- 创建视图函数:django中在应用文件夹中的views.py中创建视图函数
from django.shortcuts import render
from booktest.models import BookInfo
# 首页,展示所有图书
def index(reqeust):
# 查询所有图书
booklist = BookInfo.objects.all()
# 将图书列表传递到模板中,然后渲染模板
return render(reqeust, 'booktest/index.html', {'booklist': booklist})
urlconf
用户通过在浏览器中输入网址发起请求。对于Django开发的网站,由哪一个视图函数来处理,由urlconf来设置
配置步骤
- 1.在项目名/settings.py中通过ROOT_URLCONF指定url配置。默认已经配置
ROOT_URLCONF = 'michael.urls'
- 2.打开项目名/urls.py,添加新的url路径
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^hello/$',hello), url(r'^index/$',index), url(r'^$',include('booktest.urls')) ] 注意点: 1.在项目名/urls.py中进行包含配置,在各自应用中进行具体配置 2.定义urlpatterns列表,存储url()对象,这个名称是固定的
url()语法
- url()被定义在django.conf.urls包中,有两种语法结构
- 1.包含:
url(正则,include('应用.urls'))
- 如:
url(r'^$', include('booktest.urls'))
- 2.直接指定视图函数的名字:
url(正则,'视图函数的名字')
- 如:
from django.conf.urls import url from booktest import views urlpatterns = [ url(r'^$', views.index), ]
获取值
- 传到urls.py里的url是经过裁剪的,会去掉ip,port,及参数,只匹配剩下的部分
- 匹配是使用正则进行匹配的
- 正则中可以匹配位置参数和关键字参数
#位置参数 url(r'^show/(\d+)_(\d+)$', views.show), #关键字参数 url(r'^show/(?P<id1>\d+)_(?P<id2>\d+)$', views.show),
内置错误视图
- 404错误:page not found 视图
- 500错误:server error 视图
- 如果想自定义404或者500视图,只需要在项目名/templates/下自定义404.html/500.html就行了
如果想看到错误视图而不是调试信息
- 修改settings.py里的DEBUG项
DEBUG = False # 表示设置可以访问的主机地址,*代表任意地址都可以访问 ALLOWED_HOSTS = ['*',]
HttpRequest对象
- 服务器接收到HTTP协议的请求后,会根据报文创建HttpRequest对象。这个对象不需要我们创建,直接使用服务器构造好的对象就可以
- 视图函数的第一个参数必须是HttpRequest对象
- 在django.http模块中定义了HttpRequest对象的API
属性
既然HttpRequest是一个请求对象,那么它就会有一些可以调用的属性
- path:一个字符串,表示请求页面的完整路径,不包括域名和参数部分
- method:一个字符串,表示请求使用的HTTP方法。常用值包括’GET‘,’POST’
- encoding:一个字符串,表示提交数据的编码方式,这个属性是可写的
- GET:QueryDict类型对象,类似于字典,包含get请求方式的所有参数
- POST:QueryDict类型对象,类似于字典,包含post请求方式的所有参数
- FILES:类似与字典的对象,包含所有上传的文件
- COOKIES:标准的字典,包含所有的cookie,键和值都为字符串
- session:类似字典的对象,可读可写,表示当前的会话,只有当django启用会话的支持时才可使用
QueryDict对象
- 定义在django.http.QueryDict类
- HttpRequest对象的属性GET,POST都是QueryDict类型的对象
- 类似字典的结构,与python字段不同,QueryDict对象用来处理同一个键带多个值的情况
- 使用get(),根据键,获取值:如果一个键有多个值,获取最后一个值;如果不存在,则返回None,可以设置默认值进行后续处理
dict.get('键',默认值) 可简写为: dict['键']
- 使用getlist(),根据键获取值,值以列表返回,可以获取指定键的所有值
- 如果键不存在则返回空列表,可以设置默认值进行后续处理
dict.getlist('键',默认值)
GET属性
- 一个get请求的url中
http://www.VisionaryX.cn/?a=10&b=20&c=python
- 其中,参数部分为:
?a=a0&b=2-&c=python
- 其中,参数部分为:
- 在Django中可以使用HttpRequest对象的GET属性获取get请求的参数
- GET属性是一个QueryDict类型的对象,键和值都是字符串类型
- 其中键是开发人员在编写代码时确定的,值是根据数据生成的
POST属性
- 使用form表单请求时,method 方式为post,则会发起post请求
- 需要使用HttpRequest对象的POST属性来接受参数
- POST属性是一个QueryDict类型的对象
- 表单form如何提交参数?
- 表单控件 name属性的值作为键,value属性的值作为值,构成键值对提交
- checkbox控件,会出现一键多值的情况
- 键是开发人员写的,值是用户填写或者选择的
HttpResponse对象
- 视图在接受请求并且处理后,必须返回HttpResponse对象或者子对象
- 在django.http 模块中定义了HttpResponse对象的API
- HttpRequest对象由Django创建,HttpResponse对象由开发人员创建
属性
- 既然是对象,就会有可以调用的属性/方法
- content:表示返回的内容
- charset:表示response采用的编码字符集,默认utf-8
- status_code:返回HTTP响应的的状态吗
- content-type:指定返回数据的类型,默认为’text/html‘
方法
- 有些内置方法,可以对属性进行操作
- __inint__:创建HttpResponse对象后完成内容的初始化
- set_cookie:设置cookie信息
- set_cookie(key, value='', max_age=None, expires=None)
“`
cookie是网站以键值对格式存储在浏览器的一段纯文本信息,用来实现用户追踪
.max_age:是一个整数,表示在指定秒数后过期
.expires:是一个datetime或timedelta对象会话将在这个指定的日期/时间过期。
.max_age与expires二选一
.如果不指定过期时间,在关闭浏览器时,cookie会过期
“`
- delete_cookie(key):删除指定的key的Cookie,如果KEY不存在,则什么也不发生
- write:向响应体中写入数据
- 返回响应的步骤
- 方法1:
1.加载模板
2.构造上下文
3.使用上下文渲染模板
4.返回渲染后的响应对象
from django.template import RequestContext, loader
...
def index(request)
# 加载模板
t1 = loader.get_template('templates/应用名/index.html')
# 构造上下文
context=RequestContext(request,{'h1':'hello'})
# 使用上下文渲染模板
response_data = t1.render(context)
# 返回响应
return HttpResponse(reponse_data)
- 方法2:
- 直接使用render()函数封装了以上几个步骤
from django.shortcuts import render
...
def index(request):
return render(request, 'templates/应用名/index.html',{'h1':'hello'})
JsonResponse对象
- 前端在JS代码中发送ajax请求到后端时,后端此时会以JsonResponse对象的形式返回给ajax
- JsonResponse类在django.http模块中,继承自HttpResponse类
- 创建对象时接收字典
- JsonResponse对象的content-type为‘application/json’
HttpResponseRedirect
- 当一个逻辑处理完成后,不需要向用户呈现数据,而是转到其他页面,如添加成功,修改成功,删除成功后显示数据列表,而数据的列表的视图已经开发完成,此时不需要重新编写呈现列表的代码,而是转到这个视图就可以,此时就需要模拟一个用户请求的效果,从一个视图转到另一个视图,这个过程就叫做重定向
- Django中提供了HttpResponseRedirect对象实现重定向功能。他的类继承自HttpResponse,被定义在django.http模块中,返回的状态码是302
一般代码:
from django.http import HttpResponseRedirect
...
# 定义重定向视图,转向首页
def test_redirect(request):
return HttpResponseRedirect('/')
简写形式
- 在django.shortcuts模块中重定向提供了简写函数redirect
from django.shortcuts import redirect
...
def test_redrect(request)
return redirect('/')
状态保持
浏览器请求服务器是无状态的
- 无状态是指一次用户请求后,浏览器和服务器无法知道这个用户做过什么,每次请求都是一个新的请求
- 原因:应用层面,浏览器和服务器都遵守HTTP协议
- 本质原因:浏览器和服务器之间是通过socket进行通信的,而一次通信结束后,会关闭当前的socket链接(短连接)
- 但是有时候需要保存用户的浏览状态,如服务器想知道用户是否登陆过,浏览器哪些商品,等
状态保持的方式
- cookie:在客户端存储状态信息
- session:在服务器端存储状态信息
cookie
- 有时也写作cookies,是指某些网站为了辨别用户身份,进行session跟踪而存储在浏览器本地的数据。
特点
- cookie以键值对的格式进行信息存储
- cookie基于域名安全,不同域名的cookie是不能互相访问的
- 当浏览器请求某网站时,会将浏览器存储的跟网站相关的所有cookie信息提交给服务器
应用场景
- 记住用户名
- 网站的广告推送
Django中cookie的读写
- 设置cookie
- 先创建HttpResponse对像,然后使用HttpResponse对象的set_cookie()对cookie进行设置
def cookie_set(request): # 创建响应报文对象 response = HttpResponse("<h1>设置cookie,请查看响应报文头</h1>") # 使用响应报文对象设置cookie response.set_coookie('h1','nihao') # response.set_cookie('h1','你好'.encode().decode('latin1')) return response
- 读取cookie
- cookie信息被包含在请求头中,使用request对象的COOKIES属性访问
def cookie_get(request): HttpResponse("读取cookies,数据如下:<br>") if 'h1' in request.COOKIES: response.write('<h1>'+resquest.COOKIES['h1']+'</h1>') return response
- 设置cookie
session
- session是在服务器端提状态保持的方式
对于敏感重要的信息,如用户名,余额,等级,验证码等信息,要存储在服务器端的session中,而不要存储在浏览器的cookie里
也是以键值对的形式存储信息
操作session包括三个值:键,值,过期时间
启用session
- Django中以中间件的形式启用session,需要启用,在settings.py中的MIDDLEWARE_CLASSES=()中添加一个中间件:
django.contrib.sessions.middleware.SessionMiddleware
即可。停用,将这个中间件语句删除即可
- Django中以中间件的形式启用session,需要启用,在settings.py中的MIDDLEWARE_CLASSES=()中添加一个中间件:
存储方式
- session键值对信息存储的地方,在settings.py中的SESSION_ENGINE项中设置
- 存储在数据库中
SESSION_ENGINE="django.contrib.sessions.backends.db"
- 存储在缓存中
SESSION_ENGINE="django.contrib.sessions.backends.cache"
混合存储
ESSION_ENGINE="django.contrib.sessions.backends.cache_db"
如果存储在数据库中,需要在settings.py的INSTALLED_APPS中注册Session应用
INSTALLED_APPS=( ... 'django.contrib.sessions', ... )
迁移后数据库中会创建session表
所有请求者的session都会存储在服务器中,那么服务器如何区分不同请求者的session呢?
- session 依赖于cookie
- 在使用session的时候,cookie中会存储一个seesionid的数据,每次请求时,浏览器都会将这个数据发给服务器,服务器在收到sessionid后,会根据这个值匹配到相应的session
- 所以要想使用session,浏览器必须支持cookie,session依赖于cookie才能使用
对session进行操作
- session通过HttpRequest对象进行设置
- 设置session:
request.session['键']=值
- 读取session:
request.session.get('键',默认值)
- 清除session中的值:
request.session.clear()
- 清除整条session:
request.session.flush()
- 删除session中的某个键值对:
del request.session['键']
- 设置会话超时时间 :
request.session.set_expiry(value)
- value,整数:会话将在value秒后过期
- value,0:会话将在关闭浏览器后过期
- vaLue,None:会话永远不过期
模板
- 用于编写HTML代码
- 表达页面外观,不是程序逻辑。实现了业务逻辑和现实内容的分离
- 一个视图可以使用任意一个模板,一个模板可以供多个视图使用
- 包含部分
- 静态部分:html,css,js
- 动态部分 :模板语言
- django中处理模板的阶段
- 1.加载:根据给定的路径找到模板文件,编译后放在内存中
- 2.渲染 :使用上下文数据对模板插入值并返回生成的字符串
使用步骤:render(request, ‘模板路径’, 上下文对象)
- 第一个参数为request对象
- 第二个参数为模板文件路径
- 第三个参数为字典,表示向模板中传递的上下文数据
示例:
from django.shortcuts import render def index(request): context = {'title':'图书列表',‘list’:range(10)} return render(request, 'booktest/index.html', context)
模板语言
- 在html代码中动态填入执行的模板语句
- 四种类型
- 变量
- 标签
- 过滤器
- 注释
变量
- 动态调用的值,可以是各种数据类型,包括对象的属性/方法
- 格式:{{ 变量 }}
- 如,变量为{{book.title}},表示
- 先调用字典book的key ,title对应的值
- 如果是一个对象,如模型对象,则先查找对象的属性title,没有,再调用对象的title方法
- 在模板调用方法时不能传参数
- 如果变量不存在,则插入空字符串,”
- 如,变量为{{book.title}},表示
标签
- 一些语法结构
- 格式:{%代码段%}
常用标签
- for循环语句标签
# 循环逻辑结构 {%for item in 列表%} {%endfor%} # 其中还可以增加其他方法 {{forloop.counter}}:表示当前第几次循环,从1开始 {%empty%}:列表为空或者不存在时执行此逻辑
示例:
url.py: url(r'^test_for_biaoqian/$', test_for_biaoqian), views.py: def test_for_biaoqian(request): """ 测试模板语言中的标签 for循环结构的使用 :param request: :return: """ context = {'list1':[1,2,3,4,5]} return render(request, 'test1/test_biaoqian.html', context) test_biaoqian.html: {% for i in list1 %} 这是第{{ forloop.counter }}次循环,值为:{{ i }}<br> {% empty %} 空列表 {% endfor %}
if选择语句标签
{%if 条件1%} 逻辑1 {%elif 条件2%} 逻辑2 {%else%} 逻辑3 {%endif%} # 注意运算符两侧不能紧挨着变量或者常量, 必须要有空格
过滤器
- 对变量或者获取到的结果集进行进一步操作(计算,转换等)
- 格式:
变量|过滤器:参数
常用过滤器
- length:
变量|length
- 若变量为字符串,返回字符串中字符的个数
- 若变量为列表,元组,字典,则返回元素的个数
- default:
变量|default:'默认值'
- 若变量不存在,则返回默认值
- date:
date_value|date:"Y年m月j日 H时i分s秒"
- 对日期类型的值进行格式化
- length:
自定义过滤器
- 使用Library对象的filter方法进行注册自定义的函数即可
- 步骤
在应用目录下创建templatetags目录,templatetags目录下创建filters.py文件,filter.py文件代码如下: 1. 导入模块:from django.template import Library 2. 实例化对象:register = Library() 3. 以装饰器的形式对自定义的过滤器进行注册 @register.filter # 定义求余函数mod def mod(value): return value%@ == 0
- 使用
1.使用load标签引入模块:{%load filters%} 2.和正常过滤器一样调用即可:{% if book.id|mod%}
- 需要传参,只需要在定义过滤器函数的时候,在第一个参数之后添加如要传的参数即可
@register.filter def mod_num(value, num) return value%num
注释
- 添加的一些说明
格式
- 单行注释:
{#...#}
- 多行注释:
{%comment%} ... {%endcomment%}
- 单行注释:
模板继承
- 像类的继承一样,为了提高代码的复用性,直接使用父类的通用模板内容,子模板只需要定义需要重写的内容块即可
父模板
- 有基础模板的HTML文件
- 可以预留块标签,是供子模板重写的,可以填写默认值,当字模板没有重写的时候使用默认内容
{%block 名称%} 预留区域,可以编写默认内容,也可以没有内容 {%endblock 名称%}
字模板
- 继承父模板的HTML文件
- 字模板的第一行要写:
{%extends "父模板路径"%}
,表示继承的父模板 - 字模板可以填充父模板预留的块标签,如果不填充,且父模板有默认内容的化,会使用默认内容
- 也可以既重写父模板中的预留块标签中的内容,又继承父模板预留块标签中的默认内容
{%block 名称%} 实际内容填写,如果不填写,且父模板的这个块标签中有内容,就会继承 {{block.super}} 如果填写了自己的内容,也想继承父模板中该块标签中的默认内容,就使用这个变量 {%endblock 名称}
HTML转义
- 模板对上下文传递的字符串进行输出时,会对一些字符进行转义
它们包括
- < : <
- > : >
- ’ : '
- ” : "
- & : &
如果不希望被转义,就是希望被编译执行,如上下文的字符串是一个完整的标签形式
方法1:
{%autoescape off%} ... {%endautoescape%}
方法2:
硬编码,就是使用一个默认的过滤器 {{data|default}:'<b>hello</b>'}
CSRF
- cross site request forgery,跨站点请求伪造
- C代表用户,A代表正常网站,B,代表坏蛋网站。C访问A网站并且登录成功,这个时候A网站会向C浏览器写入cookie,完成C和A网站的状态保持。在没有退出登录A网站的前提下,C又登录了B网站,B网站会在自己的浏览器上模拟C发送请求到A网站,在A网站上对C的信息进行操作
危害
- 以C的名义发邮件,发消息,盗取账号,转账,欺诈C的亲友。。造成个人隐私泄露及财产损失
- 如扣扣号,微信号被盗
怎么避免CSRF
- 1.重要信息的传递使用POST,不要用get
- 2.在django的settings.py文件中的MIDDLEWARE_CLASSES设置项开启csrf中间件
- 将
django.middleware.csrf.CsrfViewMiddleware
注释去掉,默认是去掉的
- 将
- 3.在form表单中加一个标签:
{%csrf_token%}
原理
- 当启用中间件并加入标签csrf_token后,form表单会自动生成一行隐藏起来的input元素,里面是加密的csrftoken值,这个csrftoken值也会写入浏览器的cookie中。在浏览器进行提交表单的处理时,会把cookie一同提交给服务器,服务器会通过中间件的形式首先验证一下cookie中的csrftoken值和表单隐藏input标签的csrftoken的值是否一致,如果一致,再进行操作,否则,直接返回403,不再进行之后的操作
验证码
- 为了防止用户暴力注册,机器点击,而在一定条件下触发的随机字码,用户验证通过后,才能继续操作
- 调用第三方库实现这个功能:PIL模块
- 实现步骤
- 定义生成验证码的视图函数:verify_code,注意生成的验证码要在session中保存一份
- 设置触发条件,前端来做(如一秒内点击5次,连续点击10次这样)
- 触发后,返回生成验证码图片
- 点击提交后,取出session中保存验证码进行比较,比较通过后,进行后续操作,不通过,提醒继续输入或者过一段时间(1min)后再登录/注册等操作
反向解析
在模板文件中需要使用超链接,或者在重定向中需要重定向到另一个页面时,一般的做法是把相应的url写完整,这样一旦url的正则表达式发生改变(随着应用和逻辑的增多,这种改变是合理的),那就需要也将超链接或者重定向中的url也跟着正则表达式规则改一遍,比较麻烦。
有没有什么方法可以在模板文件的超链接和重定向中可以动态的随着url匹配规则的改变而随着动态改变?
- 有,反向解析
反向解析就是在在主url.py文件的include设置后加一个 namespace属性,在每一个应用的具体的url分配设置行后加一个 names属性,两个属性名都命名的有意义。
- 项目目录下的url.py文件:
url(r'^',include('booktest.urls',namespace='booktest')),
- 分支应用下的url.py文件:
url(r'^fan2$', views.fan2,name='fan2'),
- 项目目录下的url.py文件:
- 这样,在需要使用到这个url的时候,写成以下形式
- 超链接:
<a href="{%url 'booktest:fan2'%}">fan2</a>
- 重定向:
return redirect(reverse('booktest:fan2'))
- 超链接:
在实际解析过程中,就会根据
booktest:fan
动态的反向解析成该url正则该匹配的样子,正则匹配规则更改后,会随着正则的变化而变化,不需要手动更改了。这就叫做反向解析示例
对于超链接:
项目url.py:
url(r'^', include('test1.urls', namespace='test1')),
应用url.py:
url(r'^test_fanxiangjiexi/$', test_fanxiangjiexi),
url(r'^fan12345678/$', fan2, name='fan2'),
应用views.py:
def test_fanxiangjiexi(request):
"""
测试反向解析
:param request:
:return:
"""
return render(request, 'test1/test_fanxiangjiexi.html')
def fan2(request):
"""
超链接测试
:param request:
:return:
"""
return HttpResponse("到家了")
templates/test1/test_fanxiangjiexi.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
下面是一个超链接 <br>
<a href={% url 'test1:fan2' %}>小魔仙</a>
</body>
</html>
对于重定向:
项目url.py和应用url.py设置不变(项目url.py里加上namespace属性,注意写在include括号里,应用url.py里加上name属性),只需要在需要重定向的视图函数返回语句里加上reverse函数(注意导入模块,不是直接可以用的reversed函数)
from django.shortcuts import redirect
from django.core.urlresolvers import reverse
def test_fanxiangjiexi(request):
"""
测试反向解析
:param request:
:return:
"""
return redirect(reverse('test1:fan2'))
- url参数
- 有时候url也需要传递参数到函数中方式有以下两种
- 位置参数:在url正则匹配中使用(),每一个()表示一个参数:
url(r'^fan(\d+)_(\d+)$', views.fan2,name='fan2'),
- 对于反向解析的超链接,要传递参数:
<a href="{%url 'booktest:fan2' 2 3%}">fan2</a>
- 对于重定向,要传递参数:
return redirect(reverse('booktest:fan2', args=(2,3)))
- 对于反向解析的超链接,要传递参数:
- 关键字参数:
url(r'^fan(?P<id>\d+)_(?P<age>\d+)$', views.fan2,name='fan2'),
- 对于反向解析的超链接,要传递参数:
<a href="{%url 'booktest:fan2' id=100 age=18%}">fan2</a>
- 对于重定向,要传递参数:
return redirect(reverse('booktest:fan2', kwargs={'id':100,'age':18}))
- 对于反向解析的超链接,要传递参数:
常用
静态文件处理
静态文件:项目中的CSS文件,图片,JS文件
- 一般会将静态文件放在一个单独的目录里,方便管理
- 静态文件放在根目录下
settings.py静态文件路径的设置
STATIC_URL = '/static'# 为了安全,可以隐藏真实路径,比如也可以写成‘/abc/’ STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static') ]
注:如果配置了隐藏静态文件的的设置,而又不想总是该路径名,可以使用static标签,根据配置项动态生成文件路径
{%load static from staticfiles%} <img src="{%static "img/sg.png" %}"/>
注意:隐藏真实路径的方式,当在结合Nginx部署的时候,因为会将所有的静态文件都交给Nginx处理,而不用转到Django部分,所以这项配置就无效了
中间件
- Django的中间件是一个轻量级,底层的插件系统。可以介入Django的请求响应处理过程,修改Django的输入或者输出。能够增强Django框架的健壮性。
内容,五个方法:
- 1.init,无需任何参数,服务器响应的第一个请求的时候调用一次,用于确定是否启用当前中间件
def __init__(self): pass
- 2.process_request,必须要求有参数request,在request请求对象产生后,url匹配前调用,返回None或者HttpResponse对象
def precess_request(self, request): pass
- 3.process_view,必须要有参数request,view_func,如果有参数,传递参数。在url匹配之后,视图函数调用之前调用,返回None,或者HttpResponse
def process_view(self, request, view_func,*view_args,**view_kwargs): pass
- 4.process_response,必须要有参数request,response,在视图函数调用之后,响应返回浏览器之前使用,在每个请求上调用,返回HttpResponse对象
def process_response(self, request, response): pass
- 5.process_exception,必须要求有参数,request,exception,当视图抛出异常时调用,在每一个请求上调用,返回HttpResponse对象
def process_exception(self, request, exception): pass
中间件是一个独立的python类,可以定义这些方法中的一个或者多个
使用步骤
- 在应用目录下创建middleware.py文件代码如下
class MyMid: def __init__(self): print '--------------init' def process_request(self,request): print '--------------request' def process_view(self,request, view_func, *view_args, **view_kwargs): print '--------------view' def process_response(self,request, response): print '--------------response' return response
- 在setting.py的MIDDLEWARE_CLASSES中注册该类
应用名.middleware.MyMid
- 运行服务器,当发起一个请求的时候,中间件及视图函数运行的顺序为:
- init->request->view->视图函数->response
- 再次访问:request->view->视图函数->response
异常中间件:process_exception需要单独定义类,注册类
class exp1: def process_exception(self,request,exception): print '--------------exp1' class exp2: def process_exception(self,request,exception): print '--------------exp2'
- 会在视图函数中抛出异常时调用:
def index(request): print '======index======' raise Exception('自定义异常') return render(request,'booktest/index.html')
- 如果多个注册的中间件类中都有process_exeption的方法,先注册的后执行
上传图片
进行图片操作,需要安装包PIL
上传图片的方式:
- 在管理页面admin中上传图片
- 自定义form表单上传图片
上传图片后,将图片存储在服务器上,然后将图片的路径存储在表中
步骤
admin上传图片
- 1.创建存储图片地址的模型类
class PicTest(models.Model): pic = models.ImageField(upload_to='test2/')
- 2.生成迁移文件,迁移表
python manage.py makemigatrations python manage.py migrate
3.设置图片保存路径
- 在static目录下新建media文件夹,media文件下新建应用名文件夹
- 配置setting.py文件:
MEDIA_ROOT=os.path.join(BASE_DIR,'static/media')
4.注册模型类到admin中
from django.db import models class PicTest(models.Model): pic = models.ImageField(upload_to='test2/')
5.在admin页面进行上传图片的操作
- 在浏览器中登录到admin操控台进行添加图片即可
- 图片文件会自动上传到指定的static/media/应用文件夹下
- 数据库中会自动存储图片存储的文件路径
form表单上传图片
- 1.获取图片数据
- 2.存储图片数据到文件夹
- 3.给数据库中添加记录
def pic_handle(request): """ 图片处理 :param request: :return: """ # 1.获取传来的图片 pic = request.FILES.get('pic') # 2.把图片存到midia文件夹中 # 1)实例化文件存储对象 fs = FileSystemStorage() # 2)存储图片到指定路径:参1:存储到的路径;参2:要存储的文件 newpic = fs.save('test2/%s'% pic.name, pic) # 3.在数据表中增加一条语句 pictest = PicTest() pictest.pic = newpic pictest.save() return HttpResponse("图片上传OK")
读取图片
- 只需要从数据库中取出图片的地址信息,用img标签读取即可
views.py: from booktest.models import PicTest ... def pic_show(request): pic=PicTest.objects.get(pk=1) context={'pic':pic} return render(request,'booktest/pic_show.html',context) pic_show.html: <html> <head> <title>显示上传的图片</title> </head> <body> <img src="/static/media/{{pic.pic}}"/> </body> </html>
Admin站点
- 内容发布的部分由网站的管理员负责查看,添加,修改,删除数据。开发这些重复的功能是一件单调乏味,缺乏创造力的工作。为此,Django能够根据定义的模型类自动地生成管理模块。
admin使用流程
- 创建管理员用户和密码:
python manager.py createsuperuser
- 在应用里的admin.py里注册模型类
- 在浏览器登录admin管理平台对注册的表(模型类)进行增删改查操作
- 创建管理员用户和密码:
想要模型类按照自己的想法进行展示,可以在注册模型类的基础上再加上管理类
- 管理类:控制模型类在admin页面的展示方式
使用步骤:
- 1.在admin.py中定义管理类
2.使用管理类
- 1)注册参数:
admin.site.register(模型类类名,管理类类名)
- 2)装饰器
注意用装饰起注册 admin.site.register就可以不写了 @admin.register(模型类名) class 管理类名(admin.ModelAdmin): pass
- 1)注册参数:
- 管理类中的设置:
- 每页显示的数据数:
list_per_page=100
- 操作选项的位置:
actions_on_top=True
,actions_on_bottom=False
- 设置显示的表属性(字段):
list_display=[模型字段1,模型字段2,...]
- …
- 每页显示的数据数:
分页
- 对获取到的列表数据进行分页处理
- 主要使用Paginator类和page类进行操作
- paginator类
- __init__(列表,int),返回分页对象,参1:列表数据;参2:每页的数据条数
- 属性
- count:返回对象总数
- num_pages:返回页面总数
- page_range:返回页码列表,从1开始
- 方法
- page(m):返回Page类实例对象,表示第m页的数据
- page类
- 调用Paginator对象的page()方法返回Page对象,不行也要手动构造
- 属性
- object_list:返回当前页对象的列表
- number:返回当前是第几页,从1开始
- paginator:当前页对应的Paginator对象
- 方法
- has_next():如果有下一页,返回true
- has_previous():如果有前一页,返回True
- len():返回当前页面对象的个数