Python-Django其他组件②之分页、Form、序列化、model进阶、ajax
来自:Pixiv 画师( 紫李鳥 )
- 目录
- 分页
- Form
- 序列化
- model进阶
- Ajax
分页
Django内置分页:
views.py
def index(request):
BookList=[]
for i in range(1,100):
BookList.append('Book'+str(i))
#Book.objects.bulk_create(BookList) #批量导入数据
paginator = Paginator(BookList, 10)
page = request.GET.get('page', 1)
currentPage = int(page)
try:
print(page)
book_list = paginator.page(page)
except PageNotAnInteger:
book_list = paginator.page(1)
except EmptyPage:
book_list = paginator.page(paginator.num_pages)
return render(request,'index.html',locals())
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>分页</title>
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<ul>
{% for book in book_list %}
<li>{{ book }}</li>
{% endfor %}
</ul>
<ul class="pagination" id="pager">
{% if book_list.has_previous %}
<li class="previous"><a href="/index/?page={{ book_list.previous_page_number }}">上一页</a></li>
{% else %}
<li class="previous disabled"><a href="#">上一页</a></li>
{% endif %}
{% for num in paginator.page_range %}
{% if num == currentPage %}
<li class="item active"><a href="/index/?page={{ num }}">{{ num }}</a></li>
{% else %}
<li class="item"><a href="/index/?page={{ num }}">{{ num }}</a></li>
{% endif %}
{% endfor %}
{% if book_list.has_next %}
<li class="next"><a href="/index/?page={{ book_list.next_page_number }}">下一页</a></li>
{% else %}
<li class="next disabled"><a href="#">下一页</a></li>
{% endif %}
</ul>a
</body>
</html>
内置分页扩展:
views.py
def index(request):
BookList=[]
for i in range(1,100):
BookList.append('Book'+str(i))
paginator = Paginator(BookList, 15)
page = request.GET.get('page', 1)
currentPage = int(page)
# 如果页数十分多时,换另外一种显示方式
if paginator.num_pages > 30:
if currentPage - 5 < 1:
pageRange = range(1, 11)
elif currentPage + 5 > paginator.num_pages:
pageRange = range(currentPage - 5, paginator.num_pages + 1)
else:
pageRange = range(currentPage - 5, currentPage + 5)
else:
pageRange = paginator.page_range
try:
book_list = paginator.page(page)
except PageNotAnInteger:
book_list = paginator.page(1)
except EmptyPage:
book_list = paginator.page(paginator.num_pages)
return render(request, "index.html", locals())
自定制分页组件:
组件:pager.py
class Pagination(object):
def __init__(self, current_page, all_count, per_page_num=10, pager_count=8):
"""
封装分页相关数据
:param current_page: 当前页
:param all_count: 数据库中的数据总条数
:param per_page_num: 每页显示的数据条数
:param pager_count: 最多显示的页码个数
用法:
queryset = model.objects.all()
page_obj = Pagination(current_page,all_count)
page_data = queryset[page_obj.start:page_obj.end]
获取数据用page_data而不再使用原始的queryset
获取前端分页样式用page_obj.page_html
"""
try:
current_page = int(current_page)
except Exception as e:
current_page = 1
if current_page < 1:
current_page = 1
self.current_page = current_page
self.all_count = all_count
self.per_page_num = per_page_num
# 总页码
all_pager, tmp = divmod(all_count, per_page_num)
if tmp:
all_pager += 1
self.all_pager = all_pager
self.pager_count = pager_count
self.pager_count_half = int((pager_count - 1) / 2)
@property
def start(self):
return (self.current_page - 1) * self.per_page_num
@property
def end(self):
return self.current_page * self.per_page_num
def page_html(self):
# 如果总页码 < 11个:
if self.all_pager <= self.pager_count:
pager_start = 1
pager_end = self.all_pager + 1
# 总页码 > 11
else:
# 当前页如果<=页面上最多显示11/2个页码
if self.current_page <= self.pager_count_half:
pager_start = 1
pager_end = self.pager_count + 1
# 当前页大于5
else:
# 页码翻到最后
if (self.current_page + self.pager_count_half) > self.all_pager:
pager_end = self.all_pager + 1
pager_start = self.all_pager - self.pager_count + 1
else:
pager_start = self.current_page - self.pager_count_half
pager_end = self.current_page + self.pager_count_half + 1
page_html_list = []
BaseUrl = '/myindex'
# 添加前面的nav和ul标签
page_html_list.append('''
<nav aria-label='Page navigation>'
<ul class='pagination'>
''')
first_page = '<li><a href="%s?page=%s">首页</a></li>' % (BaseUrl,1)
page_html_list.append(first_page)
if self.current_page <= 1:
prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
else:
prev_page = '<li><a href="%s?page=%s">上一页</a></li>' % (BaseUrl,self.current_page - 1,)
page_html_list.append(prev_page)
for i in range(pager_start, pager_end):
if i == self.current_page:
temp = '<li class="active"><a href="%s?page=%s">%s</a></li>' % (BaseUrl,i, i,)
else:
temp = '<li><a href="%s?page=%s">%s</a></li>' % (BaseUrl,i, i,)
page_html_list.append(temp)
if self.current_page >= self.all_pager:
next_page = '<li class="disabled"><a href="#">下一页</a></li>'
else:
next_page = '<li><a href="%s?page=%s">下一页</a></li>' % (BaseUrl,self.current_page + 1,)
page_html_list.append(next_page)
last_page = '<li><a href="%s?page=%s">尾页</a></li>' % (BaseUrl,self.all_pager,)
page_html_list.append(last_page)
# 尾部添加标签
page_html_list.append('''
</nav>
</ul>
''')
return ''.join(page_html_list)
views.py
from app.pager import Pagination
def myindex(request):
BookList=[]
for i in range(1,100):
BookList.append('Book'+str(i))
pager_obj = Pagination(request.GET.get('page', 1), len(BookList))
data_list = BookList[pager_obj.start:pager_obj.end]
html = pager_obj.page_html()
return render(request,'myindex.html',locals())
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>自定义分页组件</title>
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<ul>
{% for data in data_list %}
<li>{{ data }}</li>
{% endfor %}
<br>
</ul>
{{ html |safe}}
</body>
</html>
参考blog:
Form
验证用户请求;生成Html代码
作用过程:
1、定制Form类check() [约束条件、自定义valid信息]
2、url对应函数:处理数据
①GET:obj=check()
生成html代码
②POST:obj=check(request.POST)
if checkFrom(request.POST).is_valid():
return HttpResponse(‘验证成功!’)
else:
obj=checkFrom(request.POST)
return render(request,’f1.html’,locals())
前端数据交给Form类处理,返回valid信息到前端
3、html页面
将生成的html代码与valid信息显示即可
表单提交:(显示用户列表;添加/修改用户)
#urls.py>>>
urlpatterns = [
path('admin/', admin.site.urls),
path('user/', views.user),
path('add/', views.add),
path('edit/', views.edit),
]
#models.py>>>
class User(models.Model):
username=models.CharField(max_length=12)
password=models.CharField(max_length=16)
email=models.EmailField()
#checkForm.py>>>
class checkFrom(forms.Form):
username=fields.CharField(max_length=12,min_length=4,required=True,label='用户名',
error_messages={
'required':'用户名不能为空',
'max_length':'长度最多12位',
'min_length':'长度最少4位',
})
password=fields.CharField(max_length=16,min_length=8,required=True,label='密码',
error_messages={
'required': '密码不能为空',
'max_length': '长度最多16位',
'min_length': '长度最少8位',
})
email=fields.EmailField(required=True,label='邮箱',
error_messages={
'required': '邮箱不能为空',
'invalid': '请输入正确的邮箱',
})
#views.py>>>
def user(request):
user_list=User.objects.all()
return render(request,'user.html',locals())
def add(request):
if request.method == 'GET':
obj = checkFrom()
return render(request, 'add.html', locals())
else:
username = request.POST.get('username')
password = request.POST.get('password')
email = request.POST.get('email')
obj=checkFrom(request.POST)
if obj.is_valid():
User.objects.create(**obj.cleaned_data)
return redirect('/user/')
else:
obj = checkFrom(request.POST)
return render(request, 'add.html', locals())
def edit(request):
if request.method=='GET':
id = request.GET.get('id')
userById = User.objects.get(id=id)
print(userById)
obj=checkFrom({'username':userById.username,
'password':userById.password,
'email':userById.email})
return render(request,'edit.html',locals())
else:
obj=checkFrom(request.POST)
username = request.POST.get('username')
if obj.is_valid():
User.objects.filter(username=username).update(**obj.cleaned_data)
return redirect('/user/')
else:
return render(request,'edit.html',locals())
#html页面>>>
#user.html:
<h2>用户列表</h2><hr>
<ul>
{% for user in user_list %}
<li>{{ user.username }}---{{ user.email }}
<a href="/edit/?id={{ user.id }}">修改</a></li>
{% endfor %}
</ul>
<a href="/add/">添加</a>
#add.html:
<form action="/add/" method="post" >
{% csrf_token %}
{# <p>{{ obj.username.label }}{{ obj.username }}{{ obj.errors.username.0 }}</p>#}
{# <p>{{ obj.password.label }}{{ obj.password }}{{ obj.errors.password.0 }}</p>#}
{# <p>{{ obj.email.label }}{{ obj.email }}{{ obj.errors.email.0 }}</p>#}
{{ obj.as_p }}
<input type="submit" value="提交">
#edit.html:
<form action="/edit/" method="post" novalidate>
{% csrf_token %}
{# <p>{{ obj.username.label }}{{ obj.username }}{{ obj.errors.username.0 }}</p>#}
{# <p>{{ obj.password.label }}{{ obj.password }}{{ obj.errors.password.0 }}</p>#}
{# <p>{{ obj.email.label }}{{ obj.email }}{{ obj.errors.email.0 }}</p>#}
{{ obj.as_p }}
<input type="submit" value="提交">
</form>
ajax提交:
#views.py
def f1(request):
if request.method=='GET':
obj=checkFrom()
return render(request,'f1.html',locals())
else:
obj = checkFrom(request.POST)
ret={'msg':False}
if checkFrom(request.POST).is_valid():
ret['msg']=True
return HttpResponse(json.dumps(ret))
else:
from django.forms.utils import ErrorDict
ret['msg']=obj.errors
return HttpResponse(json.dumps(ret))
#html页面
<form id="form" action="/f1/" method="post" novalidate>
{{ obj.as_p }}
<input type="button" value="ajax提交" id="btn"><br>
</form>
<script>
$(function () {
$('#btn').click(function () {
$.ajax({
url:'/f1/',
type:'POST',
data:$('#form').serialize(),
datatype:"JSON",
success:function (arg) {
if(arg.msg==true){
window.location.href='http://www.baidu.com'
}
console.log(arg);
}
})
})
})
</script>
与表单提交区别:手动设置页面跳转;错误信息手动展示
Form字段和插件:
创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML。
Django内置字段:
Field
required=True, 是否允许为空
label=None, 用于生成Label标签或显示内容
initial=None, 初始值
help_text='', 帮助信息(在标签旁边显示)
error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'}
show_hidden_initial=False, 是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
validators=[], 自定义验证规则
localize=False, 是否支持本地化
disabled=False, 是否可以编辑
label_suffix=':' Label内容后缀
CharField(Field)
max_length=None, 最大长度
min_length=None, 最小长度
strip=True 是否移除用户输入空白
IntegerField(Field)
max_value=None, 最大值
min_value=None, 最小值
FloatField(IntegerField)
...
DecimalField(IntegerField)
max_value=None, 最大值
min_value=None, 最小值
max_digits=None, 总长度
decimal_places=None, 小数位长度
BaseTemporalField(Field)
input_formats=None 时间格式化
DateField(BaseTemporalField) 格式:2015-09-01
TimeField(BaseTemporalField) 格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
DurationField(Field) 时间间隔:%d %H:%M:%S.%f
...
RegexField(CharField)
regex, 自定制正则表达式
max_length=None, 最大长度
min_length=None, 最小长度
error_message=None, 忽略,错误信息使用 error_messages={'invalid': '...'}
EmailField(CharField)
...
FileField(Field)
allow_empty_file=False 是否允许空文件
ImageField(FileField)
...
注:需要PIL模块,pip3 install Pillow
#以上两个字典使用时,需要注意两点:
- form表单中 enctype="multipart/form-data"
- view函数中 obj = MyForm(request.POST, request.FILES)
URLField(Field)
...
BooleanField(Field)
...
NullBooleanField(BooleanField)
...
ChoiceField(Field)
...
choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),)
required=True, 是否必填
widget=None, 插件,默认select插件
label=None, Label内容
initial=None, 初始值
help_text='', 帮助提示
ModelChoiceField(ChoiceField)
... django.forms.models.ModelChoiceField
queryset, # 查询数据库中的数据
empty_label="---------", # 默认空显示内容
to_field_name=None, # HTML中value的值对应的字段
limit_choices_to=None # ModelForm中对queryset二次筛选
ModelMultipleChoiceField(ModelChoiceField)
... django.forms.models.ModelMultipleChoiceField
TypedChoiceField(ChoiceField)
coerce = lambda val: val 对选中的值进行一次转换
empty_value= '' 空值的默认值
MultipleChoiceField(ChoiceField)
...
TypedMultipleChoiceField(MultipleChoiceField)
coerce = lambda val: val 对选中的每一个值进行一次转换
empty_value= '' 空值的默认值
ComboField(Field)
fields=() 使用多个验证,如下:即验证最大长度20,又验证邮箱格式
fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
MultiValueField(Field)
PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
SplitDateTimeField(MultiValueField)
input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
FilePathField(ChoiceField) 文件选项,目录下文件显示在页面中
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹
required=True,
widget=None,
label=None,
initial=None,
help_text=''
GenericIPAddressField
protocol='both', both,ipv4,ipv6支持的IP格式
unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
SlugField(CharField) 数字,字母,下划线,减号(连字符)
...
UUIDField(CharField) uuid类型
...
常用选择插件:
# 单radio,值为字符串
user = fields.CharField(
initial=2,
widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
)
# 单radio,值为字符串
user = fields.ChoiceField(
choices=((1, '上海'), (2, '北京'),),
initial=2,
widget=widgets.RadioSelect
)
# 单select,值为字符串
user = fields.CharField(
initial=2,
widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
)
# 单select,值为字符串
user = fields.ChoiceField(
choices=((1, '上海'), (2, '北京'),),
initial=2,
widget=widgets.Select
)
# 多选select,值为列表
user = fields.MultipleChoiceField(
choices=((1,'上海'),(2,'北京'),),
initial=[1,],
widget=widgets.SelectMultiple
)
# 单checkbox
user = fields.CharField(
widget=widgets.CheckboxInput()
)
# 多选checkbox,值为列表
user = fields.MultipleChoiceField(
initial=[2, ],
choices=((1, '上海'), (2, '北京'),),
widget=widgets.CheckboxSelectMultiple
)
动态绑定数据:
#方式一:重构构造方法(推荐)
class ClassesForm(Form):
name = fields.CharField()
user_id = fields.IntegerFiled(
widget=widgets.Select()
)
#重写init方法,时时更新
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
self.fields["user_id"].widget.choices =User.objects.values_list('id', "username")
#方式二:ModelChoiceField(不推荐)
from django.forms.models import ModelChoiceField
class ClassesForm(Form):
name = fields.CharField()
user_id = ModelChoiceField(
queryset=User.objects.all(),
to_field_name='id'
)
#models.py
class User(models.Model):
name=models.charField()
user_id=models.IntegerField()
#显示name而不是object:__str__()返回name
def __str__(self):
return self.name
校验数据库字段:
不需要在视图函数中编写校验代码。
#自定制Form类中
class CheckForm(forms.Form):
username=fields.CharField()
userid=fields.IntField(
widget=widgets.Select(choices=[(0,'alex'),(1,'egon')])
)
#定义 clean_'字段' 方法(单字段)
def clean_username(self):
v=self.cleaned_data['username']
if User.objects.filter(username=v).count()>0:
raise ValidationError('用户名已存在')
return v
#定义clean方法(整体)
def clean(self):
value_dict=self.cleaned_data
v1=value_dict.get('username')
v2=value_dict.get('userid')
if xxx:
raise ValidationError('整体错误')
return cleaned_data
序列化
关于Django中的序列化主要应用在将数据库中检索的数据返回给客户端用户,特别的Ajax请求一般返回的为Json格式。
原始方式:
#views.py
def getuser(request):
user_list = User.objects.all()
return render(request, 'getuser.html', locals())
#xu.html
<h1>用户列表</h1><hr>
<table id="tb" >
</table>
<script>
$(function () {
initData();
});
function initData() {
$.ajax({
url:'/get_user/',
type:'GET',
success:function (ret) {
$('#tb').append(ret);
}
})
}
#getuser.html
{% for user in user_list %}
<tr>
<td>{{ user.id }}</td>
<td>{{ user.username }} </td>
<td>{{ user.age }} </td>
</tr>
{% endfor %}
serializers :[object]
#views.py
from django.core import serializers
def getuser(request):
ret={'status':True,'data':None}
try:
user_list = User.objects.all()
ret['data'] = serializers.serialize('json', user_list)
except Exception as e:
ret['status']=False
return HttpResponse(json.dumps(ret))
#xu.html
<h1>用户列表</h1><hr>
<table id="tb" >
</table>
<script>
$(function () {
initData();
});
function initData() {
$.ajax({
url:'/get_user/',
type:'GET',
dataType:'JSON',
success:function (ret) {
if(ret.status){
var val=JSON.parse(ret.data);
for (let i = 0; i <val.length; i++) {
$('#tb').append(val[i].pk+'\t');
$('#tb').append(val[i].fields.username+'\t');
$('#tb').append(val[i].fields.age+'\t');
$('#tb').append('<br>');
}
}
}
})
}
json.dumps :[tuple]
#views.py
def getuser(request):
ret={'status':True,'data':None}
try:
user_list = User.objects.all().values('id','username','age')
ret['data']=list(user_list)
except Exception as e:
ret['status']=False
return HttpResponse(json.dumps(ret))
#xu.html
<h1>用户列表</h1><hr>
<table id="tb" >
</table>
<script>
$(function () {
initData();
});
function initData() {
$.ajax({
url:'/get_user/',
type:'GET',
dataType:'JSON',
success:function (ret) {
if(ret.status){
for (let i = 0; i <ret.data.length; i++) {
$('#tb').append(ret.data[i].id);
$('#tb').append(ret.data[i].username);
$('#tb').append(ret.data[i].age);
$('#tb').append('<br>');
};
}
}
})
}
model进阶
参考博客:yuan先生
Ajax
1、发送请求
①基于jquery
#GET
function submit1() {
$.ajax({
url:'/submit1/',
type:'GET',
data:{'msg':'123'},
success:function (arg) {
}
})
}
#POST
function submit1() {
$.ajax({
url:'/submit1/',
type:'POST',
data:{'msg':'123'},
success:function (arg) {
}
})
}
②基于XMLHttpRequest
#GET
function submit2() {
var xhr=new XMLHttpRequest();
xhr.onreadystatechange=function(){
if (xhr.readyState==4){
console.log(xhr.responseText)
}
};
xhr.open('GET','/submit?msg=234');
xhr.send(null);
}
#POST
function submit2() {
var xhr=new XMLHttpRequest();
xhr.onreadystatechange=function(){
if (xhr.readyState==4){
console.log(xhr.responseText)
}
};
xhr.open('POST','/submit/');
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded','charset-UTF-8')
xhr.send('msg=345');
}
③Iframe伪造ajax请求
<form id="fm" action="/submit/" method="post" target="iframe">
<input type="text" >
<a onclick="submit3()">提交</a>
</form>
<iframe id="iframe" name="iframe"></iframe>
function submit3() {
document.getElementById('iframe').onload=reloadiframe;
document.getElementById('fm').submit();
}
#伪造回调函数
function reloadiframe() {
var content=this.contentWindow.document.body.innerHTML;
var obj=JSON.parse(content);
if (obj.status){
alert(obj.msg)
}
}
2、上传文件
①基于jquery
#html页面
<input type="file" id="img"><br>
<a onclick="upload1()">上传</a><br>
function upload1() {
var data=new FormData();
data.append('img',document.getElementById('img').files[0]);
$.ajax({
url:'/upload/',
type:'POST',
data:data,
processData:false,
contentType:false,
success:function (arg) {
}
})
}
#views.py
def upload(request):
img = request.FILES.get('img')
with open('upload/' + img.name, 'wb') as f:
for line in img.chunks():
f.write(line)
return HttpResponse('up...')
②基于XMLHttpRequest
#html页面
function upload2() {
var xhr=new XMLHttpRequest();
var data=new FormData();
data.append('img',document.getElementById('img').files[0]);
xhr.onreadystatechange=function(){
if (xhr.readyState==4){
console.log(xhr.responseText)
}
};
xhr.open('POST','/upload/');
xhr.send(data);
}
③基于iframe+form表单
#html页面
<iframe style="display: none" id="iframe" name="iframe"></iframe>
<form id="fm" action="/upload/" method="post" enctype="multipart/form-data" target="iframe">
<input type="file" id="img" name="img"><br>
<a onclick="upload3()">上传</a><br>
</form>
function upload3() {
document.getElementById('iframe').onload=reloadiframe;
document.getElementById('fm').submit();
}
function reloadiframe() {
var content=this.contentWindow.document.body.innerHTML;
var obj=JSON.parse(content);
if (obj.status){
alert(obj.msg)
}
}
#views.py
def upload(request):
img = request.FILES.get('img')
print(request.FILES)
print(request.POST)
with open('upload/' + img.name, 'wb') as f:
for line in img.chunks():
f.write(line)
data = {'status': True, 'msg': 'ok'}
return HttpResponse(json.dumps(data))
优化:上传即提交,上传预览
#views.py
def upload(request):
img = request.FILES.get('img')
with open('app01/static/' + img.name, 'wb') as f:
for line in img.chunks():
f.write(line)
data = {'status': True, 'url': os.path.join('/static/',img.name)}
return HttpResponse(json.dumps(data))
#html页面
<iframe style="display: none" id="iframe" name="iframe"></iframe>
<form id="fm" action="/upload/" method="post" enctype="multipart/form-data" target="iframe">
<input type="file" id="img" name="img" onchange="upload()"><br>
</form>
<div id="preview"></div>
function upload() {
document.getElementById('iframe').onload=reloadiframe;
document.getElementById('fm').submit();
}
function reloadiframe() {
var content=this.contentWindow.document.body.innerHTML;
var obj=JSON.parse(content);
if (obj.status){
console.log(obj.url);
var preview=document.createElement('img');
preview.src=obj.url;
$('#preview').empty().append(preview);
}
}
3、JSONP跨域请求
浏览器同源策略:XMLHttpRequest只能向本地发送数据;jsonp巧妙解决
jquery集成的jsonp:
<input type="button" value="发送跨域请求" onclick="jsonp()">
function jsonp() {
$.ajax({
url:'[路径]',
type:'GET',
DATA: 'jsonp',
})
}
function list(arg) {
$('#content').html(arg)
}
本质上:
function jsonp() {
var req=document.createElement('script');
req.src='[路径]',
document.head.appendChild(req);
document.head.removeChild(req);
}
function list(arg) {
$('#content').html(arg)
}
实例:跨域请求江西卫视节目表
<input type="button" value="发送跨域请求" onclick="jsonp()">
<div id="list"></div>
function jsonp() {
$.ajax({
url: 'http://www.jxntv.cn/data/jmd-jxtv2.html',
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'list',
})
}
function list(arg) {
{#console.log(arg);#}
{#console.log(arg.data[0].list[0].time);#}
for (let i = 0; i < arg.data.length ; i++) {
$('#list').append('<p>'+arg.data[i].week+'</p>');
$('#list').append('<hr>');
for (let j = 0; j <arg.data[i].list.length ; j++) {
$('#list').append(arg.data[i].list[j].time+' '+arg.data[i].list[j].name+' '+arg.data[i].list[j].link);
$('#list').append('<br>');
}
}
}
实现效果:
另:CORS跨站资源共享(了解)
#被请求端的views.py
def list(request):
data={'name':'alex','age':22……}
obj=HttpResponse(json.dumps(data))
#设置响应头为*,则绕过了浏览器同源策略
obj['Access-Control-Allow-Origin']='*'
return obj
——————————————以上——————————————