这一部分包括了flask 的基础知识点和一个简单的博客系统,代码仓库,之后的学习笔记也会一直更新。
1.环境
conda reate -n flask python
conda activate flask
pip install flask -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
2.知识点
2.1.第一个flask项目
首先项目的结构
static(文件夹,放css,js,图片文件等)
templates(文件夹,放html文件)
1.第一个flask项目.py
from flask import Flask#flask包中导入Flask类
app=Flask(__name__)#使用Flask类创建一个对象
#创建路由和试图函数的映射
@app.route("/")
def hello():
return "hello world"
if __name__=="__main__":
app.run()
2.2.修改Debug,host,port配置
app.run(debug=True,host="0.0.0.0",port="5001")
2.3.url与视图函数
有参路由,路由传参
from flask import Flask,request
app=Flask(__name__)
#1.url:http[80]/https[443]://www.域名.com:port/path
@app.route("/")
def hello():
return "hello world"
@app.route("/profile/")
def profile():
return "个人中心"
#2.有参路由,路由传参,利于seo优化
@app.route("/blog/<int:blog_id>/")
def blog_detail(blog_id):
return "您访问的博客是:%d" %blog_id
#3.查询字符串的方式传参:http://172.20.10.5:5000/book/list?page=9,默认page=1,不利于seo优化,一般后台用这种。
@app.route("/book/list/")
def book_list():
page=request.args.get(key="page",default=1,type=int)
return f"这是第{page}页"
if __name__=="__main__":
app.run(debug=True,host="0.0.0.0",port="5000")
#2.路由传参的参数类型:
string:默认的,接收没有任何斜杠的文本。
int:整型
float:浮点类型
path:和string类型类似,但可以接收斜杠
uuid:uuid字符,全宇宙唯一的标识符,一般用来作为表的主键。
any:可以指定多种路径共用。
@app.route('/<any(blog,user):url_path>/<id>/')
def two(url_path,id):
if url_path=='blog':
return "博客详情:%s"%id
else:
return "用户详情:%s"%id
(url_for)反向查找路径
@app.route("/")
def hello():
print(url_for('my_list',page=1,count=2))#输出是:/list/1?count=2
return "hello"
@app.route("/list/<page>/")
def my_list():
return "list"
2.4.模板渲染
1.templates/blog.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<titel>博客</titel>
</head>
<body>
<h1>博客id是:{{blog_id}}</h1>
<p>博客名是:{{user_name}}</p><!--1.取变量值*/-->
<div>{{user.username}}/{{user.email}}</div><!--2.取对象属性*/-->
<div>{{person.u}}/{{person["e"]}}</div><!--1.字典的取值有两种方式*/-->
</body>
</html>
2.模板渲染.py
from flask import Flask,render_template
app=Flask(__name__)
@app.route("/")
def hello():
return render_template("index.html")#1.自动去templates目录下面找index.html文件,并渲染
@app.route("/blog/<blog_id>/")
def blog_detail(blog_id):
return render_template("blog.html",blog_id=blog_id,user_name="zoe")#2.传参数给html去渲染,html:{{var_name}}
class User:
def __init__(self,username,email):
self.username=username
self.email=email
@app.route("/information/")
def information():
user=User(username="张三",email="111@zs")
person={"u":"李四","e":"222@ls"}
return render_template("blog.html",user=user,person=person)#3.传的参数是对象,字典。
if __name__=="__main__":
app.run(debug=True,host="0.0.0.0",port="5000")
2.5.过滤器
传到html的变量处理再渲染,这时用管道操作符(|),连接自带的过滤器或者自定义的过滤器.
1.filter.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<titel></titel>
</head>
<body>
<div>{{user.username}}长度是:{{user.username|length}}</div><!--1.管道操作符后连接length自带的过滤器-->
<div>{{mytime|dformat}}</div><!--2.管道操作符后连接的是自定义的过滤器-->
</body>
</html>
2.过滤器.py
from flask import Flask,render_template
from datetime import datetime
app=Flask(__name__)
class User:
def __init__(self,username,email):
self.username=username
self.email=email
#2.自定义过滤器
def datetime_format(value,format="%Y年%m月%d日 %H:%M"):
return value.strftime(format)
app.add_template_filter(datetime_format,"dformat")#将自定义的datetime_format,以dformat为名添加到app的过滤器中
@app.route("/filter/")
def filter():
user=User(username="张三",email="111@zs")
mytime=datetime.now()
return render_template("filter.html",user=user,mytime=mytime)#1.user这里在html中会用到自带的过滤器,给出变量的length
if __name__=="__main__":
app.run(debug=True,host="0.0.0.0",port="5000")
2.6.控制语句for与if
1.control.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta chatset="UTF-8">
<title>控制语句if与for</title>
</head>
<body>
{% if age>18 %}
<div>你已成年</div>
{% elif age==18 %}
<div>你今年成年</div>
{% else %}
<div>你未成年啊</div>
{% endif %}
{% for book in books %}
<div>书名:{{book.name}},作者:{{book.author}}</div>
{% endfor %}
</body>
</html>
2.控制语句.py
from flask import Flask,render_template
app=Flask("__name__")
@app.route("/control/")
def control():
age=8
books=[{"name":"三国演义","author":"罗贯中"},{"name":"水浒传","author":"施耐庵"}]
return render_template("control.html",age=age,books=books)
if __name__=="__main__":
app.run(debug=True,host="0.0.0.0",port="5000")
2.7.模板继承
1.base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
</head>
<body>
这是base文字
{% block body %}{% endblock %}
</body>
</html>
2.child1.html
{% extends "base.html"%}
{% block title %}
child1的title
{% endblock %}
{% block body %}
child1的body
{% endblock %}
3.模板继承.py
from flask import Flask,render_template
app=Flask("__name__")
@app.route("/child1/")
def child1():
return render_template("child1.html")
if __name__=="__main__":
app.run(debug=True,host="0.0.0.0",port="5000")
2.8.加载静态文件
在html文件里加载static里面的css,js,picture等文件。
1.alert.js
alert("js执行的弹窗");
2.style.css
body{
background-color:pink;
}
3.static.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>静态文件加载</title>
<link rel="stylesheet" href="{{url_for('static',filename='css/style.css')}}"><!--加载css样式文件-->
<script src="{{url_for('static',filename='js/alert.js')}}"></script><!--加载js文件-->
</head>
<body>
<img src="{{url_for('static',filename='img/1.jpg')}}" alt=""><!--加载img文件-->
</body>
</html>
4.加载静态文件.py
from flask import Flask,render_template
app=Flask("__name__")
@app.route("/my_static/")
def my_static():
return render_template("static.html")
if __name__=="__main__":
app.run(debug=True,host="0.0.0.0",port="5000")
2.9.mysql操作
2.9.1.安装mysql
这里可以参考博文。
然后在flask环境中
pip install pymysql
pip install flask-sqlalchemy
创建一个名为database_learn的数据库
2.9.2.在python中连接数据库并测试是否连接成功
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
HOSTNAME="127.0.0.1"
PORT=3306
USERNAME="root"
PASSWORD="xxxx"
DATABASE="database_learn"
app=Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI']=f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"
db=SQLAlchemy(app)#1.sqlalchemy读取app的config,然后自动连接,
#2.测试sql是否连接成功,输出(1,),表示连接成功
with app.app_context():
with db.engine.connect() as conn:
rs=conn.execute(text("select 1"))
print(rs.fetchone())
@app.route("/")
def hello():
return "hello"
if __name__=="__main__":
app.run()
2.9.3.创建表并增删改查
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
HOSTNAME="127.0.0.1"
PORT=3306
USERNAME="root"
PASSWORD="xxxx"
DATABASE="database_learn"
app=Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI']=f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"
db=SQLAlchemy(app)
#1.ORM对象关系映射,一个ORM模型与数据库中的一个表对应:创建一个类就是创建了一张表,实例化一个对象就是插入了一条数据
class User(db.Model):
__tablename__="user"#表名
id=db.Column(db.Integer,primary_key=True,autoincrement=True)#设为主键,自动增长
username=db.Column(db.String(100),nullable=False)#不可置空
password=db.Column(db.String(100),nullable=False)
with app.app_context():
db.create_all()#开始创建表
#1.增:
@app.route("/user/add/")
def add_user():
user=User(username="张三",password="123")#1.创建ORM对象
db.session.add(user)#2.将ORM对象添加到db.session
db.session.commit()#3.将db.session中的改变同步到数据库中
return "用户创建成功"
#2.查询:get查找(根据主键查找);filter_by查找
@app.route("/query/")
def query():
#1.get查找
# user=User.query.get(1)
# print(f"{user.id}:{user.username}--{user.password}")
#2.filter_by查找
users=User.query.filter_by(username="张三")#是一个Query类数组
for user in users:
print(user.username)
return "查找成功"
#3.改:
@app.route("/user/update/")
def update_user():
user=User.query.filter_by(username="张三").first()
user.password="gai"
db.session.commit()
return "数据修改成功"
#4.删:
@app.route("/user/delete/")
def delete_user():
user=User.query.get(1)
db.session.delete(user)
db.session.commit()
return "删除成功"
@app.route("/")
def hello():
return "hello"
if __name__=="__main__":
app.run(debug=True,host="0.0.0.0",port="5000")
2.9.4.外键与表关系
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
HOSTNAME="127.0.0.1"
PORT=3306
USERNAME="root"
PASSWORD="190023"
DATABASE="database_learn"
app=Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI']=f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"
db=SQLAlchemy(app)
class User(db.Model):
__tablename__="user"#表名
id=db.Column(db.Integer,primary_key=True,autoincrement=True)#设为主键,自动增长
username=db.Column(db.String(100),nullable=False)#不可置空
password=db.Column(db.String(100),nullable=False)
class Article(db.Model):
__tablename__="article"
id=db.Column(db.Integer,primary_key=True,autoincrement=True)
title=db.Column(db.String(200),nullable=False)
content=db.Column(db.Text,nullable=False)
#添加两表之间的外键
author_id=db.Column(db.Integer,db.ForeignKey("user.id"))
#添加两表之间的对象关系
author=db.relationship("User",backref="articles")#article.author返回User的对象,user.articles返回Article的对象
with app.app_context():
db.create_all()
#增
@app.route("/article/add/")
def ar_ad():
article1=Article(title="西游记",content="xxxxxxxxxxxxxxxx")
article1.author=User.query.get(2)
article2=Article(title="红楼梦",content="yyyyyyyyyyyyyyyy")
article2.author=User.query.get(2)
#添加到session中
db.session.add_all([article1,article2])
#session中的数据同步到数据库中
db.session.commit()
return "文章添加成功"
#查
@app.route("/article/query/")
def ar_qu():
user=User.query.get(2)
for article in user.articles:
print(article.title)
return "文章查找成功"
if __name__=="__main__":
app.run(debug=True,host="0.0.0.0",port="5000")
2.9.5.flask-migrate迁移ORM模型
set flask环境
pip install flask-migrate
pip install flask-migrate --upgrade
pip install flask-sqlalchemy --upgrade
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
HOSTNAME="127.0.0.1"
PORT=3306
USERNAME="root"
PASSWORD="190023"
DATABASE="database_flask"
app=Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI']=f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"
db=SQLAlchemy(app)
migrate=Migrate(app,db)
#ORM模型映射的三步
#1.flask db init:秩序执行一次,相当于仓库初始化
#2.flask db migrate:识别ORM模型的改变,生成迁移脚本
#3.flask db upgrade:
3.博客项目实战
3.1 结构搭建
blueprints文件夹,放蓝图
static文件夹放静态文件
templates文件夹放html文件
models.py放模型文件
config.py放配置文件
exts.py放扩展文件
app.py汇总主程序文件
app.py:
from flask import Flask
import config
from exts import db
from models import UserModel
from blueprints.qa import bp as qa_bp
from blueprints.auth import bp as auth_bp
app=Flask(__name__)
#1.绑定配置文件config.py
app.config.from_object(config)
#2.绑定exts文件的SQLAlchemy
db.init_app(app)
#3.绑定蓝图
app.register_blueprint(qa_bp)
app.register_blueprint(auth_bp)
if __name__=="__main__":
app.run()
3.2 连接数据库
首先在config文件夹中设置数据库连接的配置文件
HOSTNAME="127.0.0.1"
PORT='3306'
DATABASE="blog"
USERNAME="root"
PASSWORD="xxxx"
DB_URI="mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8".format(USERNAME,PASSWORD,HOSTNAME,PORT,DATABASE)
SQLALCHEMY_DATABASE_URI=DB_URI
然后在models文件里定义自己的表
from exts import db
from datetime import datetime
class UserModel(db.Model):
__tablename__="user"
id=db.Column(db.Integer,primary_key=True,autoincrement=True)
username=db.Column(db.String(100),nullable=False)
password=db.Column(db.String(100),nullable=False)
email=db.Column(db.String(100),nullable=False,unique=True)
join_time=db.Column(db.DateTime,default=datetime.now)
在app文件里导入表模型,并且进行数据库的映射
from models import UserModel
#4.数据库映射
migrate =Migrate(app,db)
最后在终端进行ORM模型映射的三步
#1.flask db init:秩序执行一次,相当于仓库初始化
#2.flask db migrate:识别ORM模型的改变,生成迁移脚本
#3.flask db upgrade:
3.3静态模板渲染
主要就是静态html改为jianjia2的模式,这里action的href=“#”,不然出现问题。然后在蓝图中设置路由和页面,
auth.py,这里设置了注册的路由和页面
from flask import Blueprint,render_template
# /auth
bp=Blueprint("auth",__name__,url_prefix="/auth")
@bp.route("/regist/")
def regist():
return render_template("regist.html")
3.4使用flask-mail邮箱验证
3.4.1邮箱发送服务搭建与测试
pip install flask-mail
进行邮箱smtp协议验证,设置邮箱服务器。然后去config进行邮箱信息设置。
MAIL_SERVER="smtp.qq.com"
MAIL_USE_SSL=True
MAIL_PORT=465
MAIL_USERNAME="xxx"
MAIL_PASSWORD="xxx"#smtp协议授权密码
MAIL_DEFAULT_SENDER="xxx"
在exts.py中引入mail
from flask_mail import Mail
mail=Mail()
在app中进行导入与绑定
mail.init_app(app)
在auth中设置路由进行测试
from flask_mail import Message
from exts import mail
@bp.route("/mail/test/")
def mail_test():
message=Message(subject="邮箱测试",recipients=["18xxxx8@163.com"],body="这是一条测试邮件")
mail.send(message)
return "邮件发送成功"
运行,进行测试,我成功收到了验证信息
3.4.2邮箱发送验证
1.首先用变量传参的方式,设置路由和蓝图auth
@bp.route("/captcha/email/")
def get_email_captcha():
email=request.args.get("email")#?变量传递的方式传入参数email
source=string.digits*6
captcha=random.sample(source,6)
captcha=''.join(captcha)
message=Message(subject="注册验证码",recipients=[email],body=f"您的验证码是:{captcha}")
mail.send(message)
return "success"
进入网址http://192.168.3.76:5000/auth/captcha/email?email=xxx@163.com进行测试。
2.将邮箱和验证码存储到数据库表中,因此在models中创建一个model
class EmailCaptchaModel(db.Model):
__tablename__="email_captcha"
id=db.Column(db.Integer,primary_key=True,autoincrement=True)
email=db.Column(db.String(100),nullable=False)
captcha=db.Column(db.String(100),nullable=False)
然后将表映射到数据库中
flask db migrate
flask db upgrade
然后再auth蓝图中,将数据实例化到数据库中
from exts import db
from models import EmailCaptchaModel
email_captcha=EmailCaptchaModel(email=email,captcha=captcha)
db.session.add(email_captcha)
db.session.commit()
并且用ajax请求,所以返回数据格式化为js格式
from flask import jsonify
return jsonify({"code":200,"message":"","data":None})
3.前端按下获取验证码按钮,通过js,获取到邮箱,然后向服务端发送一个请求,然后就是上面的后端运行代码。用到了jquery。regist.js:
//整个网页加载完成后再执行
$(function(){
$("#captcha-btn").click(function(event){
event.preventDefault();//组织默认的实践
var email=$("input[name='email']").val();//通过name从input中获取用户输入的val
$.ajax({
url:"/auth/captcha/email?email="+email,
method:"GET",
success:function(result){
var code=result['code'];
if (code==200){alert("邮箱验证码发送成功");}
else{alert(result['message']);}
},
fail:function(error){console.log(error);}
})
});
});
3.5使用flask-wtf表单验证
pip install flask-wtf
pip install email_validator
蓝图文件夹里面建一个forms.py写一个注册表单前端验证
import wtforms
from wtforms.validators import Email,Length,EqualTo
from models import UserModel,EmailCaptchaModel
from exts import db
#Form:验证前端提交的数据是否符合要求
class RegisterForm(wtforms.Form):
email=wtforms.StringField(validators=[Email(message="邮箱格式错误")])
captcha=wtforms.StringField(validators=[Length(min=6,max=6,message="验证码格式错误")])
username=wtforms.StringField(validators=[Length(min=3,max=20,message="用户名格式错误")])
password=wtforms.StringField(validators=[Length(min=6,max=20,message="密码格式错误")])
password_confirm=wtforms.StringField(validators=[EqualTo("password",message="密码不一致")])
#自定义验证1:邮箱是否已经注册
def validate_email(self,field):
email=field.data
user=UserModel.query.filter_by(email=email).first()
if user:
raise wtforms.ValidationError(message="该邮箱已经被注册")
#2:验证码是否正确
def validate_captcha(self,field):
captcha=field.data
email=self.email.data
captcha_model=EmailCaptchaModel.query.filter_by(email=email,captcha=captcha).first()
if not captcha_model:
raise wtforms.ValidationError(message="验证码错误")
else:
db.session.delete(captcha_model)
db.session.commit()
3.6登录页面
1.首先是把静态的login.html改为flask格式的;
2.然后在form.py里面利用wtforms.Form对提交来的表单进行前端格式验证;
3.通过post提交来的表单进行验证,并保存此登陆者的cookie
@bp.route("/login/",methods=['GET','POST'])
def login():
if request.method=='GET':
return render_template('login.html')
else:
form=LoginForm(request.form)
if form.validate():
email=form.email.data
password=form.password.data
user=UserModel.query.filter_by(email=email).first()
if not user:
print("用户邮箱未注册")
return redirect(url_for("auth.login"))
if check_password_hash(user.password,password):
#cookie,flask中的session,经过加密存储到cookie中
session['user_id']=user.id
return redirect("/")
else:
print("密码错误")
return redirect(url_for("auth.login"))
else:
print(form.errors)
return redirect(url_for("auth.login"))
3.通过钩子函数(befor_request/before_first_request/after_request),保存用户cookie到一个全局对象上,并利用上下文处理钩子(context_processor)将数据显示到前端。
@app.before_request
def my_before_request():
user_id=session.get(user_id)
if user_id :
user=UserModel.query.get(user_id)
setattr(g,"user",user)
else:
setattr(g,"user",None)
#上下文处理器的钩子
@app.context_processor
def my_context_processor():
return {"user":g.user}
4.在base.html中将钩子拿到的user显示到前端,并写一个logout路由蓝图
{% if user %}
<li><a >{{ user.username }}</a></li>
<li><a href="{{url_for('auth.logout')}}">注销</a></li>
{% else %}
<li><a href="{{url_for('auth.login')}}">登录</a></li>
<li><a href="{{url_for('auth.regist')}}">注册</a></li>
{% endif %}
@bp.route('/logout/')
def logout():
session.clear()
return redirect('/')
3.7发布问答页面
1.首先是把静态的question.html改为flask格式的,然后在蓝图中设置路由,当get请求时,就render这个html文件。
2.post发布的内容也要通过form表单提交的方式保存到数据库中,所以在models中需要建对象表,并且有外键和反向引用的关系表
class QuestionModel(db.Model):
__tablename__="question"
id=db.Column(db.Integer,primary_key=True,autoincrement=True)
title=db.Column(db.String(100),nullable=False)
content=db.Column(db.Text,nullable=False)
create_time=db.Column(db.DateTime,default=datetime.now)
#外键
author_id=db.Column(db.Integer,db.ForeignKey("user.id"))
author=db.relationship(UserModel,backref="questions")
3.post提交表单的话,也需要表单前端先验证,所以需要在forms.py中进行验证。
class QuestionForm(wtforms.Form):
title=wtforms.StringField(validators=[Length(min=3,max=100,message="标题格式错误")])
content=wtforms.StringField(validators=[Length(min=3,message="内容格式错误")])
4.在qa.py中设置路由和蓝图,对post拿来的form进行验证并存到数据库中。
@bp.route("/qa/public/",methods=['GET','POST'])
def public_question():
if request.method=='GET':
return render_template("question.html")
else:
form=QuestionForm(request.form)
if form.validate():
title=form.title.data
content=form.content.data
question=QuestionModel(title=title,content=content,author=g.user)
db.session.add(question)
db.session.commit()
return redirect("/")
else:
print(form.errors)
return redirect(url_for("qa.public_question"))
5.新建一个decorators.py文件,设置一个登陆装饰器,当用户没有登录时,就不可以访问问答这个页面。
from flask import g,redirect,url_for
from functools import wraps
def login_required(func):
@wraps(func)#保留func信息
def inner(*args,**kwargs):#万能参数:位置参数*args(1,2,3);关键字参数**kwargs(d=4,e=5)
if g.user:
return func(*args,**kwargs)
else:
return redirect(url_for("auth.login"))
return inner
3.8问答列表显示页面
1.首先是把静态的index.html改为flask格式的,然后在蓝图中设置路由,当get请求时,就render这个html文件。
2.当点击列表标题时跳入到列表详情内容的页面,所以需要写路由蓝图,跳到detail.html
3.9评论相关内容
1.首先评论需要入库,所以先建Model,这里用了两个外键。
class AnswerModel(db.Model):
__tablename__="answer"
id=db.Column(db.Integer,primary_key=True,autoincrement=True)
content=db.Column(db.Text,nullable=False)
create_time=db.Column(db.DateTime,default=datetime.now)
#外键
question_id=db.Column(db.Integer,db.ForeignKey("question.id"))
author_id=db.Column(db.Integer,db.ForeignKey("user.id"))
#关系
question=db.relationship(QuestionModel,backref=db.backref("answers",order_by=create_time.desc()))
author=db.relationship(UserModel,backref="answers")
2.表单前端先验证,所以需要在forms.py中进行验证。
class AnswerForm(wtforms.Form):
content=wtforms.StringField(validators=[Length(min=3,message="标题格式错误")])
question_id=wtforms.StringField(validators=[InputRequired(message="必须要传入问题id")])
3.路由蓝图
@bp.post("/answer/public/")
@login_required
def public_answer():
form=AnswerForm(request.form)
if form.validate():
content=form.content.data
question_id=form.question_id.data
answer=AnswerModel(content=content,question_id=question_id,author=g.user.id)
db.session.add(answer)
db.session.commit()
return redirect(url_for("qa_detail",question_id=question_id))
else:
print(form.errors)
return redirect(url_for("qa_detail",question_id=request.form.get("question_id")))
4.前端,表单提交和跳转的页面。
5.搜索问答功能的实现:写一个search路由蓝图,然后在base模板里,把search地址给search按钮的跳转链接,就实现了按下这个按钮实现search功能。