Django(四)
一、请求周期
url> 路由 > 函数或类 > 返回字符串或者模板语言?
1、Form表单提交:
提交 -> url > 函数或类中的方法
- ....
HttpResponse('....')
render(request,'index.html')
redirect('/index/')
用户 < < 返回字符串
(当接收到redirect时)自动发起另外一个请求
--> url .....
2、Ajax提交:
$.ajax({
url: '/index/',
data: {'k': 'v', 'list': [1,2,3,4], 'k3': JSON.stringfy({'k1': 'v'}))},
data的另一种获取数据的方式 $(form对象).serilize()
如果多个值发到后台如上面的list是一个列表,需要加如下参数 traditional才能发送到后台
type: 'POST',
dataType: 'JSON',
traditional: true,
success:function(d){
location.reload() # 刷新
location.href = "某个地址" # 跳转
}
})
提交 -> url -> 函数或类中的方法
用HttpResponse可以返回序列化的字典(可定制更高)
HttpResponse('{}')
使用render的返回本质也是字符串,只是返回的是模板渲染后,特殊的字符串
render(request, 'index.html', {'name': 'v1'})
<h1>{{ name }}</h1> -->
最终返回给用户的是<h1>v1</h1>
唯独不可以使用 redirect...
只能自己做跳转
location.reload() # 刷新
location.href = "某个地址" # 跳转
用户 <<<<< 本质上也是返回字符串
二、路由系统URL
a. /index/ -> 函数或类
b. /index/(\d+) -> 函数或类
c. /index/(?P<nid>\d+) -> 函数或类
d. /index/(?P<nid>\d+) name='root' -> 函数或类
reverse()
{% url 'root' 1%}
e. /crm/ include('app01.urls') -> 路由分发
f. 默认值
url(r'^index/', views.index, {'name': 'root'}),
def index(request,name):
print(name)
return HttpResponse('OK')
g. 命名空间
/admin/ include('app01.urls',namespace='m1')
/crm/ include('app01.urls',namespace='m1')
app01.urls
/index/ name = 'n1'
reverser('m1:n1')
三、试图views的获取请求方式
def func(request):
request.POST
request.GET
request.FILES
request.getlist
request.method
request.path_info
return render,HttpResponse,redirect等方式
- 请求的其他信息
from django.core.handlers.wsgi import WSGIRequest
request.environ#封装了所有请求相关的信息,取得话,可以根据字典来取
request.environ['HTTP_USER_AGENT'] #根据某个key,去获取请求相应的信息
装饰器
FBV:
def auth(func):
def inner(reqeust,*args,**kwargs):
v = reqeust.COOKIES.get('username111')
if not v:
return redirect('/login/')
return func(reqeust, *args,**kwargs)
return inner
CBV:
fom django import views
from django.utils.decorators import method_decorator
@method_decorator(auth,name='dispatch')
class Order(views.View):
# @method_decorator(auth)
# def dispatch(self, request, *args, **kwargs):
# return super(Order,self).dispatch(request, *args, **kwargs)
# @method_decorator(auth)
def get(self,reqeust):
v = reqeust.COOKIES.get('username111')
return render(reqeust,'index.html',{'current_user': v})
def post(self,reqeust):
v = reqeust.COOKIES.get('username111')
return render(reqeust,'index.html',{'current_user': v})
四、模板引擎(Templates)
render(request, 'index.html',' ')#index.html是模板路径
# for
# if
# 索引. keys values items all
- 母版...html
extends 继承的母版,子板只能继承一个母版
include
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> {# 对应tpl1.html的title#} <title>{% block title %}{% endblock %}</title> <link rel="stylesheet" href="/static/commons.css" /> <style> .pg_header{ height: 50px; background-color: aqua; color: rebeccapurple; } </style> {# 对应tpl1.html的css#} {% block css %}{% endblock %} </head> <body> <div class="pg_header"> {# 对应tpl1.html的content#} {% block content %}{% endblock %} </div> <script src="/static/jquery.js"></script> {# 对应tpl1.html的js#} {% block js %}{% endblock %} </body> </html> master.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> {# 对应tpl1.html的title#} <title>{% block title %}{% endblock %}</title> <link rel="stylesheet" href="/static/commons.css" /> <style> .pg_header{ height: 50px; background-color: aqua; color: rebeccapurple; } </style> {# 对应tpl1.html的css#} {% block css %}{% endblock %} </head> <body> <div class="pg_header"> {# 对应tpl1.html的content#} {% block content %}{% endblock %} </div> <script src="/static/jquery.js"></script> {# 对应tpl1.html的js#} {% block js %}{% endblock %} </body> </html> master.html
{#被include继承#} <div> <input type="text" /> <input type="submit" value="提交" /> </div>
如果传的格式是datetime类型,可以转换成时间日期格式
{{ item.event_start|date:"Y-m-d H:i:s" }}
截取后台传过来的字符串的前30个字符
{{ bio|truncatewords:"30" }}
拿到第一个字符,转换为大写
{{ my_list|first|upper }}
字符转换为小写
{{ name|lower }}
- 自定义函数
自定义simple_tag
a. 相应的app下创建templatetags目录
b. 在templatetags目录下,创建任意py文件(如xxoo.py)
c. 创建template对象 register(这个对象名不能改,必须为register)
d. 装饰函数
@register.simple_tag
def func(a1,a2,a3....) #可以传参数a1,a2,a3
return "asdfasd"
e. settings中注册APP
f. 顶部 {% load xxoo %}
g. {% 函数名 arg1 arg2 %}
缺点:
不能作为if条件
优点:
参数任意
自定义filter
a. app下创建templatetags目录
b. 任意xxoo.py文件
c. 创建template对象 register
d.
@register.filter
def func(a1,a2)
return "asdfasd"
e. settings中注册APP
f. 顶部 {% load xxoo %}
g. {{ 参数1|函数名:"参数二,参数三" }} {{ 参数1|函数名:数字 }}
缺点:
最多两个参数,不能加空格
优点:
能作为if条件
{% load xxoo %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> {{ name }} </div> <div> {{ name | lower }} </div> <div> {# register.simpletag装饰器#} {% func1 2 5 7 %} </div> <div> {# register.filter装饰器#} {{ 'xiaozemaliya'|func2:28 }} </div> </body> </html> simple_tag-filter
from django import template
from django.utils.safestring import mark_safe
# 创建register(register名字不能改)对象,
register = template.Library()
# simple_tag装饰器
@register.simple_tag
def func1(a1,a2,a3):
return a1 + a2
# filter装饰器
@register.filter
def func2(a1,a2):
print(a1,type(a2))
return a1 + str(a2)
xxoo任意函数
五、数据库操作
class User(models.Model):
username = models.CharField(max_length=32) #字符长度
email = models.EmailField()
有验证功能
Django Admin
无验证功能:
可以创建成功
User.objects.create(username='root',email='asdfasdfasdfasdf')
User.objects.filter(id=1).update(email='666')
#一对多
class UserType(models.Model):
name = models.CharField(max_length=32)
class User(models.Model):
username = models.CharField(max_length=32)
email = models.EmailField()
user_type = models.ForeignKey("UserType")
#获取对象列表,对象的获取跨表值用"."点
user_list = User.objects.all()
for obj user_list:
obj.username,obj.email,obj.user_type_id,obj.user_type.name,obj.user_type.id
#获取单个对象
user = User.objects.get(id=1)
user.
#跨表,字符串的获取跨表值,用“__”双下滑杠
user.objects.all().values("username","user_type__name",)
#多对多
class UserType(models.Model):
name = models.CharField(max_length=32)
class User(models.Model):
username = models.CharField(max_length=32)
email = models.EmailField()
user_type = models.ForeignKey("UserType")
#自动生成第三张表
m = models.ManyToMany('UserGroup')
class UserGroup(models.Model):
name = ....
#获取一个对象(user表中id=1的对象)
obj = User.objects.get(id=1)
obj.m.add(2)
obj.m.add(2,3)
obj.m.add(*[1,2,3])#注这里的列表前面加*
obj.m.remove(...)
obj.m.clear()
obj.m.set([1,2,3,4,5])#注这里的列表前面不加*
# 多个组,UserGroup对象
obj.m.all() #获取的是m(及usergroup)中的多个对象
obj.m.filter(name='CTO') #获取的是name='CTO'的对象
六、分页
防止XSS攻击:
{{ page_str|safe }}#前端添加
mark_safe(page_str)#或者后台添加
封装:
from django.utils.safestring import mark_safe class Page: ''' current_page当前页 data_count总数据 per_page_count每页显示数据个数 pager_num每页显示页码数 @property 装饰一个方法变成属性来调用 ''' def __init__(self,current_page,data_count,per_page_count=10,pager_num=7): self.current_page = current_page self.data_count = data_count self.per_page_count = per_page_count self.pager_num = pager_num #当前页显示的起始页 @property def start(self): return (self.current_page-1) * self.per_page_count #当前页面显示的末页 @property def end(self): return self.current_page * self.per_page_count #总页数 @property def total_count(self): #divmod取商和余数v为商,y为余数 v,y = divmod(self.data_count, self.per_page_count) #当余数不为0时,总页数加一 if y: v += 1 return v #base_url就是url路由 def page_str(self, base_url): page_list = [] #当总页数小于,每页显示的页数时 if self.total_count < self.pager_num: start_index = 1 end_index = self.total_count + 1 #当总页数大于,每页显示的页数时 else: if self.current_page <= (self.pager_num+1)/2: start_index = 1 end_index = self.pager_num + 1 else: start_index = self.current_page - (self.pager_num-1)/2 end_index = self.current_page + (self.pager_num+1)/2 if (self.current_page + (self.pager_num-1)/2) > self.total_count: end_index = self.total_count + 1 start_index = self.total_count - self.pager_num + 1 #上一页,如果当前页数为1时,点击上一页href="javascript:void(0);"代表不做任何操作 if self.current_page == 1: prev = '<a class="page" href="javascript:void(0);">上一页</a>' else: prev = '<a class="page" href="%s?p=%s">上一页</a>' %(base_url,self.current_page-1,) page_list.append(prev) for i in range(int(start_index),int(end_index)): if i ==self.current_page: temp = '<a class="page active" href="%s?p=%s">%s</a>' %(base_url,i,i) else: temp = '<a class="page" href="%s?p=%s">%s</a>' %(base_url,i,i) page_list.append(temp) #下一页,如果下一页等于总页数时,点击下一页href="javascript:void(0);"代表不做任何操作 if self.current_page == self.total_count: nex = '<a class="page" href="javascript:void(0);">下一页</a>' else: nex = '<a class="page" href="%s?p=%s">下一页</a>' %(base_url,self.current_page+1,) page_list.append(nex) #跳转 val是获取当前输入的页码值,然后location.href跳转到后面的base+val字符串拼接 jump = """ <input type='text' /><a onclick='jumpTo(this, "%s?p=");'>GO</a> <script> function jumpTo(ths,base){ var val = ths.previousSibling.value; location.href = base + val; } </script> """ %(base_url,) page_list.append(jump) #以下加mark_safe,是为了确保后台定义字符串包含特殊的html字符,前端可以做解析 page_str = mark_safe("".join(page_list)) return page_str
七、cookie和session
二者的定义:
当你在浏览网站的时候,WEB 服务器会先送一小小资料放在你的计算机上,Cookie 会帮你在网站上所打的文字或是一些选择,都纪录下来。当下次你再光临同一个网站,WEB 服务器会先看看有没有它上次留下的 Cookie 资料,有的话,就会依据 Cookie里的内容来判断使用者,送出特定的网页内容给你。 Cookie 的使用很普遍,许多有提供个人化服务的网站,都是利用 Cookie来辨认使用者,以方便送出使用者量身定做的内容,像是 Web 接口的免费 email 网站,都要用到 Cookie。
具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上它还有其他选择。
cookie机制。正统的cookie分发是通过扩展HTTP协议来实现的,服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的cookie。然而纯粹的客户端脚本如JavaScript或者VBScript也可以生成cookie。而cookie的使用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的cookie,如果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置,则把该cookie附在请求资源的HTTP请求头上发送给服务器。
cookie的内容主要包括:名字,值,过期时间,路径和域。路径与域一起构成cookie的作用范围。若不设置过期时间,则表示这个cookie的生命期为浏览器会话期间,关闭浏览器窗口,cookie就消失。这种生命期为浏览器会话期的cookie被称为会话cookie。会话cookie一般不存储在硬盘上而是保存在内存里,当然这种行为并不是规范规定的。若设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie仍然有效直到超过设定的过期时间。存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存里的cookie,不同的浏览器有不同的处理方式session机制。session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否已包含了一个session标识(称为session id),如果已包含则说明以前已经为此客户端创建过session,服务器就按照session id把这个session检索出来使用(检索不到,会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个session id将被在本次响应中返回给客户端保存。保存这个session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发送给服务器。一般这个cookie的名字都是类似于SEEESIONID。但cookie可以被人为的禁止,则必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。
经常被使用的一种技术叫做URL重写,就是把session id直接附加在URL路径的后面。还有一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。比如:
<form name="testform" action="/xxx">
<input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">
<input type="text">
</form>
实际上这种技术可以简单的用对action应用URL重写来代替。
cookie 和session 的区别:
1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗
考虑到安全应当使用session。
3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
考虑到减轻服务器性能方面,应当使用COOKIE。
4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
5、所以个人建议:
将登陆信息等重要信息存放为SESSION
其他信息如果需要保留,可以放在COOKIE中