一、Ajax介绍
-异步:跟同步是对应的
-javascript:通过javascript来操作,发送请求 ,到服务端
-xml:数据交互使用xml,现在主流使用json格式
-xml:可阅读性比较高,解析复杂,占的空间大
<name>wu</name>
<age>19</age>
-json:可阅读性比较高,解析简单,占的空间小
{"name":"wu","age":19}
-浏览器页面局部刷新(js的dom操作)
-通过js发送http的请求(go,java,php,requset)
同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
1 原生js写ajax请求(写起来很复杂,而且需要考虑浏览器版本)
2 jquery帮咱们封装好了一个方法 ajax,我们直接调用jquery的方法,就可以发送ajax的请求
3 后期,前后端分离了,还可以继续使用jquery的ajax, axios更主流一些
4 现在我们学的jquery的ajax方法的使用
5 需求:通过Ajax,实现前端输入两个数字,服务器做加法,返回到前端页面
6 模板
$.ajax({
url: '',
method: 'post',
data:{'a':$("#first").val() ,'b':$("#second").val() },
success:function (data) {
//成功触发
},
error:function (error) {
//失败,触发
}
})
后端代码:app01.views
def add(request):
if request.method == 'POST':
a = int(request.POST.get('a'))
b = int(request.POST.get('b'))
print(a, b)
return HttpResponse(a + b)
默认情况下ajax会把{'a':$("#first").val() ,'b':$("#second").val() }数据转成
预处理数据 a=20&b=30,放到body体中
编码默认用urlencoded
二、Ajax上传文件
1 http请求,body体中放文件内容,ajax本质就是发送http请求,所以它可以上传文件
2 两种上传文件的方式,form表单,ajax
3 固定模板
var formdata=new FormData()
form.append('username', $('#username').val())
formdata.append('myfile',$("#id_file")[0].files[0])
$.ajax({
url:'/uploadfile/',
method: 'post',
//上传文件必须写这两句话
processData:false,
contentType:false,
data:formdata,
success:function (data) {
console.log(data)
}
})
三、Ajax提交json格式
$.ajax({
url:'/uploajson/', //写全,是什么样就写什么样,无法重定向
method:'post',
contentType: 'application/json',
//data要是json格式字符串
//data:'{"name":"","password":""}',
//把字典转成json格式字符串
//JSON.stringify(dic)
//把json格式字符串转成对象
//JSON.parse(data)
data:JSON.stringify({’name‘:$("#id_name1").val(),’password‘:$("#id_password1").val()}),
success:function (data) {
//返回字符串类型,需要转成js的对象,字典
//1 如果:django 返回的是HttpResponse,data是json格式字符串,需要自行转成字典
//2 如果:django 返回的是JsonResponse,data是就是字典
//ajax这个方法做的是,如果响应数据是json格式,自动反序列化
console.log(typeof data)
var res=JSON.parse(data)
console.log(typeof res)
console.log(res.status)
console.log(res.msg)
}
})
四、django内置序列化器
1 把对象转成json格式,json.dumps实现不了,
2 django内置了一个东西,可以把对象转成json格式
from django.core import serializers
book_list = Book.objects.all()
ret = serializers.serialize("json", book_list)
ll=[]
for book in book_list:
ll.append({'name':book.name,'price':book.pirce})
import json
ret=json.dumps(ll)
return HttpResponse(ret)
五、Django结合sweetalter
<script>
$('.del').on('click',function () {
let currentBtn = $(this);
swal({
title: "你确定要删吗?",
text: "你可要考虑清除哦,可能需要拎包跑路哦!",
type: "warning",
showCancelButton: true,
confirmButtonClass: "btn-danger",
confirmButtonText: "是的,老子就要删!",
cancelButtonText: "算了,算了!",
closeOnConfirm: false,
closeOnCancel: false,
showLoaderOnConfirm: true
},
function(isConfirm) {
if (isConfirm) {
$.ajax({
{#url:'/delete/user/' + currentBtn.attr('delete_id'),
url:'/delete/user/',
type:'post',
data:{'delete_id':currentBtn.attr('delete_id')},
success:function (args) {
if(args.code === 1000){
swal("删了!", args.msg, "success");
{#window.location.reload()#}
currentBtn.parent().parent().remove()
}else{
swal('完了','出现了位置的错误','info')
}
}
})
} else {
swal("怂逼", "不要说我认识你", "error");
}
});
})
</script>
六、批量插入数据和choices参数
rom app01 import models
def index(request):
for i in range(100):
models.Book.objects.create(name='书籍%s'%i,price=i+1)
ll = []
for i in range(100):
book = models.Book(name='书籍%s' % i, price=i + 1)
ll.append(book)
models.Book.objects.bulk_create(ll, 10)
return render(request, 'index.html')
"""
在设计表的时候 针对可以列举完全的可能性字段
一般都是用choices参数
"""
gender_choices = (
(1,'male'),
(2,'female'),
(3,'others')
)
gender = models.IntegerField(choices=gender_choices)
user_obj.gender
user_obj.get_gender_display()
"""有对应关系就拿对应关系,没有则还是数据本身不会报错"""
七、多对多表关系的三种建立方式
class Book(models.Model):
name = models.CharField(max_length=32)
authors = models.ManyToManyField(to='Author')
class Author(models.Model):
name = models.CharField(max_length=32)
"""
优点:代码不需要你写 非常的方便 还支持orm提供操作第三张关系表的方法...
不足之处:第三张关系表的扩展性极差(没有办法额外添加字段...)
"""
class Book(models.Model):
name = models.CharField(max_length=32)
class Author(models.Model):
name = models.CharField(max_length=32)
class Book2Author(models.Model):
book_id = models.ForeignKey(to='Book')
author_id = models.ForeignKey(to='Author')
'''
优点:第三张表完全取决于你自己进行额外的扩展
不足之处:需要写的代码较多,不能够再使用orm提供的简单的方法
不建议你用该方式
'''
class Book(models.Model):
name = models.CharField(max_length=32)
authors = models.ManyToManyField(to='Author',
through='Book2Author',
through_fields=('book','author')
)
class Author(models.Model):
name = models.CharField(max_length=32)
class Book2Author(models.Model):
book = models.ForeignKey(to='Book')
author = models.ForeignKey(to='Author')
"""
through_fields字段先后顺序
判断的本质:
通过第三张表查询对应的表 需要用到哪个字段就把哪个字段放前面
你也可以简化判断
当前表是谁 就把对应的关联字段放前面
半自动:可以使用orm的正反向查询 但是没法使用add,set,remove,clear这四个方法
"""
八、自定义分页器
class Pagination(object):
def __init__(self, current_page, all_count, per_page_num=2, pager_count=11):
"""
封装分页相关数据
:param current_page: 当前页
:param all_count: 数据库中的数据总条数
:param per_page_num: 每页显示的数据条数
:param pager_count: 最多显示的页码个数
"""
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):
if self.all_pager <= self.pager_count:
pager_start = 1
pager_end = self.all_pager + 1
else:
if self.current_page <= self.pager_count_half:
pager_start = 1
pager_end = self.pager_count + 1
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 = []
page_html_list.append('''
<nav aria-label='Page navigation>'
<ul class='pagination'>
''')
first_page = '<li><a href="?page=%s">首页</a></li>' % (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="?page=%s">上一页</a></li>' % (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="?page=%s">%s</a></li>' % (i, i,)
else:
temp = '<li><a href="?page=%s">%s</a></li>' % (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="?page=%s">下一页</a></li>' % (self.current_page + 1,)
page_html_list.append(next_page)
last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
page_html_list.append(last_page)
page_html_list.append('''
</nav>
</ul>
''')
return ''.join(page_html_list)
后端
def get_book(request):
book_list = models.Book.objects.all()
current_page = request.GET.get("page",1)
all_count = book_list.count()
page_obj = Pagination(current_page=current_page,all_count=all_count,per_page_num=10)
page_queryset = book_list[page_obj.start:page_obj.end]
return render(request,'booklist.html',locals())
前端
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
{% for book in page_queryset %}
<p>{{ book.title }}</p>
{% endfor %}
{{ page_obj.page_html|safe }}
</div>
</div>
</div>
九、forms组件介绍和校验字段功能
1 注册功能,登录功能,前端需要校验(字段长度,邮箱是否合法。。。)
2 前端校验可以没有,后端校验是必须的,使用传统方式 if判断写的很多
3 借助于forms组件,可以快速实现字段的校验
from django.forms import Form
4 禁止浏览器自动检测数据,在form中填写novalidate
1、在app目录下创建一个utils的py文件
from django import forms
class Myform(forms.Form):
name = forms.CharField(max_length=10, min_length=3, widget=forms.widgets.TextInput(attrs={'class': 'form-control'}),
error_messages={'max_length': '不能多余10位',
'min_length': '不能小于3位',
'required': '必须填写'
},
label='用户名')
password = forms.CharField(max_length=10, min_length=3,
widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}),
error_messages={'max_length': '不能多余10位',
'min_length': '不能小于3位',
'required': '必须填写'
},
label='密码')
re_password = forms.CharField(max_length=10, min_length=3,
widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}),
error_messages={'max_length': '不能多余10位',
'min_length': '不能小于3位',
'required': '必须填写'
},
label='确认密码')
email = forms.EmailField(widget=forms.widgets.EmailInput(attrs={'class': 'form-control'}),
error_messages={'invalid': '邮箱格式不正确',
'required': '必须填写'
},
label='邮箱')
date = forms.DateField(required=False, widget=forms.widgets.DateInput(attrs={'class': 'form-control'}),
label='出生日期', error_messages={'invalid': '邮箱格式不正确',
'required': '必须填写'})
gender = forms.ChoiceField(choices=((1, '男'), (2, '女'), (3, '保密')), initial=3, widget=forms.widgets.RadioSelect(),
label='性别',
)
text = forms.CharField(
widget=forms.widgets.Textarea(attrs={'class': 'form-control', 'cols': 10, 'rows': 10, 'style': 'resize: none'}),
label='个人简介', error_messages={'required': '必须填写'}, )
def register(request):
data={'name':'wx','email':'33333@qq.com','age':900}
form=myforms.MyForm(data)
if form.is_valid():
print('校验通过')
print(form.cleaned_data)
else:
print(form.cleaned_data)
print('校验失败')
print(form.errors)
print(type(form.errors))
from django.forms.utils import ErrorDict
print(form.errors.as_json())
print(form.errors.as_data())
return HttpResponse('ok')
def register(request):
if request.method=='GET':
form=myforms.MyForm()
return render(request,'register.html',{'form':form})
elif request.method=='POST':
form=myforms.MyForm(request.POST)
if form.is_valid():
print('校验通过,存数据库')
else:
print(form.errors.as_data())
print('校验失败,返回错误')
return HttpResponse('ok')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<hr>
<h1>手动创建模板</h1>
<form action="" method="post">
<p>用户名:<input type="text" name="name"></p>
<p>邮箱:<input type="text" name="email"></p>
<p>年龄:<input type="text" name="age"></p>
<p><input type="submit" value="提交"></p>
</form>
<hr>
<h1>半自动渲染模板1</h1>
<form action="" method="post">
<p>用户名:{{ form.name }}</p>
<p>邮箱:{{ form.email }}</p>
<p>年龄:{{ form.age }}</p>
<p><input type="submit" value="提交"></p>
</form>
<h1>半自动渲染模板2(用的最多)</h1>
<form action="" method="post">
<p>{{ form.name.label }}--{{ form.name }}</p>
<p>{{ form.email.label }}---{{ form.email }}</p>
<p>{{ form.age.label }}---{{ form.age }}</p>
<p><input type="submit" value="提交"></p>
</form>
<h1>半自动渲染模板3(用的最多)</h1>
<form action="" method="post">
{% for foo in form %}
<p>{{ foo.label }} :{{ foo }}</p>
{% endfor %}
<p><input type="submit" value="提交"></p>
</form>
<h1>全自动(了解)</h1>
<form action="" method="post">
{
{{ form.as_p }}
{
{
{
<p><input type="submit" value="提交"></p>
</form>
</body>
</html>
十、froms渲染错误信息
1 form对象.errors 字典,所有的错误信息
2 name对象.errors 当前字段的错误信息
3 校验数据只校验类中出现的字段 多传不影响 多传的字段直接忽略
4 校验数据 默认情况下 类里面所有的字段都必须传值
方式一:不保留上次输入的结果
def register(request):
if request.method =='GET':
form = myforms.MyForm()
return render(request, 'register.html',{'form':form})
else:
form = myforms.MyForm(request.POST)
if form.is_valid():
return redirect('http://www.baidu.com')
else:
return render(request, 'register.html',{'form':form})
<form action="" method="post" novalidate>
{% for foo in form %}
<div class="form-group">
<label for="">{{ foo.label }}</label>
{{ foo }}
<span class="text-danger pull-right">{{ foo.errors.0 }}</span>
</div>
{% endfor %}
<div class="text-center">
<input type="submit" value="提交" class="btn btn-danger">
</div>
</form>
方式二:保留上一次输入的参数
def index(request):
form_obj = MyForm()
if request.method == 'POST':
form_obj = MyForm(request.POST)
if form_obj.is_valid():
return HttpResponse('OK')
return render(request,'index.html',{‘form’: from_obj})
"""
1.必备的条件 get请求和post传给html页面对象变量名必须一样
2.forms组件当你的数据不合法的情况下 会保存你上次的数据 让你基于之前的结果进行修改更加的人性化
"""
十一、forms组件参数配置
from django.forms import widgets
widget=widgets.PasswordInput(attrs={'class': 'form-control'})
error_messages={'min_length': '太短了小伙子'}
class MyForm(forms.Form):
name = forms.CharField(required=False, max_length=32, min_length=3, label='用户名',
widget=widgets.TextInput(attrs={'class': 'form-control'}),
error_messages={'min_length': '太短了小伙子',
'max_length': '太长了小伙子'
})
password = forms.CharField(required=False, max_length=32, min_length=3, label='密码',
widget=widgets.PasswordInput(attrs={'class': 'form-control'}),
error_messages={'min_length': '太短了小伙子',
'max_length': '太长了小伙子'
})
re_password = forms.CharField(required=False, max_length=32, min_length=3,
label='确认密码',
widget=widgets.PasswordInput(attrs={'class':'form-control'}),
error_messages={'min_length': '太短了小伙子',
'max_length': '太长了小伙子'
})
email = forms.EmailField(label='邮箱', error_messages={'required': '小伙子,这个必填',
'invalid':'邮箱格式不正确',
},
widget=widgets.TextInput(attrs={'class': 'form-control'}))
age = forms.IntegerField(max_value=200, min_value=0, label='年龄',
error_messages={'required': '小伙子,这个必填',
'min_value': '太小了,小伙子',
'max_value': '太大了,小伙子',
},
widget=widgets.TextInput(attrs={'class': 'form-control'}))
text = forms.CharField(label='个人简介',
error_messages={'required': '小伙子,这个必填'},
widget=widgets.Textarea(attrs={'class': 'form-control'}))
date = forms.CharField(label='出生日期',
error_messages={'required': '小伙子,这个必填'},
widget=widgets.DateInput(attrs={'class': 'form-control'}))
label 字段名
error_messages 自定义报错信息
initial 默认值
required 控制字段是否必填
"""
1.字段没有样式
2.针对不同类型的input如何修改
text
password
date
radio
checkbox
...
"""
widget=forms.widgets.PasswordInput(attrs={'class':'form-control c1 c2'})
validators=[
RegexValidator(r'^[0-9]+$', '请输入数字'),
RegexValidator(r'^159[0-9]+$', '数字必须以159开头')
]
"""其他类型form的渲染"""
gender = forms.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性别",
initial=3,
widget=forms.widgets.RadioSelect()
)
hobby = forms.ChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球")),
label="爱好",
initial=3,
widget=forms.widgets.Select()
)
hobby1 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球")),
label="爱好",
initial=[1, 3],
widget=forms.widgets.SelectMultiple()
)
keep = forms.ChoiceField(
label="是否记住密码",
initial="checked",
widget=forms.widgets.CheckboxInput()
)
hobby2 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球")),
label="爱好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
)
十二、局部钩子和全局钩子(HOOK)
"""
钩子函数在forms组件中就类似于第二道关卡,能够让我们自定义校验规则
## 局部钩子的使用
# 1 在自定义的Form类中写 clean_字段名
# 2 取出字段的真正值,name=self.cleaned_data.get('name')
# 3 判断自己的规则,如果判断失败,抛出ValidationError
# 4 如果通过,return 字段名
"""
from django.forms import ValidationError
def clean_name(self):
name = self.cleaned_data.get('name')
if name.startswith('sb'):
raise ValidationError('不能以sb开头')
else:
return name
def clean(self):
password = self.cleaned_data.get('password')
re_password = self.cleaned_data.get('re_password')
if password == re_password:
return self.cleaned_data
else:
raise ValidationError('两次密码不一致')