1、常见的请求方式
默认页面请求都是get请求,常用的请求方式get和post:
1、get:默认是get请求,请求数据以明文形式放在路由上,get的格式是以?开头,键等于值的形式,以&来分割键值对,通常用于向服务器获取资源。
https://www.baidu.com/s?wd=张三&rsv_spt=1
2、post:请求数据隐藏发送,安全系数更高。通常用于向服务器提交资源。
2、请求对象
视图函数中request是传递到视图的请求对象,包含了本次请求所有的信息。
request对象的类型是django.http.HttpRequest,常用属性如表所示:
属性 | 描述 |
---|---|
request.GET | 获取get请求数据的方法 |
request.POST | 获取post请求数据的方法 |
request.FILES | 获取文件上传请求数据的方法 |
request.method | 获取请求的方法 |
request.META | 请求的详细参数 |
request.META.OS | 请求端系统 |
request.META.HTTP_USER_AGENT | 用户请求头,返回请求浏览器版本 |
request.META.HTTP_HOST | 请求的主机 |
request.META.HTTP_REFERER | 请求的来源 |
3、表单请求
3.1 get请求
在表单中默认使get请求提交表单
属性 | 说明 |
---|---|
action | 提交的地址,默认是当前路由。 |
method | 提交的方法,默认是get |
name | 用来做传参的标识 |
submit | 会自动提交当前表单的数据 |
获取get请求的表单数据
# 获取表单中name的值为username的数据
username = request.GET.get("username")
3.2 post请求
表单使用post请求提交时需要进行CSRF验证,在Django的1.4版本之前,CSRF默认关闭,需要在settings当中手动开启,在1.4之后,默认开启。
在Django的任何post请求,都会在请求之初,给用户下发一下串用来校验身份的编码,并且每次请求不一样。如果不加csrf校验,则会发生错误。
使用Django的csrf校验
视图必须以render函数返回页面,render函数的功能和render_to_response功能类似,但是会返回请求到前端,这样,前端就可以调用csrf_token了,前端必须在form表单当第一行加入csrf_token标签。使用如下
def login(request):
"""登录"""
if request.method == "POST":
pass
return render(request, "login.html", locals())
<form class="user" method="post">
{% csrf_token %}
<div class="form-group">
<input type="text" class="form-control" name="username" id="username" placeholder="用户名">
</div>
<div class="form-group">
<input type="password" class="form-control" name="password" id="password" placeholder="密码">
</div>
<button type="submit" class="btn btn-primary btn-user btn-block">
登陆
</button>
<hr>
</form>
3.3 文件上传
3.3.1 settings配置
文件的上传需要设置上传文件的位置,在settings中修改
文件的位置还可以在模型中指定,例如upload_to=“store/img”,在static文件下创建store/img,从而实现文件存储在/static/store/img目录下。开发者也不用考虑文件名重复的问题,框架会自动修改有相同名字的文件。
picture = models.ImageField(null=True, upload_to="store/img")
3.3.2 文件上传
form表单设置
需要设置method=“post” enctype=“multipart/form-data”, 如下
<form method="post" class="form" enctype="multipart/form-data" action="/goods/">
{% csrf_token %}
<div class="form-group">
<label class="">商品名称</label>
<input class="form-control" type="text" name="name">
</div>
<div class="form-group">
<label class="">商品图片</label>
<input class="form-control" type="file" name="picture">
</div>
<button class="btn btn-primary fa-pull-right" type="submit">提交商品</button>
</form>
后端处理
普通文字:request.POST.get
文件字段:request.FILES.get
def goods(request):
if request.method == "POST":
name = request.POST.get("name")
picture = request.FILES.get("picture")
goods = Goods()
goods.name = name
goods.picture = picture
goods.save()
return render(request, "goods.html", locals())
3.3.3 新增
goods.save()
文件会自动保存到MEDIA_ROOT设置的路径中,数据库中的名字默认是文件的名字,若设置了upload_to属性,数据库中存储的数据是upload_to的字段加上文件名。
4、表单类
4.1 表单类介绍
用户表单是Web端的一项基本功能,大而全的Django框架中自然带有现成的基础Form对象。
Form表单的功能:
1、自动生成HTML表单元素
2、检查表单数据的合法性(后端验证)
3、如果验证错误,重新显示表单(数据不会重置)
4、数据类型转换(字符类型的数据转换成相应的Python类型)
Django表单类,带有前后端验证的。
1、前端验证:
Django表单类对象渲染到模板后,会变成HTML附带属性标签,这些是属性一般是HTML5的属性,可以交互。
2、后端验证
通过将request的参数传给Form,得到一个Form对象,调用这个对象的is_valid方法,如果返回True表示参数通过验证,否则不通过验证。
4.2 表单类的使用
创建表单类
# form.py 表单类文件
from django import forms
class RegisterForm(forms.Form):
username = forms.CharField(
required=True, # 是否必须填写
min_length=2, # 最小长度
max_length=10, # 最大长度
error_messages={ # 用字典来存储每个验证的错误信息
"required": "用户名必填",
"min_length": "用户名至少是2位",
"max_length": "用户名不能超过10位"
}
)
password = forms.CharField(
required=True,
error_messages={
"required": "密码必填"
}
)
视图,处理表单校验的结果及业务逻辑
# views.py
def register(request):
"""注册"""
if request.method == "POST":
# 获取参数,放入表单校验
register_form = RegisterForm(request.POST)
if register_form.is_valid(): # 判断表单是否校验成功
# 获取表单提交验证后的数据
username = register_form.data.get("username")
password = register_form.data.get("password")
# 查询是否有该用户
seller = Seller.objects.filter(name=username).first()
if not seller:
# 注册用户
seller = Seller()
seller.name = name
seller.password = encrypt_password(password)
seller.save()
return redirect("/login/")
return render(request, "register.html", locals())
前端渲染
注:可以用断点调试的方法查看一个对象的数据,例如查看register_form的所有属性,根据需求在前端渲染需要的数据。
<!--register.html-->
<form class="user" method="post"> <!-- 不写action默认提交到原路由 -->
{% csrf_token %}
<div class="form-group row">
<div class="col-sm-12 mb-3 mb-sm-0">
<input type="text" name="username" class="form-control form-control-user" id="username" placeholder="用户名" value="{{ register_form.data.username }}">
</div>
<p class="container-fluid" style="color: red; margin-top: 5px;">
{{ register_form.errors.username.0 }} <!-- 调用表单校验后register_form对象的username的错误属性返回前段显示 -->
</p>
</div>
<div class="form-group">
<input type="password" name="password" class="form-control form-control-user" id="password" placeholder="密码">
<p class="container-fluid" style="color: red; margin-top: 5px;">
{{ register_form.errors.username.0 }}
</p>
</div>
<button type="submit" class="btn btn-primary btn-user btn-block">
注册用户
</button>
</form>
5、表单校验
5.1 常用验证器
在验证某个字段的时候,可以传递一个validators参数用来指定验证器,进一步对数据进行过滤。
常用的验证器
验证器 | 描述 |
---|---|
MaxValueValidator | 验证最大值。 |
MinValueValidator | 验证最小值 |
MinLengthValidator | 验证最小长度 |
MaxLengthValidator | 验证最大长度 |
EmailValidator | 验证是否是邮箱格式 |
URLValidator | 验证是否是URL格式 |
RegexValidator | 正则表达式的验证 |
案例:验证用户名是2-10位字母数字下划线组成的。
# form.py
from django.core.validators import RegexValidator
class RegisterForm(forms.Form):
username = forms.CharField(
required=True,
validators=[
RegexValidator(
r"^[a-zA-Z0-9_]{2,10}$", # 正则表达式
"用户名只能是2-10位字母数字下划线组成" # 验证失败提示信息
)
],
error_messages={
"required": "用户名必填"
}
)
password = forms.CharField(
required=True,
error_messages={
"required": "密码必填"
}
)
视图,和前端渲染同4.2
结果如下:
5.2 自定义验证
Django表单类也提供了对特定字段的自定义验证,在Form类中定义实例方法,如果验证失败,抛出ValidationError异常,否则正常返回值。
案例: 验证用户名是否包含敏感词
class Sensitive_Word():
"""类式自定义"""
def __call__(self, value):
datas = ["admin", "nb", "sb"]
for data in datas:
if value.find(data) != -1:
raise ValidationError("用户名不能含有敏感词汇")
def sensitive_word(value):
"""函数式自定义"""
datas = ["admin", "nb", "sb"]
for data in datas:
if value.find(data) != -1:
raise ValidationError("用户名不能含有敏感词汇")
class RegisterForm(forms.Form):
username = forms.CharField(
required=True,
validators=[
RegexValidator(
r"^[a-zA-Z0-9_]{2,10}$",
"用户名只能是2-10位字母数字下划线组成"
),
# Sensitive_Word(), # 自定义类校验器的调用
sensitive_word # 自定义函数校验器的调用
],
error_messages={
"required": "用户名必填"
}
)
password = forms.CharField(
required=True,
error_messages={
"required": "密码必填"
}
)
视图,和前端渲染同4.2
6、会话
Django的时间默认是使用UTC,与我们本地相差了8个小时。因cookie和session具有时效性,需要设置成我们当前的时区。
Django的response获取的方式有:
response= HttpResponse(“xx”)
response= render(request,”xx.html”)
response= redirect(“/index”)
6.1 cookie
1、创建cookie
response.set_cookie(键,值,有效期) # 有效期单位是秒
2、删除cookie
response.delete_cookie(键)
3、获取cookie
request.cookie.get(键)
cookie可以用来存储一些不重要的数据,比如用户的账号和昵称等,把这些信息回显到前端,实现用户下一次登录时不用再输入账号。(如“记住我”这样的功能)
6.2 session
Django中默认配置把session数据存储到了数据库中。
session的操作
1、创建session
request.session[键] = 值 # 有效期默认是2周,可以修改
request.session.set_expiry(时间) #单位是秒
2、获取session
request.session.get(键)
3、删除session
del request.session[键] # 删除一个键值对
request.session.clear() # 删除所有键值对
服务器获取不到session,验证失败的情况:
1、客户端没有发来sessionid
2、客户端发来sessionid,但是从数据库中找不到
3、客户端发来sessionid,从数据库中找到了,但是过期了
上述三种情况都是导致session的验证失败
案例:创建检测用户的登录状态的装饰器,实现在session验证通过的情况下才能访问相应页面
from functools import wraps
def login_check(fun):
@wraps(fun)
def inner(*args, **kwargs):
if not args[0].session.get("logined"):
# 未登录
return redirect("/login")
else:
return fun(*args, **kwargs)
return inner
@login_check
def index(request):
return render(request, "index.html", locals())