布局响应式
响应式就是浏览器随着边框的缩小会产生的浏览样式的变化。
@media (max-width: 700px) { .jeff{ width: 100%; height: 100px; background-color: yellow; }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .jeff{ width: 100%; height: 100px; background-color: red; } @media (max-width: 700px) { .jeff{ width: 100%; height: 100px; background-color: yellow; } } </style> </head> <body> <div class="jeff">love</div> </body> </html>
当然也可以使用bootstrap里封装好的导航条等代码,其完成响应式的方法也是基于@media完成的。
栅格系统
bootstrap把页面分为12个大格子,使用.col-md-8的方式就可以轻松的把页面划分开。一共有四种方式划分,根据显示屏幕的像素大小分别为.col-xs-<.col-sm-<.col-md-<.col-lg-。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title></title>
<link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.css"/>
</head>
<body>
<div style="background-color: #dddddd">
<div class="col-lg-1">左边</div>
<div class="col-lg-11">右边</div>
</div>
<div style="background-color: #dddddd">
<div class="col-md-1">左边</div>
<div class="col-md-11">右边</div>
</div>
<div style="background-color: #dddddd">
<div class="col-sm-1">左边</div>
<div class="col-sm-11">右边</div>
</div>
<div style="background-color: #dddddd">
<div class="col-xs-1">左边</div>
<div class="col-xs-11">右边</div>
</div>
</body>
</html>
栅格也是根据响应式做的大小调整。
不允许缩放的栅格:
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
hover:
之前做的鼠标悬浮外层div使子层发生样式改变都是使用js来完成的,其实可以直接使用hover来完成:
外层:hover 要改变的里层{悬浮后的样式}
.pg-header .avatar .user-info{ display: none; background-color: white; border: 1px solid #dddddd; position: absolute;width: 200px;top: 48px;right: 2px;color: white;z-index: 100; } .pg-header .avatar:hover .user-info{ display: block;
html模板渲染
#后台视图函数 def test(request): return render(request,‘test.html‘,{‘k1‘: 1,‘k2‘: ‘uuu‘}) #前端test.html <body> <h1>{{ k1 }}</h1> <h1>{{ k2 }}</h1> <script> alert(‘{{ k2 }}‘);//uuu alert({{ k2 }});//uuu not define </script> </body>
后端一定是先将html文件渲染以后再发送给客户端浏览器,{{k2}}在后端被渲染成uuu,前者以字符串形式发出,后者则被前端认为是变量未定义报错。
Cookie
简单的理解为保存在浏览器端“键值对”,用于解决http无状态短连接的问题,发送Http请求时,在请求头中携带当前所有可访问的cookie。
def login(request): if request.method == "GET": return render(request,‘login.html‘) else: user = request.POST.get(‘username‘) pwd = request.POST.get(‘password‘) if user == ‘alex‘ and pwd == ‘123‘: obj = redirect(‘/classes/‘) obj.set_cookie(‘ticket‘,"123123")#设置cookie return obj else: return render(request,‘login.html‘) //登陆的页面视图函数可以接收头部的cookie # 去请求的cookie中找凭证 tk = request.COOKIES.get(‘ticket‘)print(tk) if not tk: return redirect(‘/login/‘)
set_cookie可以有很多的参数:
max_age,存在时长单位s。超过时间就自动失效。
expires与max_age意义相同,只是它用于指定具体的时间。相比较而言,max_age更常用。
def login(request): if request.method == "GET": return render(request,‘login.html‘) else: user = request.POST.get(‘username‘) pwd = request.POST.get(‘password‘) if user == ‘alex‘ and pwd == ‘123‘: obj = redirect(‘/classes/‘) import datetime from datetime import timedelta ct = datetime.datetime.utcnow()#当前时间 v= timedelta(seconds=10)#往后延迟10s value = ct + v # obj.set_cookie(‘ticket‘,"asdasdsd",max_age=10) obj.set_cookie(‘ticket‘,"asdasdsd",expires=value) return obj else: return render(request,‘login.html‘)
path,指定cookie生效的url,默认是path(/),在整个路径下都生效。
domain,指定域名访问。
secure=False,httponly=False部分安全操作,httponly只能自Http请求中传入,js代码无法获取到(抓包依然可以获取),secure是控制Https操作。
cookie签名(类似加盐)
obj.set_signed_cookie(‘ticket‘,"123123",salt=‘jjjjjj‘) request.get_signed_cookie(‘ticket‘,salt=‘jjjjjj‘)
xss攻击
xss就是在网页评论等input框里,写入js语句,从而控制得到后台cookie等操作。django默认是可以阻止xss攻击的。
但是我们有时还是需要使用到传入html语句的。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>评论</h1> {% for item in msg %} <div>{{ item|safe }}</div> {% endfor %} </body> </html>
def test(request): from django.utils.safestring import mark_safe temp = "<a href=‘http://www.baidu.com‘>百度</a>" newtemp = mark_safe(temp) return render(request,‘test.html‘,{‘temp‘:newtemp})
如果你做了操作放行了xss,那么你一定要在后台做过滤来保证你的安全。
def comment(request): if request.method == "GET": return render(request,‘comment.html‘) else: v = request.POST.get(‘content‘) if "script" in v: return render(request,‘comment.html‘,{‘error‘: ‘小比崽子还黑我‘}) else: msg.append(v) return render(request,‘comment.html‘)
CSRF
简单的来说就是在页面生成随机字符串来帮助确认用户身份的(用户下一次登陆就会带着这个字符串)。
django默认开启了CSRF功能,在页面写上{% csrf_token %},浏览器就会渲染成
<input type="hidden" name="csrfmiddlewaretoken" value="HJ5pKbvzGcCMeBYSm37ceuTXraBe6ZTi5xS2d0desCTU9iglNcIBtTEIdYVY28Bp">
同时,在cookie中也有这个字符串。
要想全栈都禁用csrf就要在settings.py中直接注释掉。
局部禁用csrf要使用装饰器@csrf_exempt:
from django.views.decorators.csrf import csrf_exempt @csrf_exempt def csrf1(request): if request.method == ‘GET‘: return render(request,‘csrf1.html‘) else: return HttpResponse(‘ok‘)
局部使用,全局下要禁用,只在使用的函数前加装饰器@csrf_protect:
# ‘django.middleware.csrf.CsrfViewMiddleware‘, from django.views.decorators.csrf import csrf_exempt,csrf_protect @csrf_protect def csrf1(request): if request.method == ‘GET‘: return render(request,‘csrf1.html‘) else: return HttpResponse(‘ok‘)
CBV添加装饰器的方式
CBV: from 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})
from django.views import View from django.utils.decorators import method_decorator @method_decorator(csrf_protect,name=‘dispatch‘)#name是使用的函数名 class Foo(View): def get(self,request): pass def post(self,request): pass
如果网站有csrf,那么往后台发Ajax时也必须要把csrf传到后台。除了把标签里的input中的csrf以data传到后台,还可以通过cookie的方式传递。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form method="POST" action="/csrf1.html"> {% csrf_token %} <input id="user" type="text" name="user" /> <input type="submit" value="提交"/> <a onclick="submitForm();">Ajax提交</a> </form> <script src="/static/jquery-1.12.4.js"></script> <script src="/static/jquery.cookie.js"></script>{# jQuery简单获取cookie的插件#} <script> function submitForm(){ var token = $.cookie(‘csrftoken‘); var user = $(‘#user‘).val(); $.ajax({ url: ‘/csrf1.html‘, type: ‘POST‘, headers:{‘X-CSRFToken‘: token},//只能放在请求头里传到后台,X-CSRFToken名字不能改 data: { "user":user}, success:function(arg){ console.log(arg); } }) } </script> </body> </html>
$.cookie(‘csrftoken‘)可以取到cookie的值,还可以设置cookie的值$.cookie(‘csrftoken‘,‘123123‘),cookie的值还可以是很多。
admin管理
django自带了数据库后台管理,我们使用
python manage.py createsuperuser
设置用户账号与密码就可以登陆进后台。
操作的表要在admin.py中注册:
from django.contrib import admin from app01 import models admin.site.register(models.UserInfo)
MVC与MTV
这两者其实是一个概念,MVC是models(数据库,模型),views(html模板),controllers(业务逻辑处理)。而MTV则是换了个名称models(数据库,模型),templates(html模板),views(业务逻辑处理)。django使用的就是MTV的逻辑。
django的生命周期
web框架的本质是socket,我们使用的django从本质上上来说是wsgi(wsgiref模块或其他wsgi模块)与django两部分组成。
Wsgi+Django from wsgiref.simple_server import make_server def RunServer(environ, start_response): Django框架开始 中间件 路由系统 视图函数 。。。。。 start_response(‘200 OK‘, [(‘Content-Type‘, ‘text/html‘)]) return [bytes(‘<h1>Hello, web!</h1>‘, encoding=‘utf-8‘), ] if __name__ == ‘__main__‘: httpd = make_server(‘127.0.0.1‘, 8000, RunServer) httpd.serve_forever()
中间件
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse class M1(MiddlewareMixin): def process_request(self,request): print(‘m1.process_request‘) def process_view(self, request, callback, callback_args, callback_kwargs): print(‘m1.process_view‘) # response = callback(request,*callback_args,**callback_kwargs) # return response def process_response(self,request,response): print(‘m1.process_response‘) return response def process_exception(self, request, exception): print(‘m1.process_exception‘) def process_template_response(self,request,response): """ 视图函数的返回值中,如果有render方法,才被调用 :param request: :param response: :return: """ print(‘m1.process_template_response‘) return response
创建完在配置中注册即可生效。process_request与请求信息相关,若定义返回值,则直接从此中间件的response返回。process_view与视图有关,若有返回值,直接跳过剩下的中间件的process_view函数,从最后一个response返回,process_exception,出错时才会触发,并且跳过之后所有process_exception,从最后一个response返回。process_response有返回值,并且直接从最后一个response返回。
class JSONResponse: def __init__(self,req,status,msg): self.req = req self.status = status self.msg = msg def render(self):#有render方法才能触发 import json ret = { ‘status‘: self.status, ‘msg‘:self.msg } return HttpResponse(json.dumps(ret)) def test(request): return JSONResponse(request,True,"错误信息")
中间件是为了对所有请求或一部分请求做批量处理的。