练习目标:
- 使用flask完成一个注册接口,数据由用户名+密码组成,要求用户名和密码都是大小写字母和数字的组合。注册后写入本地数据库。
- 随机生成一百组数据,写入数据库。
- 完成一个登录接口,验证输入的用户名和密码是否准确。
- 完成一个get_userlist接口,以指定格式返回用户名和密码。
- 将用户名和密码下载到本地。
- 清空数据库,读取本地文件,将文件中的数据批量注册到同一数据库中。
拆解:
准备工作:
- 使用pip安装flask、SQLAlchemy等必要库
- 数据库-使用navicat连接本机的mysql,创建flask_register数据库,并且新建一个名为register表
- 本地新建项目,项目中新增config.py,存放数据库连接代码
- 项目中新增py文件,存放服务端的所有自定义的接口代码(服务端的代码最好写在一起,一定要和客户端分开放)
HOST = 'localhost'
PORT = 3306
USERNAME = 'root'
PASSWORD = '123456' #本机实际的mysql密码
DB = 'flask_register' #先在mysql中建立好这个名字的数据库
DB_URI = f'mysql+pymysql://{USERNAME}:{PASSWORD}@{HOST}:{PORT}/{DB}'
配置数据库:
'''配置数据库'''
app = Flask(__name__)
app.config["JSON_AS_ASCII"] = False
app.config['SECRET_KEY'] ='hard to guess'
# 这里登陆的是root用户,要填上自己的密码,MySQL的默认端口是3306,填上之前创建的数据库名
app.config['SQLALCHEMY_DATABASE_URI']='mysql+pymysql://root:123456@127.0.0.1:3306/flask_register'
#设置这一项是每次请求结束后都会自动提交数据库中的变动
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN']=True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS']=True #这一句不加会报错
#实例化
db = SQLAlchemy(app)
engine = create_engine(DB_URI)
Base = declarative_base(engine) # SQLORM基类
session = sessionmaker(engine)() # 构建session对象
class User_Register(db.Model):
__tablename__ = 'register' # 表名
id = db.Column(Integer, primary_key=True, autoincrement=True) # 作为主key,且自增1
username = db.Column(String(20))
password = db.Column(String(20))
print(type(User_Register))
Base.metadata.create_all() # 将模型映射到数据库中
此文件需要运行,需在文件末尾增加app.run():
if __name__ == '__main__':
app.run(port=8080, debug=True)
1、编写注册接口register:
@app.route('/register',methods = ['post'])
def user_register():
username1 = request.values.get('username')
password1 = request.values.get('password')
if username1 and password1:
import re
if re.match("^(?:(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])).*$",username1) == None:
return jsonify({"code": 202, "msg": "用户名必须是大小写字母+数字,请检查!"})
elif re.match("^(?:(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])).*$",password1)==None:
return jsonify({"code": 203, "msg": "密码必须是大小写字母+数字,请检查!"})
else:
user_register = User_Register(username=username1, password=password1)
session.add(user_register)
session.commit()
return jsonify({"code": 200, "msg": "恭喜,注册成功!"})
else:
return jsonify({"code": 201, "msg": "用户名/密码,请检查!"})
注意:
1、re.match为正则表达式匹配,匹配成功则返回None,需要import re
2、“^(?😦?=.[A-Z])(?=.[a-z])(?=.[0-9])).$”为字符串必须包含a-z和A-Z以及0-9
3、request.values.get(“username”)表示拿到传过来的字典中username的值,与request.get()方法不同
postman请求及返回:
注意:
post请求不要写在params中,会出现在地址栏,不安全。get请求写在params中。
post请求写在body或者headers里面,注意类型(form或者raw或者json之类)都需要和代码对应。
2、完成一个user_login接口,判断:用户名是否在数据库中;密码是否和用户名匹配:
@app.route('/login',methods = ['post'])
def user_login():
username1 = request.values.get('username')
password1 = request.values.get('password')
if username1:
username_list = session.query(User_Register.username).all()
print(username_list)
username_exists = session.query(User_Register.password).filter(User_Register.username == username1).first()
print(username_exists)
# 用户名存在,判断密码是否符合
if username_exists:
print(username1 + "在用户列表中")
password_one = session.query(User_Register.password).filter(
User_Register.username == username1).first() # result = Test.query.filter(Test.username == 'guest1').first()
print(password1)
print(str(username1) + "对应的密码为:" + str(password_one))
if password1 in password_one:
return jsonify({"code": 0, "msg": "密码正确,登录成功!"})
else:
return jsonify({"code": 205, "msg": "密码错误,请重新输入!"})
else:
print(username1 + "不在用户列表中")
return jsonify({"code": 203, "msg": "用户名未注册,请重新注册"})
else:
return jsonify({"code": 201, "msg": "请输入用户名"})
另外一种判断用户名是否存在的写法:
from sqlalchemy.sql import exists
username_exists = session.query(
exists().where(User_Register.username == username1)
).scalar()
if username1 in username_list:
3、完成一个userlist接口,以指定格式返回用户名和密码:
'''定义userlist接口,返回所有username和password'''
@app.route('/register/userlist',methods = ['get'])
def user_list():
getdata = session.query(User_Register.username,User_Register.password).all()
print(getdata)
return str(getdata)
1、返回多个列,直接加逗号就可以了
2、这里最好处理成json格式,或者其他指定格式,但是我还不会写,格式转换不太会
至此服务端接口全部设置完成。其他客户端的操作不要写在服务端的脚本中了。
4、随机生成一百组数据,并写入到数据库中:
import random
import string
import requests
def auto_register(username_auto,password_auto):
postdata ={"username":username_auto,"password":password_auto}
response=requests.post("http://localhost:8080/register",data=postdata)
print (1)
print(response.text)
return response
for i in range(100):
username_auto = ''.join([random.choice(string.ascii_uppercase +string.ascii_lowercase+ string.digits) for n in range(10)])
password_auto = ''.join([random.choice(string.ascii_uppercase +string.ascii_lowercase+ string.digits) for n in range(10)])
print (username_auto,password_auto)
auto_register(username_auto,password_auto)
注意:
1、命名中的循环有点问题,还不太会写。这个用户名和密码都固定为10位大小写字母和数字了。
2、这里没有去重处理,也还不太会写。
3、response是相应,response.text才是响应获取的内容。
4、response.text 返回的是一个 unicode 型的文本数据,response.content 返回的是 bytes 型的二进制数据。如果想取文本数据可以通过response.text 如果想取图片、文件,则可以通过 response.content。
5、string.ascii_uppercase +string.ascii_lowercase+ string.digits分别表示大写字母、小写字母和数字
5、将userlist接口中的数据下载到本地
'''将userlist接口中的数据下载到本地'''
def user_down():
response = requests.get("http://localhost:8080/register/userlist")
with open("XXX本地的绝对路径/user_list.txt","w") as f:
f.write(str(response.text))
print(response.text)
user_down()
这里也是还没有进行格式转换
6、清空本地数据库:
'''清空数据库'''
def delete_sql():
list = session.query(User_Register).all()
session.delete(list)
session.commit()
delete_sql()
写是这样写,但是运行后没有作用,最后还是手动清空的。
7、读取本地生成的文件,将文件中记录的用户名和密码批量重新注册在数据库中。
'''读取文件,批量注册'''
def auto_register():
with open("XXX本地的绝对路径/user_list.txt","r") as f:
contents=f.read()
print(contents)
print(type(contents))
c=[]
c=eval(contents)
print(c)
print(type(c))
for i in c:
username_txt=i[0]
print(username_txt)
password_txt=i[1]
print(password_txt)
userdata = {"username": username_txt, "password": password_txt}
response = requests.post("http://localhost:8080/register", data=userdata)
return response
auto_register()
注意:
1、eval()函数就是把字符串转换成列表/元组/字典,看上去想什么就能转成什么,对应的是str(),把其他的转成字符串。不过eval函数不安全。
2、要把字符串转换成列表才方便取值,不然第一个值是{、(之类的
这样就完成啦。
第一个python小练习,很多东西都不会,还遗留了很多问题,只是勉强完成了需求。先记录在这里,以后再修改。