前两天在帮一哥们做一个往数据库加数据的页面,基于python Flask框架。
赶鸭子上架简直,之前加入的时候大言不惭的告诉那哥们会Django和Flask。
说实话,Django也就看了个基础。Flask也就这是知道一个名字。数据库也没有用过,花了一天时间到晚上一点,数据库才弄好。
又是整整一天研究了pymysql和SQLAlchemy才把python和数据库连上。
周六周日都没怎么有空,今天把代码回顾一下。
割一下--------------
需求:
必要参数(在数据库中保存的就是这样的): commodityName 商品名称 commodityPic 商品图片 考虑到一种商品会有多张图片的情况,在数据库以图片路径的形式保存, 路径格式为:/image/commodityImg/商品编号/img_图片I.jpg 多张图片路径中间以英文逗号隔开 例如/image/commodityImg/1/img_1.jpg,/image/commodityImg/1/img_2.jpg 即为第一件商品的第一张和第二张图片 briefInfo 简要信息 商品的简要信息 detailedInfo 详细信息 详细信息目前暂定也是用图片的形式来展现,所以详细信息这里也是存放图片路径的, 格式只有在图片命名上略有不同:/image/commodityImg/1/detail_1.jpg 多张图片路径中间以英文逗号隔开 例如/image/commodityImg/1/detail_1.jpg,/image/commodityImg/1/detail_2.jpg 即为第一件商品的第一张和第二张详情 price 价格 like 点赞数量(暂定) 每次填300就行了 暂定功能,以后可能会改 sex 面向人群性别 1代表男性 0代表女性 填1或0就完事了 有个地方要说一下,后台更新商品是肯定要上传图片的, 商品图片上传路径是/home/static/commodityImg/商品编号/img_商品编号.jpg 详情图片上传路径是/home/static/commodityImg/商品编号/detail_商品编号.jpg
一,数据库的安装
工具:
MySql-8.0.11,Navicat 12 for MySQL
MySQL下载地址:https://dev.mysql.com/downloads/mysql/
Navicat 12 for MySQL下载地址:https://www.navicat.com/en/download/navicat-for-mysql
MySQL的安装真是要了老命,花了N种方法N个小时。
1.下载,解压到路径
2.配置环境变量
我的电脑>>属性>>环境变量>>系统环境变量>>path,将mysql的解压路径/bin复制到变量内
3.配置文件
我下载下来的时候 是没有配置文件的,听说大部分人都没有。。
配置文件命名:my.ini
代码:
[mysqld] # 设置3306端口 port=3306 # 设置mysql的安装目录 basedir=G:mysql # 设置mysql数据库的数据的存放目录 datadir=G:mysqlin # 允许最大连接数 max_connections=200 # 允许连接失败的次数。这是为了防止有人从该主机试图攻击数据库系统 max_connect_errors=10 # 服务端使用的字符集默认为UTF8 character-set-server=utf8 # 创建新表时将使用的默认存储引擎 default-storage-engine=INNODB # 默认使用“mysql_native_password”插件认证 default_authentication_plugin=mysql_native_password [mysql] # 设置mysql客户端默认字符集 default-character-set=utf8 [client] # 设置mysql客户端连接服务端时默认使用的端口 port=3306 default-character-set=utf8
4.安装MySQL
务必使用管理员权限进入命令行
cd到安装目录的/bin
输入命令对mysql进行初始化
mysqld --initialize --console
执行结果会有一段: [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: rI5rvf5x5G,E 其中root@localhost:后面的“rI5rvf5x5G,E”就是初始密码(不含首位空格)。在没有更改密码前,需要记住这个密码,后续登录需要用到。
输入命令安装MySQL
mysqld --install [服务名]
有多个MySQL服务的话,服务名要对应相应的MySQL服务
输入命令开启MySQL服务
net start mysql
开启之后,就可以登陆数据库了
登陆数据库命令
mysql -u root -p
后面会叫你输入密码,这个时候输入刚刚的密码
更改数据库登陆密码
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '新密码';
(ps:分号一定要有,python写多了习惯了不写分号,但是数据库是不会执行命令的)
后连接Navicat 12 for MySQL,创建表即可。
二,Flask虚拟环境
我直接用的是PyCharm,可以生成Flask所需的虚拟环境。
注意一下,Flask所需要的模块,需要下载到虚拟环境的编译器文件夹内,否则会无法运行
下载方式和正常的下载模块方式一致,有路径的区别
三.Flask连接数据库
我用的是flask_sqlalchemy这个模块连接的数据库。
引入的库:
from flask_sqlalchemy import SQLAlchemy
安装方法:
虚拟环境下安装flask_sqlalchemy模块
(venv) G:commodity>pip install flask_sqlalchemy
数据库配置:
配置代码我直接写在app.py里面了,这样是不好的听说,要专门新建一个confit.py保存配置是最好的
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:111111@127.0.0.1:3306/commodity?charset=utf8' app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True app.config['SECRET_KEY'] = 'xcax0cx86x04x98@x02bx1b7x8cx88]x1bxd7"+xe6px@xc3#\'
第一行是数据库的配置文件:规范是mysql+pymysql://用户名:密码@地址:端口/数据库名?编码
第二行该配置为True,则每次请求结束都会自动commit数据库的变动
第三行是生成一个密匙,CSRF需要用到
定义模型
定义模型主要是关联数据库的表,
class Commpdity(db.Model): __tablename__ = 'commodity' commodityID = db.Column(db.Integer, primary_key=True) commodityName = db.Column(db.Text) briefInfo = db.Column(db.Text) price = db.Column(db.Float) like = db.Column(db.Integer) sex = db.Column(db.Text)
一定要有一个primary_key 的值为true,否则会报错
四.表单
引入的库
from wtforms import StringField, IntegerField, SubmitField, FloatField from wtforms.validators import DataRequired, Length, Regexp from flask_wtf import FlaskForm from flask_wtf.file import FileField
第一行是表单所引用的字段类型
第二行是表单验证所引用的验证函数。空值验证,长度验证,正则表达式验证
第三行是引入表单
第四行是文件处理所使用的模型
下面是具体的表单代码
class AddCommodity(FlaskForm): commodityName = StringField('商品名称', validators=[DataRequired(message=u'商品名不能为空'), Length(1, 60), Regexp('^[A-Za-z][A-Za-z0-9/ ]*$', 0, '商品名称只允许使用汉字,英文,数字,空格和右斜杠')]) # 商品名称 文字 briefInfo = StringField(u'商品卖点', validators=[DataRequired(message=u'商品卖点不能为空'), Length(1, 60), Regexp('^[A-Za-z][A-Za-z0-9/ ]*$', 0, '商品卖点只允许使用汉字,英文,数字,空格和右斜杠')]) # 商品卖点 文字 price = FloatField(u'商品价格', validators=[DataRequired(message=u'商品价格不能为空')]) # 价格 浮点类型 like = IntegerField(u'点赞次数', validators=[DataRequired(message=u'点赞次数不能为空')]) # 点赞 sex = IntegerField(u'面向人群', validators=[DataRequired(message=u'面向人群不能为空')]) # 选择 男或女 submit = SubmitField(u'发布商品')
五.对数据库的操作
@app.route('/', methods=['GET', 'POST']) # 路由设置 def hello_world(): form = AddCommodity() if form.validate_on_submit(): # 当表单内容提交 new_id = db.session.query(func.count(Commpdity.commodityID)).scalar() + 1 path = '/home/static/commodityImg/' + str(new_id) os.makedirs(path) filename = form.commodityPic.data.filename form.commodityPic.data.save(path + filename) commodity = Commpdity( # 数据库内容提交 commodityID=new_id, commodityName=form.commodityName.data, commodityPic=form.commodityPic.data, briefInfo=form.briefInfo.data, detailedInfo=form.detailedInfo.data, price=form.price.data, like=form.like.data, sex=form.sex.data ) db.session.add(commodity) # 保存表格数据到数据库 db.session.commit() # commit数据库 flash('商品已经成功发布') return render_template('/addcommodity.html',form=form)
六.页面
{% import "bootstrap/wtf.html" as wtf %} {% block page_content %} <div class="page-header"> <h1>发布商品</h1> </div> <div class="col-md-4"> {{ wtf.quick_form(form) }} </div> {% endblock %}
目前还没有实现的功能:
一. 上传图片功能,
虽然有办法实现,但是不知道页面和流程怎么设计
二. 图片更名
有方法实现,问题同上
具体的代码:
app.py
from flask import Flask from flask import flash, render_template from flask_sqlalchemy import SQLAlchemy from flask_bootstrap import Bootstrap from forms import AddCommodity from sqlalchemy import func import os from werkzeug import secure_filename from werkzeug.utils import secure_filename app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:111111@127.0.0.1:3306/commodity?charset=utf8' app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True app.config['SECRET_KEY'] = 'xcax0cx86x04x98@x02bx1b7x8cx88]x1bxd7"+xe6px@xc3#\' bootstrap = Bootstrap(app) db = SQLAlchemy(app) @app.route('/', methods=['GET', 'POST']) # 路由设置 def hello_world(): form = AddCommodity() if form.validate_on_submit(): # 当表单内容提交 new_id = db.session.query(func.count(Commpdity.commodityID)).scalar() + 1 path = '/home/static/commodityImg/' + str(new_id) os.makedirs(path) filename = form.commodityPic.data.filename form.commodityPic.data.save(path + filename) commodity = Commpdity( # 数据库内容提交 commodityID=new_id, commodityName=form.commodityName.data, commodityPic=form.commodityPic.data, briefInfo=form.briefInfo.data, detailedInfo=form.detailedInfo.data, price=form.price.data, like=form.like.data, sex=form.sex.data ) db.session.add(commodity) # 保存表格数据到数据库 db.session.commit() # commit数据库 flash('商品已经成功发布') return render_template('/addcommodity.html',form=form) if __name__ == '__main__': app.run(debug=True) class Commpdity(db.Model): __tablename__ = 'commodity' commodityID = db.Column(db.Integer, primary_key=True) commodityName = db.Column(db.Text) commodityPic = db.Column(db.Text) briefInfo = db.Column(db.Text) detailedInfo = db.Column(db.Integer) price = db.Column(db.Float) like = db.Column(db.Integer) sex = db.Column(db.Text)
forms.py
from wtforms import StringField, IntegerField, SubmitField, FloatField from wtforms.validators import DataRequired, Length, Regexp from flask_wtf import FlaskForm from flask_wtf.file import FileField class AddCommodity(FlaskForm): commodityName = StringField('商品名称', validators=[DataRequired(message=u'商品名不能为空'), Length(1, 60), Regexp('^[A-Za-z][A-Za-z0-9/ ]*$', 0, '商品名称只允许使用汉字,英文,数字,空格和右斜杠')]) # 商品名称 文字 commodityPic = FileField(u'商品主图') # 商品主图 图片文件 briefInfo = StringField(u'商品卖点', validators=[DataRequired(message=u'商品卖点不能为空'), Length(1, 60), Regexp('^[A-Za-z][A-Za-z0-9/ ]*$', 0, '商品卖点只允许使用汉字,英文,数字,空格和右斜杠')]) # 商品卖点 文字 detailedInfo = FileField(u'上传商品详情',) # 详细介绍 图片文件 price = FloatField(u'商品价格', validators=[DataRequired(message=u'商品价格不能为空')]) # 价格 浮点类型 like = IntegerField(u'点赞次数', validators=[DataRequired(message=u'点赞次数不能为空')]) # 点赞 sex = IntegerField(u'面向人群', validators=[DataRequired(message=u'面向人群不能为空')]) # 选择框 男或女 submit = SubmitField(u'发布商品')
addcommodity.html
{% import "bootstrap/wtf.html" as wtf %} {% block page_content %} <div class="page-header"> <h1>发布商品</h1> </div> <div class="col-md-4"> {{ wtf.quick_form(form) }} </div> {% endblock %}