一、前奏
1.修改debug、host、port
debug模式:1.修改代码保存后自动运行,不需重启;
2.出现bug时,在网页上显示bug内容。
host参数:默认为127.0.0.1(本机)。修改为0.0.0.0,网页会被局域网的其他设备访问到。
port参数:端口号,默认5000。当有多个网页项目时可更改端口号。
2.建立路由(url)与视图函数之间的映射
@app.route('/path')
def path():
return "Helloworld"
二、渲染模版
1.render_template('html文件名')
使用render_template('html文件名')将html渲染出来,用return返回渲染好的html模版。
from flask import Flask,render_template
@app.route('/path')
def path():
return render_template('index.html')
注:html中的常用标签:
①<h1></h1> 一级标题
②<p></p> 正文文字
③<div></div> 换行输出
④<ul>
<a href="path"></a>
</ul> 标签,href是标签地址
⑤<img src="path" alt=""> 图片,src是图片地址。没有</img>哦
⑥<link rel="stylesheet" href="path" > 加载css。没有</link>
⑦<script src=" "> </script> 加载js。有</script>
2.传入参数
方法1:request
from flask import Flask,render_template,request
@app.route('/path')
def path():
page=request.args.get(key="page",default=1,type=int)
return render_template('index.html',page=page)
访问网址:'127.0.0.1:/5000/path?page=2'
注:1.调用request.args.get()选择是否省略type。区别在于,网址为'127.0.0.1:/5000/path?page=a'省略后依然可访问,而不省略则无法访问网址,减少出bug的可能。
2.若访问'127.0.0.1:/5000/path',即不加任何参数,最后得到的是page=1的内容。
方法2:从path路径中访问
@app.route('/path/<int:page>')
def path(page):
return render_template('index.html',page=page)
访问网址:'127.0.0.1:5000/path/2'
注:可直接<page>而不定义page的类型,效果参考方法1。
将参数传入html后,可在html调用。
<body>
<h1>Class photo</h1>
<div>您正在查看第{{ page }}页。</div>
</body>
3.传入对象和字典
传入字典列表
@app.route('/path')
def path():
books=[{
"bookname":"白夜行",
"author":"东野圭吾"
},{
"bookname":"愿你的青春不服梦想",
"author":"俞敏洪"
}]
return render_template('index.html',books=books)
在html中的访问
<body>
<h1>Books</h1>
{% for book in books %}
<div>{{book.bookname}}-{{book.author}} </div>
{% endfor %}
<div>{{books[0]['bookname']}}-{{books[0]['author']</div>
</body>
注:在html中,访问字典更常用dir.key的方式。
传入对象
class User:
def __init__(self,name,password):
self.name=name
self.password=password
@app.route('/path')
def path():
user=User('法外狂徒张三','111111')
return render_template('index.html',user=user)
在html中访问
<body>
<div>{{user.name}}-{{user.password}}</div>
</body>
4.html模版和继承
html父模版
...
<head>
<title>{% block title%}-{% endblock %}</title>
</head>
<body>
<ul>
<a href="/">首页</a>
<a href="/blog">博客</a>
</ul>
{% block body %}{% endblock %}
</body>
..
html子文件
{% extend 'base.html' %}
{% block title%}博客{% endblock %}
{% block body%}
<div> 我是子文件的文字 </div>
{% endblock %}
注:{% extend 'base.html' %}中,父文件需要加引号。
5.加载static文件
加载图片
<img scr="{{ url_for('static',filename='path') }}" alt="">
注:1.path指图片路径(默认从static开始);
2.url_for()作用:将文件目录转换为路由地址(不要丢了双大括号);
3.注意<img>没有</img>,也没有中间的文字内容。
加载css文件
<link rel="stylesheet" href="{{url_for('static','path')}}" >
注:<link>没有</link>
css改变浏览器背景颜色
body{
background-color:pink;
}
加载javascript文件
<script scr="{{ url_for('static','path') }}"></script>
注:<script>三个静态文件中唯一需要</script>的,但用处不大(似乎)。
js文件发送信息框
alert("我是js执行的!");
注:css文件和js文件的句末都需要带等号。
6.html的判断和循环语句
判断语句
<body>
{% if age>18%}
<div>您已满18岁,可以进入网吧。</div>
{% elif age < 18%}
<div>您未满18岁,不能进入网吧</div>
{% else %}
<div>您刚满18岁,需在成年人陪同下进入网吧</div>
{% endif %}
</body>
循环语句
<body>
<h1>Books</h1>
{% for book in books %}
<div>{{book.bookname}}-{{book.author}} </div>
{% endfor %}
</body>
注:1.html中的判断和循环都必须有end语句;
2.html中的for循环语句不能break;
7.过滤器
.自带filter
<body>
<div>{{user_id}}-{{ user_id | length }}</div>
</body>
注:user_id | length可获取user_id的长度。
.自定义filter
from datetime import datetime
def datetime_format(value,format="%Y-%m-%d %H:%M"):
return value.strftime(format)
app.add_template_filter(datetime_format,"dformat")
@app.route('/time')
def get_time():
mytime=datetime.now()
return render_template('time.html',mytime=mytime)
注:1.app.add_template_filter(函数名,过滤器名)。将函数生成了过滤器。其中第一个参数value为'|'前的参数。
2.若想调用多个参数,则需要调用过滤器时,在过滤器名后加()添加第2到n个参数。
<body>
<div>now time:{{mytime | dformat}}</div>
</body>
注:采用mytime | dformat("%Y-%m-%d"),可直接输出年月日。
三、数据库
1.数据库连接
.先安装Flask-SQLAlchemy这个包。
pymysql可操作数据库,SQLAlechemy建立flask和数据库的连接。其中pymysql被封装在了SQLAlchemy中,使用时只导入SQLAlchemy即可。
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
...
hostname='127.0.0.1'
port=3306
username='root'
password='password'
database='database_learn'
app.config['SQLALCHEMY_DATABASE_URI']=f"mysql+pymysql://{username}:{password}@{hostname}:{port}/{database}?charset=utf8bm4"
db=SQLAlchemy(app)
注:1.app.config['SQLALCHEMYL_DATABASE_URI']=...容易写错,多写;
2.db为database的简称,SQLAlchemy建立了一个alchemy对象。
3.定义的变量中只有一个是数字而不是字符型的,即port=3306。数据库默认端口3306
.检测是否连接成功
with app.app_context():
with dp.enging.connect() as conn:
rs=conn.execute('select 1')
print(rs.fetchone())
注:1.如打印(1,),则说明连接成功;
2.需在Navicat Premium中先添加数据库在连接。
2.创建orm模型
.orm模型实际上是继承自db.Model的类,建立python类和数据库的映射。
class User(db.Model):
__tablename__='user'
id=db.Column(db.Integer,primary_key=1,autoincrement=True)
username=db.Column(db.String(100),nullable=False)
password=db.COlumn(db.String(100),nullable=False)
注:1.建立类与数据库的映射,实际上是建立元素与数据库的映射。db.Column(db.type,...)实现了这一点。
2.注意不要丢__tablename__='',其值为数据库table的标题。
3.每一个orm对象都需要一个id变量。
.为了使数据库与orm模型实现同步,可使用以下代码:
with app.app_context():
db.create_all()
注:使用上述代码后,可在数据库中看到新建的数据类型和信息。但db.create_all()无法做到在元素增加时同步更新。
3.数据的增、查、改、删除
.添加数据
@app.route('/user/add')
def user_add():
user=User(username='法外狂徒张三',password='111111')
dp.session.add(user)
dp.commit()
return "添加数据成功!"
注:1.若添加多个元素,可使用db.session.add_all([user1,user2])。注意参数为列表。
2.dp.session.commit()的作用:将db的修改同步到数据库。千万不要丢。
.查找数据
@app.route('/user/query')
def user_query():
user1=User.query.get(1)
user2=User.query.filter_by(username='法外狂徒张三').first()
print(f'username:{user1.username}--password:{user1.password}')
print(f'username:{user2.username}--password:{user2.password}')
return "查找数据成功!"
注:1.User.query来自父类db.Model,User.query查找的返回值是user对象;
2.User.query.get()根据id查找,数据唯一;
3.User.query.filter_by()根据任意值查找,返回列表,列表,列表!
取元素的方式有两种:①User.query.filter_by(username='法外狂徒张三')[0]
②User.query.filter_by(username='法外狂徒张三').first()
其中first()在查找结果为空的情况下不会报错,使用起来更稳定,一般采用这种方式。
.修改数据
@app.route('/user/change')
def user_change()
user=User.query.get(1)
user.password='222222'
db.session.commit()
return "修改数据成功!"
注:没什么好注的,记住db.session.commit()同步数据。
.删除数据
@app.route('/user/delete')
def user_delete()
user=User.query.get(1)
db.session.delete(user)
db.session.commit()
return "数据删除成功!"
注:删除db.session.delete(orm对象)。
4.表与表之间的连接
.建立外键
class User(db.Model):
__tablename__='user'
id=db.Column(db.Integer,primary_key=1,autoincrement=True)
username=db.Column(db.String(100),nullable=False)
password=db.COlumn(db.String(100),nullable=False)
#authors=db.relationship('Article',back_populates='Users')
class Article(db.Model):
__tablename__='article'
id=db.Column(db.Integer,primary_key=1,autoincrement=True)
article_name=db.Column(db.String(100),nullable=False)
article_text=db.Column(db.Text,nullable=False)
author_id=db.Column(db.Integer,db.ForeignKey('user.id'))
#author=db.relationship("User",back_poplulates='articles')
author=db.relationship('User',backref='articles')
注:对author_id=db.Column(db.Integer,db.ForeignKey('user.id'))的理解:
- 将Article中的author_id元素映射成db中的Integer类型,且以user.id建立外键。此后可根据User.query.get(author_id)访问作者信息;
- 作用:将Article和User两个表连接起来。
.建立relationship
使用db.relationship=('orm对象',backref/back_polulates='orm对象的访问元素'),建立两对象的连接。
方法1:back_populates=...
代码如注释部分。
方法2:backref=...
代码如上。
注:1.a_id=...同a=db.relationship()中的a,即建立的外键和relationship必须统一。本质上relationship是通过外键建立的;
2.作用:可通过user访问所有article。
.通过user访问article
@app.route('/article/query')
def query_article():
user=User.query.get(1)
for article in user.articles:
print(f'{article.title}-{article.text}')
return "文章查找成功!"
注:通过user访问article时,能通过外键author_id访问到所有作者为user的文章,返回类型为列表。