Django
django-admin startproject wjtest(项目名) 在命令行里创建django项目
wjtest
- wjtest #对整个程序进行配置
- init
- settings #配置文件
- url #URL对应关系
- wsgi #遵循WSGI规范,程序正式上线用uwsgi+nginx
- manage.py #管理Django程序
- python manage.py
- python manage.py startapp xx
- python manage.py makemigrations
- python manage.py migrate
运行
python manage.py runserver ip+端口
抽屜
- 抽屜
- 配置
- 主站app
- 后台管理app
创建app
使用app时要在app_info里添加app名称,并且以逗号结尾
python manage.py startapp 主站名
python manage.py startapp 后台管理名
app目录:
migrations 数据修改表结构
admin Django提供的后台管理
apps 配置当前app
models ORM,写制定的类,通过命令创建数据库结构
tests 单元测试
views 业务逻辑代码
1. 配置模板的路径
TEMPLATES = [
{
\'BACKEND\': \'django.template.backends.django.DjangoTemplates\',
\'DIRS\': [os.path.join(BASEDIR,\'templates\')],
\'APPDIRS\': True,
\'OPTIONS\': {
\'contextprocessors\': [
\'django.template.contextprocessors.debug\',
\'django.template.contextprocessors.request\',
\'django.contrib.auth.contextprocessors.auth\',
\'django.contrib.messages.contextprocessors.messages\',
],
},
},
]
2. 配置静态路径,配置之后就可以直接访问到,静态文件就能生效
STATICFILESDIRS=(
os.path.join(BASE_DIR,\'static\'),#必须有逗号隔开
)
在setting中,middelrware里注释 csrf保证数据可以提交
def func(request): # request.method GET/POST # http://127.0.0.1:8000/home?nid=123&name=wj #request.GET.get(\'\',None) #获取请求发来的数据
#request.POST.get(\'\',None)
return HttpResponse(\'字符串\')
return render(request,\'html模板的路径\')
return redirect(\'/只能填URL路径\')重定向
return redirect(\'/login\') 斜杠要有
模板渲染
-
特殊的模板语言 --{{变量名}}-- def func(request): return render(request,"index.html",{\'currentuser\':\'wj\'})
{{currentuser}} -
--for循环-- def func(request): return render(request,"index.html",{\'currentuser\':\'wj\',\'userlist\':[\'alex\',\'eric\']},\'userdict\':{\'k1\':\'v1\',\'k2\':\'v2\'})
{{currentuser}}-
{% for li in userlist%}
- li {%endfor%} {{userlist.1}} {{userlist.0}} {{userdict.k1}} {{user_dict.k2}}
</body>
-
条件
def func(request): return render(request,"index.html",{\'currentuser\':\'wj\',\'userlist\':[\'alex\',\'eric\']},\'userdict\':{\'k1\':\'v1\',\'k2\':\'v2\'}){{currentuser}}{{userlist.1}} {{userlist.0}} {{userdict.k1}} {{userdict.k2}} {% if age %} 有年龄 {% if age > 8 %}一定加空格隔开 <a>老男人</a> {% else %} 小鮮肉 {% endif %} {% else %} 无年龄 {% endif %}</body>
Django请求声明周期
-> URL对应关系(匹配)-> 视图函数 -> 返回用户字符串
-> URL对应关系(匹配) -> 视图函数 -> 打开一个HTML文件,读取内容
路由系统,URL
1. url(r\'^index/\',views.index),url(r\'^home/\',views.Home.as_view())
2. url(r\'^detail-(\\d+).html\',views.detail),
3. url(r\'^detail-(?P<nid>\\d+)-(?P<uid>\\d+).html\',views.detail)接收的时候用*args **kwargs,带指定名的参数使用kwargs,没有指定参数名使用args
视图
request.body是所有方法的上层方法
1. GET方法获取数据 v=request.GET.get(\'sex\')
2. POST方法获取数据 v=request.POST.get(\'sex\')
3. 取文件 obj=request.FILES.get(\'fafafa\')# 取到文件对象
提交的时候需要在html代码里要加,enctype="multipart/form-data"才能上传文件
obj=request.FILES.get(\'fafafa\')# 取到文件对象
print(type(obj))
print(obj.name)#文件名称
import os
filepath=os.path.join(\'upload\',obj.name)
f=open(filepath,\'wb\')
for i in obj.chunks(): #生成器
f.write(i)
f.close()
文件对象=request.FILES.get()
文件对象.name
文件对象.size
文件对象.chunks()
4. 两种对应关系
FBV
function base view
url.py index->函数名
view.py 存函数
CBV class base view
from django.views import View
class Home(View):
def dispatch(self, request, *args, **kwargs):
#调用父类里的dispath
result=super(Home,self).dispatch(request, *args, **kwargs)
return result
#发来get请求执行get方法
def get(self,request):
print(request.method)
return render(request,\'home.html\')
#发来post请求执行post方法
def post(self,request):
print(request.method)
return render(request,\'home.html\')
url(r\'^home/\', views.Home.as_view()),
getlist用于checkbox多选时
- 装饰器
-
django模板语言循环字体
-
{% for row in user_list.values %}
- {{ row }} {% endfor %}
传值
-
{% for k,rwo in userdict.items %}
- {{ rwo.name }} {% endfor %}
def index(request): USERLIST={ \'k1\':\'root1\', \'k2\':\'root2\', \'k3\':\'root3\', \'k4\':\'root4\', } return render(request,\'index.html\',{\'userlist\':USER_LIST})
正则表达式分组 url(r\'^detail-(?P\\d+)-(?P \\d+).html\', views.detail),#调用的时候就不分顺序了
def detail(request,nid,uid): return render(request,\'detail.html\',{\'detailinfo\':USERLIST[nid]})
<!DOCTYPE html>详细信息
{{ detailinfo.name }}
{{ detailinfo.email }}
def func(request,args): args=(2,9)
def func(request,args,kwargs): args=(1,9)url(r\'^detail-(?P
\\d+)-(?P \\d+).html\', views.detail),#调用的时候就部分顺序了
def func(request,**kwargs): kwargs={\'nid\':1,\'uid\':3}
路由 name是对URL路由关系进行命名,以后根据此名称生成自己想要的URLurl(r\'^indexx/\', views.index,name=\'i1\'),
url(r\'^home/(\\d+)/\',views.index,name=\'i2\'), url(r\'^login/(?P\\d+)/(?P \\d+)/\',view.index,name=\'i3\'), def func(request,args,*kwargs): from django.urls import reverse url1=reverse(\'i1\') #indexx/ url2=reverse(\'i2\',args(1,2,)) #home/1/2 url3=reverse(\'i3\',kwargs={\'pid\':1,\'nid\':9}) #login/1/9 xxx.html {% url \'i1\' %} {% url \'i2\' 1 2 %} {% url \'i3\' pid=1 nid=9 %} 模板语言
{% url \'index\' %} action="{% url \'index\' 3 %}"
注: #当前URL
request.path_info 模板语言里的使用
from django.urls import reverse
v=reverse(\'indexx\',args=(90,80,)
v=reverse(\'indexx\',kwargs={\'nid\':1,\'uid\':99}) action="{% url \'index\' nid=3 uid=3 %}"
print(v)
路由分发 匹配app名字 from django.conf.urls import url,include
urlpatterns=[ url(r\'^cmdb/\',include(\'app01,urls\')),#app01新建urls文件
url(r\'^monitor/\',include(\'app02,urls\')), ]
模板
ORM操作
创建类
dbfirst先写数据库在写程序 codefirst直接通过程序代码生成数据库
a. 写类
from django.db import models
# Create your models here.
#app01userinfo
class UserInfo(models.Model):
#id列,自增,主键
#用户名列,字符串类型,指定长度
username=models.CharField(maxlength=32)
password=models.CharField(maxlength=64)
b. 注册
settings:
installapps里添加app名字
c. 执行
python manage.py makemigrations
python manage.py migrate
d.注意
Django默认使用mysqldb模块链接MySQL
主动修改为pymysql,在project同名文件夹下init文件中添加如下代码
import pymysql
pymysql.installasMySQLdb()
1. 根据类自动创建数据库表
app下的models.py
2. 根据类对数据库表中的数进行各种操作
添加数据数据的三种方式
1.
# models.UserInfo.objects.create(
# username=\'root\',
# password=\'123\',
# )
2.
# obj=models.UserInfo(
# username=\'wj\',
# password=\'321\'
# )
# obj.save()
3.
dic={
\'username\':\'eric\',
\'password\':\'666\'
}
models.UserInfo.objects.create(**dic)
查
#查 返回的result的是个对象列表queryset
# result=models.UserInfo.objects.all()
# for row in result:
# print(row.id,row.username,row.password)
# result=models.UserInfo.objects.filter(username=\'root\')#根据条件查询 返回的也是列表
# result=models.UserInfo.objects.filter(username=\'root\',passwrod=\'123\')#根据条件查询 返回的也是列表
# print(result)
result=models.UserInfo.objects.filter(username=\'root\').first取出第一个对象
#删除
# models.UserInfo.objects.filter(id=3).delete()
#更新
# models.UserInfo.objects.all().update(password=\'5678\')
models.UserInfo.objects.filter(id=1).update(password=\'78\')
修改表结构
- 第一种添加字段的方式在models里添加一个字段,email=models.CharField(max_length=60),执行python manage.py makemigrations,会出现一个选项,选择第一个,输入字段的默认值,再执行python manage.py migrate就可以添加一个新的字段
- 第二种添加字段的方式gender=models.CharField(max_length=60,null=True),直接添加一个null参数默认它为True,这样执行python manage.py makemigrations,python manage.py migrate新增加的gender字段就都默认为空字段。
-
删除字段就直接再models里注释调字段。再执行就可一删去字段
创建超级用户
python manage.py createsuperuser
字段:
字符串类型
数字
时间
二进制
自增(必须加primarykey=True)
字段的参数
null 数据库中字段是否可以为空 dbcolumn 数据库中字段的列名 dbtablespace default 数据库中字段的默认值 primarykey 数据库中字段是否为主键 dbindex 数据库中字段是否可以建立索引 unique 数据库中字段是否可以建立唯一索引 uniquefordate 数据库中字段【日期】部分是否可以建立唯一索引 uniqueformonth 数据库中字段【月】部分是否可以建立唯一索引 uniqueforyear 数据库中字段【年】部分是否可以建立唯一索引 autonow ->创建时,自动生成时间
autonowadd -> 更新时,自动更新为当前时间
#obj=UserGroup.objects.filter(id=1).update(caption="CEO")
#obj=UserGroup.objects.filter(id=1).first() #obj.caption="CEO"
#obj.save()verbosename Admin中显示的字段名称,verbosename=用户名 blank Admin中是否允许用户输入为空 editable Admin中是否可以编辑 help_text Admin中该字段的提示信息 choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作,django admin中显示下拉框,避免链表查询 如:gf = models.IntegerField(choices=[(0, \'何穗\'),(1, \'大表姐\'),],default=1)
errormessages 自定义错误信息(字典类型),从而定制想要显示的错误信息; 字典健:null, blank, invalid, invalidchoice, unique, and uniquefordate 如:{\'null\': "不能为空.", \'invalid\': \'格式错误\'}
validators 自定义错误验证(列表类型),从而定制想要的验证规则 from django.core.validators import RegexValidator from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\\ MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator 如: test = models.CharField( maxlength=32, errormessages={ \'c1\': \'优先错信息1\', \'c2\': \'优先错信息2\', \'c3\': \'优先错信息3\', }, validators=[ RegexValidator(regex=\'root\\d+\', message=\'错误了\', code=\'c1\'), RegexValidator(regex=\'root112233\\d+\', message=\'又错误了\', code=\'c2\'), EmailValidator(message=\'又错误了\', code=\'c3\'), ] )
外键
usergroup=models.ForeignKey(\'UserGroup\',tofield=\'uid\')#tofield表示关联字段,必须是唯一的
usergroup=models.ForeignKey(\'UserGroup\',tofield=\'uid\',default=1)默认为UserGroup uid为1的对象
两种创建带外键的模型数据,第二种方式好,只操作一次数据库 models.UserInfo.objects.create( username=\'root1\', password=\'123\', email=\'sfdfa\', usergroup=models.UserGroup.objects.filter(id=1).first()) models.UserInfo.objects.create( username=\'root1\', password=\'123\', email=\'sfdfa\', usergroupid=1) 获取表单数据的三种方式 - 对象 v1=models.Business.objects.all() QuerySet [obj(id,caption,code),obj(id,caption,code)...]
-
字典
v2=models.Business.objects.all().values(\'id\',\'caption\') QuerySet [{\'id\':1,\'caption\':\'运维部\'},{\'id\':1,\'caption\':\'开发部\'}...] -
元组 v3=models.Business.objects.all().valueslist(\'id\',\'caption\') QuerySet [(1,运维部),(2,开发部)...] v1=models.Host.objexts.filter(nidgt=0)\'gt\'表示大于 v2=models.Host.objexts.filter(nidgt=0).values(\'nid\',\'hostname\',\'bid\',\'bcaption\')其中bcaption是跨表查询,所有的跨表查数据都用双下划线
模板语言forlop.counter循环几次就表示几
forlop.parentloop当有嵌套循环时,表示上层序号信息 初识ajax
$.ajax({ url:"/monitor/test_ajax/", type:"POST", data:{\'hostname\':$(\'#hn\').val(),\'ip\':$(\'#ip\').val(),\'port\':$(\'#port\').val(),\'caption\':$(\'#cp\').val()}, success:function(data){ if(data=="OK"){ location.reload() }else{ alert(data) } } })$.ajax({ url:"/monitor/testajax/", type:"POST", data:{\'hostname\':$(\'#hn\').val(),\'ip\':$(\'#ip\').val(),\'port\':$(\'#port\').val(),\'caption\':$(\'#cp\').val()}, success:function(data){ //data返回的是字符串 var obj = JSON.parse(data) if(obj.status){ location.reload() }else{ $(\'#errortext\').text(obj.error) } } }) 服务器端永远返回一个字典
return HttpResponse(json.dumps(字典)) models创建多对多 方式一:自定义关系表 class Host(models.Model): nid=models.AutoField(primarykey=True) hostname=models.CharField(maxlength=32,dbindex=True) ip=models.GenericIPAddressField(dbindex=True) port=models.IntegerField() b=models.ForeignKey(to=\'Business\',tofield=\'id\') class Application(models.Model): name=models.CharField(max_length=32)class HostToApp(models.Model): hobj=models.ForeignKey(to=\'Host\',tofield=\'nid\') aobj=models.ForeignKey(to=\'Application\',tofield=\'id\')
方式二:自动创建关系表,无法对第三张表直接操作,可以间接操作
class Host(models.Model): nid=models.AutoField(primarykey=True) hostname=models.CharField(maxlength=32,dbindex=True) ip=models.GenericIPAddressField(dbindex=True) port=models.IntegerField() b=models.ForeignKey(to=\'Business\',tofield=\'id\') class Application(models.Model): name=models.CharField(maxlength=32) h=models.ManyToManyField(\'Host\') 间接操作
obj=Application.objexts.get(id=1)
obj.name obj.h.add(1) obj.h.add(2) obj.h.add(*[1,2,3,5])列表形式添加 obj.h.remove(1) obj.h.remove([1,2,5])列表形式移除 obj.h.clear()删除 obj.h.set([3,4,5])改不用加
obj.h.all() 拿到host的queryset对象列表 ajax传递多选,traditional为true,ajax方式不能跳转,只能收到返回的字符串,如果想跳转只能,location.reload,location.href="地址" $.ajax({ url: \'/index/\', data: {\'k\': \'v\', \'list\': [1,2,3,4], \'k3\': JSON.stringfy({\'k1\': \'v\'}))}, $(form对象).serilize() type: \'POST\', dataType: \'JSON\': traditional: true, success:function(d){ location.reload() # 刷新 location.href = "某个地址" # 跳转 } }) 知识点: URLViews 请求的其他信息 装饰器 Models 在views.py中对应请求的方法里的形参request,对应的类为WSGIRequest,WSGIRequest位置为如下位置,查看其中的方法
from django.core.handlers.wsgi import WSGIRequest
request.environ输出所有信息 for k,v in request.environ.items(): print(k,v) request.environ["HTTPUSERAGENT"] 模板中也有自己的语言,该语言可以实现数据展示 继承下面是模板
<!DOCTYPE html>
{% block content %} {% endblock %} {% block js %}{% endblock %}
继承上面的代码
{% extends \'master.html\' %}
{% block title %}
小男孩管理
{% endblock %}
{% block content %}
<h1>用户管理</h1>
<ul>
{% for i in u %}
<li>{{ i }}</li>
{% endfor %}
</ul>
{% endblock %}
{% block css %}
<style>
body{
background-color: red;
}
</style>
{% endblock %}
{{ item }}
{% for item in itemlist %} {{ item }} {% endfor %}
forloop.counter
forloop.first
forloop.last
{% if orderedwarranty %} {% else %} {% endif %}
母板:{% block title %}{% endblock %}
子板:{% extends "base.html" %}
{% block title %}{% endblock %}
帮助方法:
{{ item.eventstart|date:"Y-m-d H:i:s"}}
{{ bio|truncatewords:"30" }}
{{ mylist|first|upper }}
{{ name|lower }}
自定义simpletag
自定义simpletag:
第一步:在某个app下创建一个templatetags目录(必须要的)
第二部:创建任意py文件
第三步:创建template对象 register
第四步:创建函数用@register.simpletag装饰
@register.simpletag
def func(a1,a2)
return "abcd"
第五步:settings中注册app
第六步:顶部 {% load py文件 %}
缺点:
不能作为if条件
优点:
参数任意
from django import template
from django.utils.safestring import mark_safe
register = template.Library()
@register.simple_tag
def my_simple_time(v1,v2,v3):
return v1 + v2 + v3
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条件 {% if "maliya"|wjj:"hello" %} {% endif %}
分页(自定义的分页)
XSS攻击是拿走你的cookie进行操作
XSS安全的两种方式:
在html里处理
{{ pagestr|safe }}
在后台处理
from django.utils.safestring import marksafe
pagestr=marksafe(pagestr)
Cookie操作:
设置10秒后失效两种方法
1. res.setcookie(\'username\',username,maxage=10)
2. import datetime
currentdate=datetime.datetime.utcnow()
current_date=currentdate+datetime.timedelta(seconds=10)
res.setcookie(\'username\',username,expires=currentdate)
1、获取Cookie:
request.COOKIES[\'key\']
request.getsignedcookie(key, default=RAISEERROR, salt=\'\', maxage=None)
参数:
default: 默认值
salt: 加密盐
maxage: 后台控制过期时间
2、设置Cookie:
rep = HttpResponse(...) 或 rep = render(request, ...)
rep.setcookie(key,value,...) rep.setsigned_cookie(key,value,salt=\'加密盐\',...) 参数: key, 键 value=\'\', 值 maxage=None, 超时时间 expires=None, 超时时间(IE requires expires, so set it if hasn\'t been already.)datetime类型 path=\'/\', Cookie生效的路径,/ 表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问,其余的都用不了 domain=None, Cookie生效的域名 secure=False, https传输 httponly=False 只能http协议传输,无法被javascript获取(不是绝对,底层抓包可以获取到也可以被覆盖) 由于cookie保存在客户端的电脑上,所以,JavaScript和jquery也可以操作cookie。
<script src=\'/static/js/jquery.cookie.js\'> $.cookie("listpagernum", 30,{ path: \'/\' }); cookie加密,salt对应字符串为加盐。解密时也必须相同 obj.setsignedcookie(\'username\',\'kangbazi\',salt=\'fajlfkd\') request.getsignedcookie(\'username\',salt="fajlfkd")
model操作(原生SQL)
表内容操作:
obj=models.TB(..)
obj.save()
models.TB.objects.all()[7:10]
models.TB.objecte.create()<br/> models.TB.objects.create(**{})<br/> models.TB.objects.all()<br/> models.TB.objects.undate(..)<br/> models.TB.objects.filter(..)<br/> models.TB.objects.filter(id__in=[1,2,3])<br/> models.TB.objects.filter(单下划线id)<br/> models.TB.objects.delete()<br/> models.TB.objects.values()<br/> models.TB.objects.get()<br/> models.TB.objects.value_list()<br/> models.TB.objects.filter().undate()<br/> models.TB.objects.filter().first()<br/> models.TB.objects.filter(**{})<br/> models.TB.objects.filter(**{}).count()<br/> models.TB.objects.filter(双下划线跨表)<br/> models.TB.objects.filter(id__gt=1)双下划线gt表示大于<br/> models.TB.objects.filter(id__range=[1,2])<br/> models.TB.objects.filter(id__lt=1)小于<br/> models.TB.objects.filter(id__lte=1)小于等于 <br/> models.TB.objects.filter(id__gte=1)大于等于<br/> models.TB.objects.exclude(id__gte=1)不等于<br/>
多对多
obj.set
obj.add(1,2,3)
obj.add([1,2,3])
obj.remove([1,2,3])
obj.clear()
obj.all()..
models.TB.objects.all()
[obj,obj]
obj.fk.name
models.TB.objects.all().order_by(\'\')
models.TB.objects.distinct()
模板语言
session
-
Session 基于cookie做用户验证时:敏感信息不适合放在cookie中 a. Session原理 Cookie是保存在用户浏览器端的键值对 Session是保存在服务器端的键值对 # 获取、设置、删除Session中数据 request.session[\'k1\'] request.session.get(\'k1\',None) request.session[\'k1\'] = 123 request.session.setdefault(\'k1\',123) # 存在则不设置 del request.session[\'k1\']#删除某个键值对
# 所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()
用户session的随机字符串
request.session.session_key
将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired()
检查 用户session的随机字符串 在数据库中是否
request.session.exists("session_key")
删除当前用户的所有Session数据
request.session.delete("session_key")
注销使用
request.session.clear()
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
a. 关于session里的配置 settings.py
将数据放在缓存里,不放在数据库里 SESSIONENGINE = \'django.contrib.sessions.backends.cache\' # 引擎 SESSIONCACHE_ALIAS = \'default\' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
SESSIONCOOKIENAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串 SESSIONCOOKIEPATH = "/" # Session的cookie保存的路径 SESSIONCOOKIEDOMAIN = None # Session的cookie保存的域名 SESSIONCOOKIESECURE = False # 是否Https传输cookie SESSIONCOOKIEHTTPONLY = True # 是否Session的cookie只支持http传输 SESSIONCOOKIEAGE = 1209600 # Session的cookie失效日期(2周) SESSIONEXPIREATBROWSERCLOSE = False # 是否关闭浏览器使得Session过期 SESSIONSAVEEVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存,每次操作后,不是第一次操作开始算 session依赖cookie
CSRF
CSRF验证会验证数据提交,
{% csrftoken %}可以看到每次与服务器沟通时发出的csrf,使用表单提交要在表单写{% csrftoken %},
ajax提交数据时,两种方式
1. 写在这个script里的所有ajax都可以执行
$.ajaxSetup(
{
beforeSend:function(xhr,settings){
xhr.setRequestHeader(\'X-CSRFtoken\',$.cookie(\'csrftoken\'));
}
}
);
-
单独写在ajax请求里
$(\'#btn1\').click(function(){ $.ajax({ url:\'/login/\', type:\'POST\', data:{\'user\':\'root\',\'pwd\':\'123\'}, headers:{\'X-CSRFtoken\':$.cookie(\'csrftoken\')}, success:function(arg){}
}) })
当访问方法为GET时是不需要加token的,所以第二种方法的使用时可以做如下设置
function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } }); 当在django框架中,setting里注释掉middle里的csrf验证,但有些方法需要使用csrf验证时,可以使用装饰器,
from django.views.decorators.csrf import csrfexempt,csrfprotect
在需要用的方法上使用装饰器
@csrf_protect
def index(request): return render(request,\'index.html\')
中间件
from django.utils.deprecation import MiddlewareMixin
在setting文件中,MIDDLEWARE=[
]列表中设置MIDDLEWARE[\'Middle.m1,Row1\',\'Middle.m1,Row2\',\'Middle.m1,Row3\',]
执行顺序,processrequest,processview,url-view,processresponse,如果请求里有数据,会放到processview里的viewfuncargs或者viewfunckwargs
from django.utils.deprecation import MiddlewareMixin
class Row1(MiddlewareMixin): def process_request(self,request): print(\'zhangsan\')
def process_view(self, request, view_func, view_func_args, view_func_kwargs):
print(\'lisi\')
def process_response(self, request, response):
print(\'扛把子\')
return response
from django.shortcuts import HttpResponse
class Row2(MiddlewareMixin):
def process_request(self,request):
print(\'wangxiaoer\')
# return HttpResponse(\'走\')
def process_view(self, request, view_func, view_func_args, view_func_kwargs):
print(\'张需要\')
def process_response(self, request, response):
print(\'张三\')
return response
class Row3(MiddlewareMixin):
def process_request(self,request):
print(\'李四\')
def process_view(self, request, view_func, view_func_args, view_func_kwargs):
print(\'王二麻\')
def process_response(self, request, response):
print(\'小淘气\')
return responseviews函数有错误时执行,处理exception时也是一层一层往上找
def process_exception(self, request, exception):
if isinstance(exception,ValueError):
return HttpResponse(\'出现异常》。。\')
def process_template_response(self,request,response):
# 如果Views中的函数返回的对象中,具有render方法
print(\'-----------------------\')
return response
views里的方法,返回的类中有render方法,会在processremplateresponse时返回
class Foo:
def render(self):
return HttpResponse(\'OK\')
def test(request):
print(\'没带钱\')
return Foo()
缓存
动态网站需要经常去请求数据,每次请求服务器就会从新计算,这样消耗的时间比读一个标准文件耗时要长,所以django采用缓存机制,将某在一定时间内不会更改的数据写道缓存里,这样使用起来减少了耗时。
设置缓存
缓存系统需要一些设置才能使用。也就是必须告诉它你要把数据还存在数据库,文件系统或者直接在内存中。这个决定很重要,他会决定你的缓存性能,这几个系统缓存速度是不同的。缓存设置通过setting文件的CACHES配置来实现。
Memcached
Django支持的最快,最高效的缓存类型, Memcached 是一个全部基于内存的缓存服务,起初是为了解决LiveJournal.com负载来开发的,后来是由Danga开源出来的。 它被类似Facebook 和 维基百科这种网站使用,用来减少数据库访问,显著的提高了网站的性能。
Memcached 是个守护进程,它被分配了单独的内存块。 它做的所有工作就是为缓存提供一个快速的添加,检索,删除的接口。 所有的数据直接存储在内存中,所以它不能取代数据库或者文件系统的使用。
在安装 Memcached 后, 还需要安装 Memcached 依赖模块。Python 有不少Memcache模块最为常用的是python-memcached and pylibmc两个模块.
需要在Django中使用Memcached时:
将 BACKEND 设置为 django.core.cache.backends.memcached.MemcachedCache 或者 django.core.cache.backends.memcached.PyLibMCCache (取决于你所选绑定memcached的方式)
将 LOCATION 设置为 ip:port 值,ip 是 Memcached 守护进程的ip地址, port 是Memcached 运行的端口。或者设置为 unix:path 值,path 是 Memcached Unix socket file的路径.
在这个例子中,Memcached 运行在本地(127.0.0.1) 的11211端口,使用python-memcached(也就是需要这么一个python插件) 绑定:
CACHES = {
\'default\': {
\'BACKEND\': \'django.core.cache.backends.memcached.MemcachedCache\',
\'LOCATION\': \'127.0.0.1:11211\',
}
}
这个例子中,Memcached 通过一个本地的Unix socket file/tmp/memcached.sock 来交互,也要使用python-memcached绑定:
CACHES = {
\'default\': {
\'BACKEND\': \'django.core.cache.backends.memcached.MemcachedCache\',
\'LOCATION\': \'unix:/tmp/memcached.sock\',
}
}
Memcached有一个非常好的特点就是可以让几个服务的缓存共享。 这就意味着你可以在多台机器上运行Memcached服务,这些程序将会把这几个机器当做 同一个 缓存,从而不需要复制每个缓存的值在每个机器上。为了使用这个特性,把所有的服务地址放在LOCATION里面,用分号隔开或者当做一个list。 这个例子,缓存共享在2个Memcached 实例中,IP地址为172.19.26.240 和 172.19.26.242,端口同为11211: CACHES = { \'default\': { \'BACKEND\': \'django.core.cache.backends.memcached.MemcachedCache\', \'LOCATION\': [ \'172.19.26.240:11211\', \'172.19.26.242:11211\', ] } } 下面的这个例子,缓存通过下面几个 Memcached 实例共享,IP地址为172.19.26.240 (端口 11211), 172.19.26.242 (端口 11212), and 172.19.26.244 (端口 11213):
CACHES = {
\'default\': {
\'BACKEND\': \'django.core.cache.backends.memcached.MemcachedCache\',
\'LOCATION\': [
\'172.19.26.240:11211\',
\'172.19.26.242:11212\',
\'172.19.26.244:11213\',
]
}
}
关于Memcached最后要说一点,基于内存的缓存有一个缺点:因为缓存数据是存储在内存中的,所以如果你的服务器宕机数据就会丢失。还要明确, 内存不能替代常驻的数据存储,所以不要把基于内存的缓存当成你唯一的数据存储方式。毫无疑问的,没有任何的Django缓存后台应该被用来替代常驻存储--它们要做的是缓存解决方案,而不是存储方案--但是我们在这里指出这一点是因为基于内存的缓存真的是非常的临时。
Form
form可以做用户验证 生成HTML请求(保留提交的数据)
from django import forms
class FM(forms.Form):
user=forms.CharField()#变量名必须与html定义的名字一样
pwd=forms.CharField()
email=forms.EmailField()
def fm(request):
if request.method=="GET":
return render(request,\'fm.html\')
elif request.method=="POST":
obj=FM(request.POST)
r1=obj.isvalid()
print(r1)
if r1:#提交数据成功
print(obj.cleaneddata)
else:
print(obj.errors)
print(obj.errors.asjson())#当输入邮箱等格式不对时会报错
return redirect(\'/fm/\')
class FM(forms.Form):
user=forms.CharField(errormessage={\'required\':"用户名不能为空"})#变量名必须与html定义的名字一样
pwd=forms.CharField(maxlength=12,minlength=6,errormessages={\'required\':\'用户名不能为空\',\'minlength\':\'密码长度不能小于6\',\'maxlength\':\'密码长度不能大于12\')
email=forms.EmailField(errormessage={\'required\':\'邮箱不能为空\',\'invalid\':\'邮箱格式错误\'})
obj.erros继承自ErrorDict是一个字典,所以输出错误信息形式为obj.errors[\'user\']