验证
在static/js下新建一个reg.js文件.
这里有个小tips,就是在js的开头写一个分号”;”,因为考虑到多个js文件合并的问题。最小化的js,大家都跑到一行去了,如果不加分号难免会出错。
并且,如果js是子页面的,那么在主模板js上就不能直接写相关的js文件,而是在主模板下的script的最下面添加:
{% block js %}
{% endblock %}
然后在子页面中的这块中写我们的js文件地址。
{% block js %}
<script type="text/javascript" src="{{buildStaticUrl('/js/reg.js')}}"></script>
{% endblock %}
这样的话,在子页面中的js就能正常的加载在主模板的js下面。
同理,如果是css的话,在主模板中使用自定义的块:
{% block css %}
{% endblock %}
然后子模版的特定的css写在这个块里面。
如果元素是form表单,那么点击submit之后,链接会自动产生一个get请求,即在浏览器中可以看到链接后面多了一个问号?
js内容
;
var member_reg_ops =
{
init:function ()
{
this.eventBind();
},
eventBind:function()
{
$(".reg_wrap .do-reg").click(function(){
// 校验,如果正在处理中,不允许重复点击提交确认按钮
var btn_target = $(this);
if (btn_target.hasClass("disabled")) {
alert("正在处理中,请不要重复点击~");
return ;
}
var login_name = $('.reg_wrap input[name=login_name').val();
var login_pwd = $('.reg_wrap input[name=login_pwd').val();
var login_pwd2 = $('.reg_wrap input[name=login_pwd2').val();
if (login_name == undefined||login_name.length<1) {
alert("请输入用户名~");
return ;/*这里的return不知道是干啥用的*/
};
if (login_pwd==undefined || login_pwd.length<6) {
alert("请输入正确的密码!");
return ;
};
if (login_pwd2!=login_pwd||login_pwd2==undefined) {
alert("两次密码不一致!");
return ;
};
btn_target.addClass("disabled");
// 上面通过后将要进行Ajax处理,此时先添加一个disabled的类
// 下面是jQuery中的Ajax的写法
$.ajax({
url:"/member/reg",
type:"POST",
data:{
login_name:login_name,
login_pwd:login_pwd,
login_pwd2:login_pwd2,
},
dataType:"json",
success:function (res){
//如果成功的话,将disabled的类移除
btn_target.removeClass("disabled")
}
});
});
}
};
$(document).ready(function(){
member_reg_ops.init();
});
后端校验并返回
因为此时在member.py中定义的reg请求,是使用的默认的get不是post,所以这里的post出错了,因此需要去member.py中修改一下请求方法。
前端校验写完了,并且数据也发送到后端了,后端需要进行校验和返回了。但是为什么后端需要写校验呢,因为可以通过调用接口直接发数据,前端只是针对普通用户的。
这里需要用到一个统一的返回,因此,单独需要写一个Helper.py
# _*_ coding:utf-8 _*_
from flask import jsonify
def ops_renderJson(code =200, msg = '操作成功~' ,data = {}):
resp = {'code':code,'msg':msg,'data':data}
#有一点不太明白,
#resp的data对应的值这里不能写jsonify(data)不然会报错Object of type 'Response' is not JSON serializable
return jsonify(resp)
def ops_RenderErrJson(msg = "系统繁忙,请稍后再试~",data={}):
return ops_renderJson(code = -1,msg=msg,data=data)
这里出现了一个小插曲,获取request的请求方式是通过request.method 而不是request.methods,虽然在写装饰器的时候,使用了methods:@member_page.route(‘/reg’,methods = [‘GET’,’POST’])。于是我想回去从新使用postman测试一下看看request是什么【但是这个其实老师有说过,他只是个代理】,结果发现只有/可以访问,其他的都不能访问了,例如/me,./get全都404了。index.py文件:
from flask import Blueprint,request,make_response,jsonify,render_template
from sqlalchemy import text
from application import db
from common.models.user import User
index_page = Blueprint("index_page",__name__)
@index_page.route('/')
def index():
return render_template("common/layout.html")
# var_a = request.args.get('a','Welcom')
# return 'hello, this is me request:%sparams:%s,var_a:%s,request:%s'%(request.method,request.args,var_a,type(request))
@index_page.route('/me')
def hello():
return "hello, this is me"
@index_page.route('/get')
def get():
var_a = request.args.get('a','Welcom')
return 'request:%sparams:%s,var_a:%s,request'%(request.method,request.args,var_a,request)
@index_page.route('/post',methods=['POST'])
def post():
var_b = request.values['b'] if 'b' in request.values else 'welcome'
return 'request: %s; params: %s; var_b: %s;%s'%(request.method,request.args,var_b,request.values)
@index_page.route('/upload',methods=['POST'])
def upload():
var_c = request.files['file'] if 'file' in request.files else None
return 'request: %s; params: %s; var_c: %s; values:%s'%(request.method,request.files,var_c,request.values)
@index_page.route('/text_get')
def text_get():
return "text/html"
@index_page.route('/text_same')
def text_same():
response = make_response('text/html',200)
return response
@index_page.route('/json')
def json():
data = {'a':'Tom'}
import json
response = make_response(json.dumps(data))
response.headers['Content-type'] = 'application/json'
return response
@index_page.route('/json_same')
def json_same():
data = {'b':'Jerry'}
response = make_response(jsonify(data))
return response
@index_page.route('/template')
def template():
context = {}
context['user'] = {'name' : "juha",'age':25}
context['subject'] = ['english','math','Chinese']
return render_template ('index.html',**context)
@index_page.route('/extend_template')
def extend_template():
return render_template ('extend_template.html')
@index_page.route('/db_select')
def db_select():
context = {}
# sql = text("select * from `user`")
# result = db.engine.execute(sql)
result = User.query.all()
context['result'] = result
return render_template("db_data.html",**context)
这里面实际用到的就只有第一个定义的根目录,其他都是学习测试用的,但是之前是可以访问的,现在不知道为啥访问不了了。
此时的member.py:
# _*_ coding:utf-8 _*_
from flask import Blueprint,render_template,request,jsonify
from application import app
from common.libs.Helper import ops_renderJson,ops_RenderErrJson
from common.models.user import User
#引入数据库和数据库里的登录名做校验
member_page = Blueprint('member_page',__name__)
@member_page.route('/reg',methods = ['GET','POST'])
def reg():
if request.method == "GET" :
return render_template("member/reg.html")
req = request.values
login_name = req['login_name'] if 'login_name' in req else ""
login_pwd = req['login_pwd'] if 'login_pwd' in req else ""
login_pwd2 = req['login_pwd2'] if 'login_pwd2' in req else ""
if login_name is None or len(login_name)<1:
return ops_RenderErrJson(msg = "请输入正确的登录名~")
if login_pwd is None or len(login_pwd)<6:
return ops_RenderErrJson(msg = "请输入正确的密码!")
if login_pwd2 is None or login_pwd2!=login_pwd:
return ops_RenderErrJson(msg = "两次密码不一致!")
user_info = User.query.filter_by(login_name=login_name)
if user_info:
return ops_RenderErrJson(msg = "登录名已被占用!")
return ops_renderJson(msg = "注册成功!")
@member_page.route('/login')
def login():
return render_template("member/login.html")
都写好了之后,这里的返回值不知道为啥不是中文字符注册成功,使用postman是没问题的。
后端往数据库写数据
终于到了我认为最重要的环节了,开始往数据库写数据了。
但是在引入数据库重复值校验的时候,我这里出了一点小问题。
user_info = User.query.filter_by(login_name=login_name)
SQL语句显示的是这样的,感觉有问题,无论我输入的是什么,这里都是会重复的。
SELECT user.ID
AS user_ID
, user.alias AS user_alias, user.login_name AS user_login_name
FROM user
WHERE user.login_name = %(login_name_1)s
后面发现,是我写错了,应该是user_info = User.query.filter_by(login_name=login_name).first()
SELECT user.ID
AS user_ID
, user.alias AS user_alias, user.login_name AS user_login_name
FROM user
WHERE user.login_name = %(login_name_1)s
LIMIT %(param_1)s
并且打印出了如下信息
2020-06-20 21:15:17,039 INFO sqlalchemy.engine.base.Engine {‘login_name_1’: ‘Jerry’, ‘param_1’: 1}
接着又踩坑了。
因为之前偷懒,直接在DataHelper中把getCurrentTime函数的入参写为了加上微秒的吗,因为希望能直接在对应的css和js文件上加上此标识,但是这里直接作为日期类型传入到数据库就会报错。
跟着一步一步操作终于成功写入数据库了,开心呐。
继续写js
为了方便把js管理起来,而不使用相对链接,这里还需要创建一个common.js.
有点复杂,不是太能看懂。
;
var common_ops = {
// 统一控制的方法
buildUrl:function(path,params){
// 空字符串+path
// 这里实现的功能是例如入参是{"a":1,"b":"LI"},拼接为?a=1&b=LI
var url = "" + path;
var _param_url = "";
// params 是json
if (params) {
_param_url = Object.keys(params).map(function(k){
return [encodeURIComponent(k),encodeURIComponent(params[k])].join["="]
}).join("&");
_param_url = "?" + _param_url
}
return url + _param_url;
}
};
下面继续优化js
这里使用到了layer.js一个组件库。
common.js
;
var common_ops = {
// 统一控制的方法
buildUrl:function(path,params){
// 空字符串+path
// 这里实现的功能是例如入参是{"a":1,"b":"LI"},拼接为?a=1&b=LI
var url = "" + path;
var _param_url = "";
// params 是json
if (params) {
_param_url = Object.keys(params).map(function(k){
return [encodeURIComponent(k),encodeURIComponent(params[k])].join["="]
}).join("&");
_param_url = "?" + _param_url
}
return url + _param_url;
},
// 下面进行提示窗的优化
alert:function(msg,cb){
layer.alert(msg,{
yes:function(index){
if (typeof cb == "function") {
cb();
}
layer.close(index);
}
});
}
};
reg.js
;
var member_reg_ops =
{
init:function ()
{
this.eventBind();
},
eventBind:function()
{
$(".reg_wrap .do-reg").click(function(){
// 校验,如果正在处理中,不允许重复点击提交确认按钮
var btn_target = $(this);
if (btn_target.hasClass("disabled")) {
common_ops.alert("正在处理中,请不要重复点击~");
return ;
}
var login_name = $('.reg_wrap input[name=login_name').val();
var login_pwd = $('.reg_wrap input[name=login_pwd').val();
var login_pwd2 = $('.reg_wrap input[name=login_pwd2').val();
if (login_name == undefined||login_name.length<1) {
common_ops.alert("请输入正确的用户名~");
return ;/*这里的return不知道是干啥用的*/
};
if (login_pwd==undefined || login_pwd.length<6) {
common_ops.alert("请输入正确的密码!");
return ;
};
if (login_pwd2!=login_pwd||login_pwd2==undefined) {
common_ops.alert("两次密码不一致!");
return ;
};
btn_target.addClass("disabled");
// 上面通过后将要进行Ajax处理,此时先添加一个disabled的类
// 下面是jQuery中的Ajax的写法
$.ajax({
// url:"/member/reg",
// 因为有了统一的路径管理,这里可以用下面的进行替代
url:common_ops.buildUrl("/member/reg"),
type:"POST",
data:{
login_name:login_name,
login_pwd:login_pwd,
login_pwd2:login_pwd2,
},
dataType:"json",
success:function (reg){
//如果成功的话,将disabled的类移除
btn_target.removeClass("disabled")
// 下面是注册成功的话返回至首页
var callback = null;
if (reg.code ==200) {
// 这里就是利用到了common.js中的alert方法,把函数的结果作为参数
callback = function(){
// 这里的也可以被替代了
// window.location.href = "/";
window.location.href = common_ops.buildUrl("/");
};
}
// 这里的弹窗点击确定之后,会回到首页
common_ops.alert(reg.msg,callback);
}
});
});
}
};
$(document).ready(function(){
member_reg_ops.init();
});
老师的知识总结:
统一链接管理器;
如何正确加载模板JS和CSS文件;
版本管理;
按钮的重复点击控制;
引入的layer组件。
作业:注册页面增加一个昵称表单并添加到数据。
注册功能到此结束,感觉脑子快不够用了…