s4 django
# web框架本质
- 参考博客
https://www.cnblogs.com/wupeiqi/articles/5237672.html
import socket
sock = socket.socket()
sock.bind(('127.0.0.1',8080))
sock.listen(5)
while True:
conn,addr = sock.accept() # hang住
# 有人来连接了
# 获取用户发送的数据
data = conn.recv(8096)
conn.send(b"HTTP/1.1 200 OK\r\n\r\n")
conn.send(b'123123')
conn.close()
1. Http,无状态,短连接
2.
浏览器(socket客户端)
网站(socket服务端)
3. 自己写网站
a. socket服务端
b. 根据URL不同返回不同的内容
路由系统:
URL -> 函数
c. 字符串返回给用户
模板引擎渲染:
HTML充当模板(特殊字符)
自己创造任意数据
字符串
4. Web框架:
框架种类:
- a,b,c --> Tornado
- [第三方a],b,c --> wsgiref -> Django
- [第三方a],b,[第三方c] --> flask + jinja2
分类:
- Django框架
- 其他
- 基本配置
pip3 install django
命令:
# 创建Django程序
django-admin startproject mysite
# 进入程序目录
cd mysite
# 启动socket服务端,等待用户发送请求
python manage.py runserver 127.0.0.1:8080
pycharm:
...
Django程序目录:
mysite
mysite
- settings.py # Django配置文件
- url.py # 路由系统:url->函数
- wsgi.py # 用于定义Django用socket, wsgiref,uwsgi
# 对当前Django程序所有操作可以基于 python manage.py runserver
manage.py
# Django目录介绍
django-admin startproject mysite
cd mysite
python manage.py starapp app01
project
- app01
- admin Django自带后台管理相关配置
- modal 写类,根据类创建数据库表
- test 单元测试
- views 业务处理,多时可创建目录
- app02
- app03
1. 创建project
2. 配置:
- 模板路径
template目录
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'template')],
'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',
],
},
},
]
- 静态文件路径
static目录
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR,'static'),
)
3. 额外配置
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
4.url对应关系
/login/ login
from django.shortcuts import render,redirect,HttpResponse
def login(request):
request.method
request.POST --> 请求体
request.GET --> 请求头URL
request.POST.getlist('多选下拉框')
return HttprResponse(‘字符串’)
return render(request,'xx/login.html',{...})
return redirect('/url/')
# return render(request,'xx/login.html',{...})
# \template\xx\login.html
get请求:只有request.GET
post请求:request.GET和request.POST都可能有值
5.模板引擎中的特殊标志
login.html
{{name}}
def login(request):
return render(request,'login.html',{'name':'alex'})
def index(request):
# return HttpResponse('index')
return render(request,
'index.html',
{'name':'alex',
'users':['abc','def'],
'user_dict':{'k1':'v1','k2':'v2'},
'user_list_dict':[
{'id':1,'name':'alex','email':'alex3714@163.com'} ,
{'id':2,'name':'alex2','email':'alex3714@1632.com'} ,
{'id':3,'name':'alex3','email':'alex3714@1633.com'} ,
]
})
<h1>模板标记的学习</h1>
<p>{{ name }}</p>
<p>{{ users.0}}</p>
<p>{{ users.1}}</p>
<p>{{ user_dict.k1}}</p>
<p>{{ user_dict.k2}}</p>
<h1>循环</h1>
<ul>
{% for item in users %}
<li>{{ item }}</li>
{% endfor %}
</ul>
<table border="1">
{% for row in user_list_dict %}
<tr>
<td>{{ row.id }}</td>
<td>{{ row.name }}</td>
<td>{{ row.email }}</td>
<td><a>编辑</a>|<a href="/del/?nid={{ row.id }}">删除</a></td>
</tr>
{% endfor %}
</table>
{%if 1>2 %}
...
{%endif%}
# Ajax
# jQuery
$.ajax({
url: '要提交的地址',
type: 'POST', // GET或POST,提交方式
data: {'k1':[1,2,3,4],'k2':JSON.stringify({'k1':v1,...})}, // 提交的数据
dataType: 'JSON',// arg的数据格式
traditional: true,// 如果提交的数据的值有列表,则需要添加此属性
success:function(data){
// 当前服务端处理完毕后,自动执行的回调函数
// data返回的数据
location.href = "要跳转的地址"
}
})
# 其他:
- Form表单提交,页面会刷新
- Ajax提交页面不刷新
- 使用时机:
模态对话框(Ajax)
- 少量输入框
- 数据少
- 登录
新URL方式
- 操作多
- 对于大量的数据以及操作
- js阻止默认事件的发生
onclick=‘return modelEdit();’
function modelEdit(){
alert(123);
return false;
// return true;
}
- jQuery 事件阻止默认事件发生
$('#addmodal').click(function(){
return false;
})
# 插件
- bootstrap
- 看图拷贝 *
- 常用标签
- 样式
1. 响应式布局: @media()
2. 栅格:
3. 表格
4. 导航条
5. 路径导航
- fontawesome
# 当鼠标移动到xx样式的标签上时,其子标签.g应用以下属性
.xx:hover .g{
# 后台管理页面示例
- Cookie
# 使用:每页显示多少条
a. 保存在浏览器端“键值对”
b. 服务端可以向用户浏览器端写cookie
c. 客户端每次方请求时,会携带cookie去
- 发送Http请求时,在请求头中携带当前所有可访问的cookie
- 响应头
@xzxx
def index(request):
obj = HttpResponse('...')
obj.set_cookie(.....)
request.COOKIES.get(...)
obj.set_signed_cookie(.....)
request.get_signed_cookie(....)
def classes(request):
# 去请求的cookie中找凭证
# print(request.COOKIES)
# 打印所有cookie
tk = request.COOKIES.get('ticket')
# tk = request.get_signed_cookie('ticket',salt='jjjjjj')
if not tk:
return redirect('/login/')
def login(request):
...
obj = redirect('/classes/')
# obj = HttpResponse('ok')
# obj = redirect(..)
# obj.set_cookie('ticket','sssssdfdfdfd')
# obj.set_cookie('ticket',"asdasdsd",max_age=10)
# import datetime
# from datetime import timedelta
# ct = datetime.datetime.utcnow()
# v= timedelta(seconds=10)
# value = ct + v
# obj.set_cookie('ticket',"asdasdsd",expires=value)
obj.set_signed_cookie('ticket',"123123",salt='jjjjjj')
return obj
set_cookie参数
key,
value='',
max_age=None, # 超时值
expires=None, # 具体超时日期
path='/', # 路径
domain=None, # 域名 sso统一用户登陆使用
secure=False, # Https使用
httponly=False # 只能自Http请求中传入,js代码无法获取到(相对)
cookie签名:
obj.set_signed_cookie('ticket',"123123",salt='jjjjjj')
自定义cookie签名
# settings.py
SIGNING_BACKEND = "c1.MySigner"
# project/c1.py
from django.core.signing import TimestampSigner
class MySigner(TimestampSigner):
def sign(self, value):
return value+'123123123'
def unsign(self, value, max_age=None):
v = value[0:-8]
return v
# 装饰器实现登陆
# MVC,MTV
models(数据库,模型) views(html模板) controllers(业务逻辑处理) --> MVC
models(数据库,模型) templates(html模板) views(业务逻辑处理) --> MTV
Django -> MTV
- 路由系统
url -> 函数
a. /login/ -> def login
b. /add-user/(\d+)/ -> def add_user(request,a1)
/add-user/(\d+)/(\d+)/ -> def add_user(request,a1,a2)
c. /add-user/(?P<a1>\d+)/ -> def add_user(request,a1)
终止符:
^edit$
伪静态
url(r'^edit/(\w+).html$', views.edit),
# SEO
d. 路由分发
from django.conf.urls import url,include
urls.py
url(r'^app01/', include('app01.urls')),
app01.urls.py
url(r'^index.html$', views.index),
# 默认页面
# url(r'^', default),
from django.shortcuts import HttpResponse
def default(request):
return HttpResponse('something wrong')
e. 别名
/add-user/(\d+)/ -> def add_user(request,a1) name=n1
根据名称可以反向生成URL
1. 在Python代码中
from django.urls import reverse
# v = reverse('n1',args = (451,)) # add-user/(\d+)/
v = reverse('n1',kwargs={'a1':1111}) # /add-user/(?P<a1>\d+)/
print(v)
# /index/451/
2. 模板语言中:
url(r'^login/', views.login,name='m1')
{% url "m1" %}
{% url "m1" i %}
{% for i in user_list %}
<li>{{ i }} | <a href="/edit/{{ i }}/"> 编辑</a></li>
<li>{{ i }} | <a href="{% url 'n2' i 1%}"> 编辑</a></li>
{% endfor %}
# 别名用于做权限
使用一:
def index(request):
url_list = [
'n1',
'n2',
'n3',
]
return render(...,url_list)
html:
<ul>
for v in url_list:
<li> <a href='{% url v %}'>ff</a> </li>
</ul>
使用二:
def index(request):
url_list = [
'n1',
'n2',
'n3',
]
temp = []
for i in url_list:
url = reverse(i)
temp.append(url)
return render(...,temp)
html:
<ul>
for url in temp:
<li> <a href='{{url}}'>ff</a> </li>
</ul>
- 视图函数
- CBV & FBV
# get 查,post 创建,put 更新,delete 删除 等 -----ajax方式下
# form表单只 post、get
# urls.py
from app01 import views
urlpatterns = [
url(r'^login.html$',views.Login.as_vies())
]
#views.py
from django.views import View
class Login(View):
# get 查
# post 创建
# put 更新
# delete 删除
def get(self,request):
# return HttpResponse('login.get')
return render(request,'login.html')
def post(self,request):
print(request.POST.get('user'))
return HttpResponse('Login.post')
- 自定义dispatch:
from django.views import View
class Login(View):
# get 查,post 创建,put 更新,delete 删除 等 -----ajax方式下
# form表单只 post、get
def dispatch(self, request, *args, **kwargs):
print('before')
obj=super(Login,self).dispatch(request, *args, **kwargs)
print('after')
return obj
def get(self,request):
# return HttpResponse('login.get')
return render(request,'login.html')
def post(self,request):
print(request.POST.get('user'))
return HttpResponse('login.post')
- CBV中添加装饰器
def wrapper(func):
def inner(*args,**kwargs):
return func(*args,**kwargs)
return inner
1. 指定方法上添加装饰器
# class Foo(View):
#
# @method_decorator(wrapper)
# def get(self,request):
# pass
# @method_decorator(wrapper)
# def post(self,request):
# pass
2. 在类上添加
# @method_decorator(wrapper,name='dispatch')
# @method_decorator(wrapper,name='get') # get方式
# class Foo(View):
#
# def get(self,request):
# pass
#
# def post(self,request):
# pass
- 分页
- 分批获取数据
models.UserInfo.objects.all()[0:10]
models.UserInfo.objects.all()[10:20]
- django 自带
适用于:只有上一页,下一页
# views.py
def index(request):
# for i in range(300):
# name='root'+str(i)
# models.UserInfo.objects.create(name=name,age=18,ut_id=1)
from django.core.paginator import Paginator,Page,PageNotAnInteger,EmptyPage
current_page=request.GET.get('page')
user_list=models.UserInfo.objects.all()
paginator=Paginator(user_list,10)
# per_page;每页条目
# count 数据总个数
# num_page 总页数
# page_range 总页数的索引范围
# page: page对象
try:
posts =paginator.page(current_page)
except PageNotAnInteger as e:
posts =paginator.page(1)
except EmptyPage as e:
posts =paginator.page(1)
# has_next 是否有下一页
# next_page_number 下一页页码
# has_previous 是否有上一页
# previous_page_num 上一页页码
# object_list 分页后的数据列表
# number 当前页
# paginator 对象
return render(request,'index.html',{'posts':posts})
# html
<h1>用户列表</h1>
<ul>
{% for row in posts.object_list %}
<li>{{ row.name }}</li>
{% endfor %}
</ul>
<div>
{% if posts.has_next %}
<a href="/index.html?page={{ posts.next_page_number }}">下一页</a>
{% endif %}
<!--
{% for num in posts.paginator.page_range %}
<a href="/index.html?page={{ num }}">{{ num }}</a>
{% endfor %}
-->
{% if posts.has_previous %}
<a href="/index.html?page={{ posts.previous_page_number }}">上一页</a>
{% endif %}
</div>
- 自定义分页组件
- 模板
- 基本使用
- 母版继承
母版:
<html>
...
{% block s1 %} {%endblock%} # 占位
...
{% block s2 %} {%endblock%}
</html>
子板:
{% extends "layout.html "%}
{% block s1 %} <h1>fff</h1> {%endblock%}
{% block s2 %} <h1>ffffff</h1> {%endblock%}
- include
导入小组件
# pub.html
<div>
<h3>特别漂亮的组件</h3>
<div class="title">标题:{{ name }}</div>
<div class="content">内容:{{ name }}</div>
</div>
# html中:
{% include 'pub.html' %}
- 函数-> 自动执行
- 模板自定义函数:
- simple_filter
- 最多两个参数,方式: {{第一个参数|函数名称:"第二个参数"}}
- 可以做条件判断
- simple_tag
- 无限制: {% 函数名 参数 参数%}
-自定义simple_tag步骤:
a、在app中创建templatetags模块
b、创建任意 .py 文件,如:xx.py
from django import template
register = template.Library()
@register.filter
# filter 可作为条件语句判断,而simple_tag 不能
def my_upper(value,arg)
return value + argh
@register.simple_tag
def my_simple_time(v1,v2,v3):
return v1 + v2 + v3
c、在使用自定义simple_tag的html文件中导入之前创建的 xx.py 文件名
{% load xx %}
d、使用simple_tag
{{name|my_upper:"xxx"}} #filter
{% if name|my bool %}
{% else %}
{% endif %}
{% my_simple_time 1 2 3%}
{% my_input 'id_username' 'hide'%}
e、在settings中配置当前app,不然django无法找到自定义的simple_tag
- 例子:
# html
<h1>filter</h1>
{{ name|my_upper:'666' }}
{% if name|my_bool %}
<h3>true</h3>
{% else %}
<h3>false</h3>
{% endif %}
<h2>tag</h2>
{% my_lower 'ALEX' 'x' 'sb' 'dddd'%}
# xx.py
from django import template
register =template.Library()
@register.filter
def my_upper(value,arg):
return value+arg
@register.filter
def my_bool(value):
return False
@register.simple_tag
def my_lower(value,a1,a2,a3):
return value+a1+a2+a3
- xss攻击
# 跨站脚本攻击
- 慎用 safe和mark_safe
- 非要用,一定要过滤关键字
- 后台:
from django.utils.safestring import mark_safe
newtemp = mark_safe(temp)
- 前端:
{{temp|safe}}
- CSRF/XSRF
# 跨站请求伪造
a. 基本应用
form表单中添加
{% csrf_token %}
{{csrf_token}}
# 仅显示字符串
# django默认在cookie中生成csrftoken
b. 全站禁用
# 'django.middleware.csrf.CsrfViewMiddleware',
c. 局部禁用
'django.middleware.csrf.CsrfViewMiddleware',
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')
d. 局部使用
# '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')
c. 特殊CBV
from django.views import View
from django.utils.decorators import method_decorator
@method_decorator(csrf_protect,name='dispatch') # 只能加在类上面
class Foo(View):
def get(self,request):
pass
def post(self,request):
pass
- Ajax提交数据时,携带CSRF
方法一:放置在data中携带
<form action="/csrf1.html" method="POST" >
{% 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>
function submitForm(){
var csrf= $("input[name='csrfmiddlewaretoken']").val();
var user=$('#user').val()
$.ajax({
url:'/csrf1.html',
type:"POST",
data:{'user':user,'csrfmiddlewaretoken':csrf},
success:function(arg){
console.log(arg);
}
})
}
</script>
方法二:放在请求头中
<form action="/csrf1.html" method="POST" >
{% 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>
function submitForm(){
var token=$.cookie("csrftoken");
var user=$('#user').val();
$.ajax({
url:'/csrf1.html',
type:"POST",
headers:{'X-CSRFToken':token},
data:{'user':user},
success:function(arg){
console.log(arg);
}
})
}
# 插件:
jquery.cookie.js
# 获取:
$.cookie('csrftoken')
# 设置
$.cookie('dfdfdfdfdf','234324234324234')
- admin
python manage.py createsuperuser
# app01/admin.py
from django.contrib import admin
from app01 import models
# Register your models here.
admin.site.register(models.UserInfo)
- Session
- cookie是什么?
保存在客户端浏览器上的键值对
- session是什么?
保存在服务器端的数据(本质是键值对)
{
‘sdsfefefefe’:{'id':1,'name':'yuhao',email='xxx'}
‘eerererfefe’:{'id':1,'name':'yuhao2',email='xxx'}
}
# session依赖cookie
# 作用:保持会话 web网站
# 好处:敏感信息不会直接给客户
# 默认在数据库
# 大型放在缓存
- 梳理:
1.保存在服务器端的数据(本质是键值对)
2.配置文件中
-存储位置
-超时时间、每次刷新更新时间
3.request.session
-增删改
-获取随机字符串
-主动设置超时时间
- django中的使用:
obj =models.UserAdmin.objects.filter(username=u,password=p).first()
if obj:
request.session['username']=obj.username
return redirect('/index/')
v=request.session.get('username')
if v:
return HttpResponse('sucessfull,welcome %s'%v)
else:
return redirect('/login/')
- django session 操作:
def index(request):
# 获取、设置、删除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.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
- Session用户验证
def login(func):
def wrap(request, *args, **kwargs):
# 如果未登陆,跳转到指定页面
if request.path == '/test/':
return redirect('http://www.baidu.com')
return func(request, *args, **kwargs)
return wrap
- Django提供了5种类型的Session供开发者使用:
数据库(默认)
缓存
文件
缓存+数据库
加密cookie
- 中间件
1. Django请求生命周期
请求 -> WSGI -> 中间件 -> url -> 视图...
2. Django使用的WSGI的服务:
测试用:wsgiref
生产用:uwsgi
3. 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()
- 类
process_request
process_response(...response)
必须有返回值
return response
process_view
process_exception
process_template_view
- 注册中间件
[
....
]
- 应用:
# 对所有请求或一部分请求做批量处理
# 登陆验证
# 缓存
- 执行过程图
- 例子一:
# settings.pymysql
MIDDLEWARE = [
...
'm1.Middle1',
'm1.Middle2',
]
# m1.py
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
class Middle1(MiddlewareMixin):
def process_request(self, request):
print('m1.process_request')
# return HttpResponse('不要在往下周了')
def process_response(self, request, response):
print('m1.process_response')
return response
class Middle2(MiddlewareMixin):
def process_request(self, request):
print('m2.process_request')
# return HttpResponse('不要在往下周了')
def process_response(self, request, response):
print('m2.process_response')
return response
- 例子二:
# project\md.py
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
class M2(MiddlewareMixin):
def process_request(self,request):
print('m2.process_request')
def process_view(self, request, callback, callback_args, callback_kwargs):
print('m2.process_view')
def process_response(self,request,response):
print('m2.process_response')
return response
def process_exception(self, request, exception):
print('m2.process_exception')
return HttpResponse('错误了...')
# app01\views.py
class JSONResponse:
# 封装JSON功能
def __init__(self,req,status,msg):
self.req = req
self.status = status
self.msg = msg
def render(self):
import json
ret = {
'status': self.status,
'msg':self.msg
}
return HttpResponse(json.dumps(ret))
def test(request):
# print('test')
# return HttpResponse('...')
ret = {}
return JSONResponse(request,True,"错误信息")
- AJAX全套
Ajax博客:
http://www.cnblogs.com/wupeiqi/articles/5703697.html
1. Ajax,
a. XMLHttpRequest
GET请求:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
alert(xhr.responseText);
}
};
xhr.open('GET','/add2/?i1=12&i2=19');
xhr.send();
POST请求:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
alert(xhr.responseText);
}
};
xhr.open('POST','/add2/');
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send("i1=12&i2=19");
b. jQuery Ajax
# 内部基于“原生Ajax”
$.ajax({
url:'/add1/',
type:"POST",
data:{'i1':$('#i1').val(),'i2':$('#i2').val()},
success:function(arg){
$('#i3').val(arg);
}
})
2. 伪Ajax,非XMLHttpRequest
技术:
iframe标签,不刷新发送HTTP请求
<div>
<input type="text"id="txt1">
<input type="button"value="查看"onclick="changeSrc();">
</div>
<iframe id="ifr" src="http://www.baidu.com" frameborder="0" style="width: 1000px;height:2000px;"></iframe>
<script>
function changeSrc(){
var inp =document.getElementById('txt1').value;
document.getElementById('ifr').src=inp
}
</script>
示例:
<form id="f1" method="POST" action="/fake_ajax/" target="ifr">
<iframe id="ifr" name="ifr" style="display: none"></iframe>
<input type="text" name="user" />
<a onclick="submitForm();">提交</a>
</form>
<script>
function submitForm(){
document.getElementById('ifr').onload = loadIframe;
document.getElementById('f1').submit();
}
function loadIframe(){
var content = document.getElementById('ifr').contentWindow.document.body.innerText;
alert(content);
}
</script>
3. 基于Ajax上传文件:
1. XMLHttpRequest
- 原生: FormData
- jQuery: FormData
2. 伪造
- 兼容性
3. 总结:
1. 上传文件
伪造
2. 数据
- jQuery
- XMLHttpRequest(伪造)
3. 不要被好看的上传按钮迷惑
4. 文件上传示例代码:
<body>
<h1>原生Ajax上传文件</h1>
<input type="file"id="i1">
<a onclick="upload1();">上传</a>
<div id="container1"></div>
<h1>jQuery Ajax上传文件</h1>
<input type="file"id="i2">
<a onclick="upload2();">上传</a>
<div id="container2"></div>
<h1>伪Ajax上传文件</h1>
<form id ='f1'action="/upload/"method="POST" target="ifr"enctype="multipart/form-data">
<iframe id="ifr" name="ifr" style="display:none"></iframe>
<input type="file"name="fafafa">
<a href="#" onclick="upload3();">上传</a>
</form>
<div id="container3"></div>
<script src="/static/jquery-1.12.4.js"></script>
<script>
function upload1(){
var formData = new FormData();
// 原生上传依赖FormData
// 不用加 setRequestHeader
formData.append('k1','v1');
formData.append('fafafa',document.getElementById('i1').files[0]);
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
var file_path =xhr.responseText;
var tag=document.createElement('img');
tag.src ='/'+file_path;
document.getElementById('container1').appendChild(tag);
}
};
xhr.open('POST','/upload/');
xhr.send(formData);
}
function upload2(){
var formData = new FormData();
formData.append('k1','v1');
// formData.append('fafafa',document.getElementById('i1').files[0]);
formData.append('fafafa',$('#i2')[0].files[0]);
// jQuery 和 Dom 转换
// $('#i2') --> $('#i2')[0]
// document.getElementById('i1') --> $(document.getElementById('i1'))
$.ajax({
url:'/upload/',
type:'POST',
data:formData,
contentType:false,
processData:false,
success:function(arg){
var tag=document.createElement('img');
tag.src ='/'+arg;
$('#container2').append(tag)
}
})
}
function upload3(){
document.getElementById('ifr').onload=loadIframe;
document.getElementById('f1').submit();
}
function loadIframe(){
var content =document.getElementById('ifr').contentWindow.document.body.innerText;
var tag=document.createElement('img');
tag.src ='/'+content;
$('#container3').append(tag)
}
</script>
import os
def upload(request):
if request.method=='GET':
return render(request,'upload.html')
else:
print(request.POST,request.FILES)
file_obj =request.FILES.get('fafafa')
file_path =os.path.join('static',file_obj.name)
with open(file_path,'wb') as f:
for chunk in file_obj.chunks():
f.write(chunk)
return HttpResponse(file_path)
5. JSONP(跨域Ajax)
武陪齐博客:
www.cnblogs.com/wupeiqi/articles/5369773.html
JSONP是一种方式,目的解决跨域问题
Ajax存在问题:
访问自己域名URL
访问其他域名URL - 被阻止
浏览器的同源策略,
- 禁止:Ajax跨域发送请求时,再回来时浏览器拒绝接受
- 允许:script标签没禁止
开发需求:向其他网站发Http请求
- 浏览器->服务端->发送请求
- 浏览器直接发送请求【考虑同源】
1. 客户端
- URL?callback=xxxx
- function xxxx(arg){}
2. 服务端
- 获取 funcname = request.GET.get(callback)
- 返回: funcname(....)
使用:
1. 自己写动态创建script
function getUsers(){
var tag = document.createElement('script');
tag.src = "http://www.s4.com:8001/users/?funcname=bbb?sdd";
document.head.appendChild(tag);
}
2. jQuery
$.ajax({
url: 'http://www.s4.com:8001/users/',
type: 'GET',
dataType: 'JSONP',
jsonp: 'funcname',
jsonpCallback: 'bbb'
})
其他:
- 只能发GET请求
- 约定
代码:
<input type="button" value="获取用户列表" onclick="getUsers();">
<ul id="user_list">
</ul>
<script src="/static/jquery-1.12.4.js"></script>
<script>
/*
function getUsers(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if (xhr.readyState ==4){
var content= xhr.responseText;
console.log(content);
}
};
xhr.open('GET','http://www.s4.com:8001/users/');
xhr.send();
}
*/
/*
function getUsers(){
var tag=document.createElement('script');
tag.src ='http://www.s4.com:8001/users/?funcname=bbb';
document.head.appendChild(tag);
}
function bbb(arg){
console.log(arg)
}
*/
function getUsers(){
$.ajax({
url:'http://www.s4.com:8001/users/',
type:'GET',
dataType:'JSONP',
jsonp:'funcname',
jsonpCallback:'bbb'
})
}
function bbb(arg){
console.log(arg);
}
</script>
from django.shortcuts import render,HttpResponse
import json
# Create your views here.
def users(request):
v=request.GET.get('funcname')
print('requesting....')
user_list= [
'alex','eric','egon'
]
user_list_str =json.dumps(user_list)
temp='%s(%s)' %(v,user_list,)
return HttpResponse(temp)
- CORS跨站资源共享
返回值增加响应头
简单请求:
def new_users(request):
obj = HttpResponse('返回内容')
obj['Access-Control-Allow-Origin'] = "*"
return obj
复杂请求:
def new_users(request):
if request.method == "OPTIONS":
obj = HttpResponse()
obj['Access-Control-Allow-Origin'] = "*"
obj['Access-Control-Allow-Methods'] = "DELETE"
return obj
obj = HttpResponse('asdfasdf')
obj['Access-Control-Allow-Origin'] = "*"
return obj
- 可以发送任何请求
代码:
<input type="button" value="获取用户列表" onclick="getUsers();">
<ul id="user_list">
</ul>
<script src="/static/jquery-1.12.4.js"></script>
<script>
function getUsers(){
$.ajax({
url:'http://www.s4.com:8001/new_users/',
type:'GET',
success:function(arg){
console.log(arg);
}
})
}
</script>
def new_users(request):
user_list= [
'alex','eric','egon'
]
user_list_str =json.dumps(user_list)
obj=HttpResponse(user_list_str)
obj['Access-Control-Allow-Origin']='*'
return obj
- 缓存
- 序列化
- 信号