Forms组件
校验字段功能
否则需要自己判断用户输入,ajax js可以进行校验,获取对应数据和页面提示报错
<form action="" ></form> 不写 默认匹配当前页面的ip+端口/reg http://127..0.0.1:8000/reg 当前页面请求地址
from Django import forms
class UserForm(forms.Form):
name = forms.CharField(min_length=4,label=”用户名“) # type=text
email = forms.EmailFileld(label="邮箱") # type=email
form = UserForm({"name":"yuan","email":"123@qq.com","xxx":"alex"})
form.is_valid() 返回布尔值
form = UserForm(request.POST) form表单的name属性值应该与forms组件字段一致
if form.is_valid():
print(form.cleaned_data) # {"name":"yuan","email":"123@qq.com"}
else:
print(form.cleaned_data) # {"email":"123@qq.com"}
print(form.errors) # {"name":[",,,,,,,,"]} 错误的 键:错误信息 Errordict
print(form.errors.get("name"))
print(type(form.errors.get("name"))) # Errorlist
print(form.errors.get("name")[0]) # 获取报错信息字符串
if所有字段校验成功,则form.cleaned_data: {"name":"yuan","email":"123@qq.com"} 只要有一个校验失败就是FALSE
form设定的规则必须跟传递的值对应,可以多不能少,多的字段会忽略验证,少了就会报错,不同也会报错,只有所有都校验成功才返回true,否则返回false
- 渲染标签功能
get请求的时候,返回form页面
form = UserForm()
render(request,"index.html",locals()) {"form":form}
<form action="" method="post">
{% csrf_token %}
<p>用户名 {{ form.name }}</p>
<p>密码 {{ form.pwd }}</p>
<p>确认密码 {{ form.r_pwd }}</p>
<p>邮箱 {{ form.email }}</p>
<input type="submit">
</form>
方式二
<form action="" method="post">
{% csrf_token %}
{% for field in form %}
<div>
<label for="">{{ field.label }}</label>
{{ field }}
</div>
<input type="submit">
</form>
方式三
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
// {{ form.as_d }}
<input type="submit">
</form>
- forms 渲染错误信息
{{ form.name.errors.0 }}
<p>用户名 {{ form.name }}</p>
form.errors.get("name")[0]
2点:
1、input保存输入的value值
2、验证form 第一个是没有数据的form,POST 是i传递request.POST 数据验证的form
- 参数配置
class UserForm(forms.Form):
name = forms.CharField(min_length=4,label=”用户名“,error_message={"required":"改字段不能为空"},widget=widgets.TextInput(attrs={"class":"form-control"})) # type=text
pwd = forms.CharField(min_length=4,label=”密码“,widget=widgets.TextInput()/PasswordInput(attrs={"class":"form-control"}))
email = forms.EmailFileld(label="邮箱",error_message={"required":"改字段不能为空","invalid","格式错误"},widget=widgets.TextInput(attrs={"class":"form-control"})) # type=email
局部钩子 用于判断单个字段是否满足验证后的需求,双重验证
def clean_name(self):
val = self.cleaned_data.get("name")
ret = UserInfo.objects.filter(name=val)
if not ret:
return val
else:
raise ValidationError("该用户已注册!")
全局钩子 用于判断2次密码是否输入相同 多个变量判断
源码
def clean(self):
pass
https://www.cnblogs.com/yuanchenqi/articles/9036474.html
- 临时想到:之前一直容易的混的地方
前后端双重校验 -- 用户输入
前端校验 js实现 定义规则 ,直接返回,不通过后端实现 ( JavaScript 表单验证 function ) 伪校验 减少请求,提升用户体验
======
后端校验 form实现
2种实现方式
基于form 表单 Form 实现校验 刷新 同步 1、保留 input value值 2、校验POST值
基于ajax 触发 + jQuery事件 button提交 Form 实现校验 不刷新 异步
后端不通过form,只能手动去判断每个值是否符合要求,多重判断和错误输出,最后结果就是类似form的类来实现 校验
前端通过js + 事件 直接返回,不通过后端实现
js数组 == 列表
object . 操作 == 字典
HTTP协议的无状态保存
- 无状态特点:每次请求都是一个新连接,用户登录信息没有,没有状态
要解决登录用户再次访问,无状态请求能够保存用户登录状态
cookie 具体一个浏览器针对一个服务器存值 key-value({})
建立请求之间的联系 {islogin:true}
空cookie {}
1、更换服务端会写到空的cookie
2、除了本地cookie过期,每次都会携带去请求,得到上次的状态
3、更换浏览器也会写空的cookie
响应体:
HTTPResponse 有set_cookie方法 下面都继承HTTPResponse 都有set_cookie方法
render() 调用 HTTPResponse
redirect() 调用 HTTPResponse
设置cookie返回,可以看到响应体中携带cookie信息
response = HttpResponse("登录成功")
response.set_cookie(‘is_login’,True,max_age=15,) 15秒过期 IE不支持
import datetime
date=datatime.datetime(year=2018,month=5.day=29,hour=14,minute=3) 设定固定过期时间
有效路径 /index/ 下面可以获取到cookie 其他路径下获取不到 后面讲 域名 domain=None,
response.set_cookie(‘username’,user.user,expires=date,path="/index/")
return response
def index(request):
print(request.COOKIES)
is_login = request.COOKIES.get("is_login")
if is_login:
username = request.COOKIES.get("username")
import datetime
now = datatime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
last_time = request.COOKIES.get("last_visit_time","")
response = render(request,"index.html",{"username":username,"last_time":last_time})
response.set_cookie("last_visit_time",now)
return response
else:
return redirect("/login/")
csrftoken 中间件自动添加
- 请求头中会带着cookie进行请求 ,每次浏览器请求都会在header中携带cookie请求
request.COOKIES
cookie维持会话记录的保存
删除cookie
response.delete_cookie("cookie_key",path="/",domain=name)
浏览器直接删除cookie 清除过去1小时记录
已浏览的商品
session 基于cookie开发 存在服务端
写 读
request.session["username"] = "yuan"
request.session["is_login"] = True
request.session["username"] = user.user
1、生成随机字符串
2、设置set_cookie.sessionid=随机字符串
3、session表中生成 session-key 对应随机字符串 session-data {"username":"yuan"}
request.seesion["is_login"] 会执行下面3步
1、request.COOKIE.get("sessionid") # 随机字符串
2、Django-session表中过滤记录
session-key session-data
随机字符串 {"username":"yuan","is_login":True}
obj=django-session.objects.filter(session-key=随机字符串).first()
3、obj.session-data.get("is_login")
is_login = request.session.get("is_login")
if not is_login:
pass
上次登录时间
写在login中 request.session["visit_time"] = now
写在index中,就是获取上次访问index的时间
session更新操作
if request.COOKIE.get("session"):
更新session记录
else:
生成一条session记录
session注销功能与配置参数
删除键值
del request.session["is_login"]
注销
request.session.flush()
执行三步
1、ranon_str = request.COOKIE.get("sessionid")
2、django-session.objects.filter(seesion-key=ranon_str).delete()
3、response.delete_cookie("sessionid",)
设置cookie
1、response.set_cookie(key,value)
2、request.COOKIE.get(key)
3、request.session[key] = value
1、生成随机字符串
2、设置set_cookie.sessionid=随机字符串
3、session表中生成 session-key 对应随机字符串 session-data {"username":"yuan"}
4、request.session[key]
1、request.COOKIE.get("sessionid") # 随机字符串
2、Django-session表中过滤记录
session-key session-data
随机字符串 {"username":"yuan","is_login":True}
obj=django-session.objects.filter(session-key=随机字符串).first()
3、obj.session-data.get("is_login")
5、request.session.flush()
1、ranon_str = request.COOKIE.get("sessionid")
2、django-session.objects.filter(seesion-key=ranon_str).delete()
3、response.delete_cookie("sessionid",ranon_str)
https://www.cnblogs.com/yuanchenqi/articles/9036467.html
django用户认证组件 只做登录验证操作 session操作 保存会话记录 逻辑完善 解决多次登录更新session-data产生混淆数据,会在每次登录时候清除对应session-data记录防止更新混淆 简单来说,alex登录只保留alex的键值对,egon只保留egon的键值对,相同浏览器登录携带相同随机字符串默认是更新session-data键值对, 通过认证组件,会自动清理之前session信息(django-session表中对应记录被删除),生成新登录用户的session信息
验证码、保留上次登录时间都做不了
用户认证组件
前提:用户表 Django自带的auth_user 扩展OneToOne
功能:用session记录登录验证状态
创建超级用户 Python3 manage.py createsuperuser
API:
from django.crontrib import auth
#if 验证成功返回user对象,否则返回None
user = auth.authenticate(username=user,password=pwd)
auth.login(request,user) # request.user: 当前登录对象
auth.logout(request)
from django.crontrib.auth.models import User # User==auth_user表
if not request.user.is_authenticated()
user=User.objects.create_user()
补充:
匿名用户对象:
匿名用户
class models.AnonymouseUser
django.contrib.auth.models.AnonymouseUser 类实现了django.contrib.auth.models.User 接口,但具有下面几个不同点:
id 永远为None。
username 永远为空字符串。
get_username() 永远返回空字符串。
is_staff 和 is_superuser 永远为False。
is_active 永远为 False。
groups 和 user_permissions 永远为空。
is_anonymous() 返回True 而不是False。
is_authenticated() 返回False 而不是True。
set_password()、check_password()、save() 和delete() 引发 NotImplementedError。
New in Django 1.8:
新增 AnonymousUser.get_username() 以更好地模拟 django.contrib.auth.models.User。
总结:
request.user
if not: auth.login(request,user) request.user == AnonymouseUser()
else: request.user == 登录对象
request.user 是一个全局变量
在任何视图和模板直接使用
User接口
from django.crontrib.auth.models import User
from django.crontrib import auth
user = request.POST.get("user")
pwd = request.POST.get("pwd")
#if 验证成功返回user对象,否则返回None
user = auth.authenticate(username=user,password=pwd)
if user: # 没有登录返回匿名对象,只能打印username
auth.login(request,user) # request.user: 当前登录对象 没有登录成功返回None # auth函数 + 中间件authware实现
可以直接使用,包括在模板语言中不需要传,直接用
request.user.username
request.user.id
{{ request.user.username }}
同一浏览器测试不同用户登录,可以看到session表中会删除对应记录,重新生成新的对应用户session记录,不会再原有session-data字段上面去更新键值对,解决了上面session-data键值对混淆的问题,更加严谨
注销功能
基于ajax + button 访问其他url
基于a标签访问其他url
auth.logout(request)
User对象
匿名对象 返回false
认证装饰器
@login_required
settings.py配置
LOGIN_URL = "/login/"
访问/index跳转到/login,登录成功next自动跳转到index页面 /order会自动跳转到order页面 有next就跳转到next页面,没有就跳转index页面
next_url = request.GET.get("next","/index/")
return redirect(next_url)
https://www.cnblogs.com/yuanchenqi/articles/9064397.html
中间件
- django请求生命周期
- 应用场景
统一登录认证
统计访问频率 不管访问那个url,请求20次就关闭 限流
https://www.cnblogs.com/yuanchenqi/articles/9036479.html
默认request return None
def process_request(self,request):
return None
jQuery 事件 灵活实现
项目流程
1、搞清楚需求(产品经理)
1、基于用户认证组件和ajax实现登录验证(图片验证码)
2、基于forms组件和ajax实现注册功能
3、设计系统首页(文章列表渲染)
4、设计个人站点页面
5、文章详情页
6、实现文章点赞功能
7、实现文章的评论
---- 文件的评论
---- 评论的评论
8、富文本编辑框和防止xss攻击(评论js脚本提交执行)
2、设计表结构 所有功能model
根评论 对文章的评论
子评论 对评论的评论
自关联 自己关联自己 self
foreignkey 只是为了建立约束关系 外键约束 不用IntegerField
comment 外键会自动加id
null = True
3、按着每一个功能进行开发
4、功能测试
5、项目部署上线
静态文件statics URL="/static" 就是访问静态文件链接地址
设置static目录 os.path.join(BASEDIR,"static") 能够访问到项目的静态文件
window.onload 要等dom加载完毕才能操作 js引入写在head中需要加入onload
所有放在 head 标签里的 CSS 和 JS 文件都会堵塞渲染。如果这些 CSS 和 JS 需要加载和解析很久的话,那么页面就会一直显示空白。所以 JS 文件要放在底部,等 HTML 解析完了再加载 JS 文件。
CSS放在头部是因为:如果CSS放在尾部,会让用户第一时间看到没有样式的页面,比较的‘难看’,为了避免这种情况发生,将CSS放在头部。
入口函数
window.onload = function(){
alert(1);
}
jQuery
$(document).ready(function(){
alert(1);
})
简写
$(function() {
alert(2);
})
核心区别:
1、jQuery执行时机 DOM结构加载完执行 、 onload等全部资源加载完执行包括图片 (时间很长)
2、jQuery可执行多次 不会覆盖,顺序执行、 onload只执行一次 后面会覆盖前面
3、jQuery可简写
- 验证码图片
1、验证码生成
2、局部刷新 采用jQuery实现图片切换,开始想到jQuery绑定事件触发ajax执行访问切换图片 ==> 直接jQuery src即可实现
加载页面执行 动画效果 需要入口函数
只是事件触发执行,直接绑定事件即可,不需要在入口函数中触发执行,触发点击执行
验证码刷新
$("#valid_code_img").click(function(){
$(this)[0].src +="?"
})
利用session保存验证码 cookie也可以,session更好,保存在服务端
总结:
1、一次请求会伴随多次请求
2、PIL
3、session存储
4、验证码刷新
ajax jQuery auth session 实现
传递json数据,直接使用JsonResponse(response) 实现json解析
优化:
封装到模块中from导入模块调用对应函数
search 属性是一个可读可写的字符串,可设置或返回当前 URL 的查询部分(问号 ? 之后的部分)
意思就是获取get url链接中的请求地址,如果有就直接跳转到指定页面,没有就跳转到/index 页面 就跟之前auth组件里面会跳转next一样,例如:
next_url = request.GET.get("next","/index/") # 通过URL get请求获取数据 url访问的链接?=order 获取到next页面,这里get是浏览器发起的,ajax也可以发起GET,通过上面的方式获取到get数据,
当前get中有后缀就跳转都对应页面,没有就跳转到index页面
if(location.search){
location.href = location.search.slice(6)
}else{
location.href = "/index/"
}
- 滑动验证码 极验
基于forms组件和ajax实现注册功能
STATIC_URL='/static/'
STATICFILES_DIRS=[os.path.join(BASE_DIR,"static")]
1 基于forms组件设计祖册页面
点击头像 == 点击input
头像预览
1 获取用户选中文件对象
2 获取文件对象的路径
3 修改img的src属性 src=文件对象的路径
method.POST == 'post'
2 错误信息
views:
form.errors # {"user":[.......]}
3 局部钩子和全局钩子校验
user字段不能重复
两次密码不一致
4 FileField 与 ImageFiled
django实现
会将文件对象下载到项目的根目录中avatars文件夹中(如果没有avatar文件夹,Django会加自动创建),user_obj的avatar存的是文件的相对路径
5 media配置
django有两种静态文件:
/static/ : js,css,img
/media/ : 用户上传文件
setttings.py
MEDIA_ROOT=os.path.join(BASE_DIR,"media")
MEDIA_URL = "/media/"
提供浏览器访问
只是记住对应url和settings配置即可:
settings.py:
MEDIA_URL="/media/"
urls.pt:
# media配置:
re_path(r"media/(?P<path>.*)$",serve,{"document_root":settings.MEDIA_ROOT})
联想到的:
文件上传,with open(xx,'wb') as f, data = f.read() data发送过去
application/json ajax传递 json到服务端
$(".btn").click(function(){
$.ajax({
url: "", // 默认当前ip:端口
type:"post",
contentType: "application/json",
data:JSON.stringify({
a:1,
b:2
}),
body中a=1&b=2 ==》 {'a':1,'b':2}
首页 - 导航区域
登录注册实现
django admin (不是必须的)
django内部一个组件:后台数据管理组件(web页面)
python manage.py createsuperuser 针对用户认证组件对应的用户表
个人站点页面的文章查询
url做分发,多个APP需要做分发
ajax是发送后端请求,只是js实现而已,最终还是跟后端交互
表单验证是前端还是后端验证?
目前form(刷页面) 和 ajax (不刷页面)都是基于后端验证 前端没有验证
模板语言实现input data保存 和 报错返回不同样式,可以取代纯前端验证
结合jQuery事件 + ajax 触发,不需要等待用户提交,移开鼠标就验证当前input内容并返回错误信息,从而实现了快速验证+友好体验
取代纯前端js表单验证,如果觉得请求过多,可以只在提交的时候显示,这个根据业务场景来实现,并不是技术问题
js验证可以减少后端请求次数,仅仅而已,体验不同,目前无需关注
前端验证是为了提供更好的用户体验;
后端验证是为了保证数据满足业务条件(business invariants);
后端验证必须存在
前端是为了更好的用户体验
从必要的角度来说,前端可以不做验证,但是后端的验证是必须做的。
为什么呢?
前端不做验证,但是在表单提交的时候,后端验证的结果会返回前端,前端需要解析结果,显示对应的内容。对于验证不通过的情况,需要展示相应的不通过的原因。
后端验证一定要有,是因为后端才是接收数据,并对数据进行操作和存储的。只要保证了接收到的数据有足够的验证,就能保证最终存储的数据是满足了业务验证条件的,不是“脏数据”。
如果仅有前端验证,没有后端验证。在前后端分离的情况下,用户可以绕过前端,直接访问后端接口。那么前端验证也就失效了。也就等于没有对数据的业务验证了。
同时,如果仅有前端验证,部分验证功能不好满足。比如判断数据库是否存在相同的用户名,此时需要查询数据库才能判断。如果前端不同后端交互,那么是不清楚用户名是否重复的。
K: 后端有,前端可无
就拿设定密码这事举例,比如网站要求密码必须包含数字、字母和特殊字符,如果只做后端验证,用户就很容易有挫败感,很多用户都没心情仔细看网页上的说明的,写上最喜欢的密码123456或者自己的生日数字就发送了,然后后端验证不通过,bang!失败,用户于是只好重新来,这种体验......虽然安全,但是并不是最好。
如果加上前段验证,用户只输入123456的时候,就可以在密码框下面动态显示密码不够安全,还缺啥啥啥,这样用户容易知道自己该做的啥,再点击发送按钮前就让密码符合规则的概率大,而且体验也好很多。
url、model、templates -- 模板语言 + 嵌套继承、view 逻辑
请求生命周期 中间件
ajax与form表单提交方式思考,前后端验证 前端只是减少请求 + 提高用户体验,后端保证数据输入,具体看业务需求,不需要体验后端验证就够了,不在乎请求量,后端也可以做每个input框的验证,
ajax绑定button点击提交跟ajax绑定鼠标选中事件发送请求是一个流程,只是不同事件触发而已,也可以做到页面每个input提示错误,而且是跟后端交互实现的错误提示
ajax与form都是后端验证,只是刷不刷新页面的问题,form会刷新,ajax不会刷新,体验更好
纯前端验证 比如 在input输入框后面加提示,打钩,显示输入的格式什么的等等,更好的用户体验,减少对后端的请求量,不然每个input框都去做一次ajax请求,比较耗资源
具体看应用场景,业务需求