一、项目选择
- 继续沿用Python+Flask+MysqL的web建设技术,开发一个网站
- 网站主题根据个人兴趣与特长自由选择
- 此项目属于个人项目,每个同学独立完成,和其他同学不一样
二、项目要求
- 整个网站风格统一,布局合理,尽量美观。
- 作品必须完成:
- 网站父模板统一布局:头部导航条、底部图片导航、中间主显示区域布局
- 注册、登录、注销
- 发布、列表显示
- 详情页
- 评论、列表显示
- 个人中心
- 搜索,条件组合搜索
- 文章分类、显示
- 点赞、收藏
- 修改密码、头像、上传头像
- 我的发布、点赞、收藏、评论
- 高级搜索
- 热门文章、推荐文章
- 参考网站:http://bbs.xiaomi.cn/
A.系统概要说明
这个网站我做的是有关文学论坛的系统,基于Python+Flask+MysqL的web建设技术,在上学期学习的基础上进行完善,虽然不算完美,但是对Python有了更进一步的了解,做起来更得心应手。
Python优点:
1.“优雅”、“明确”、“简单”
这是python的定位,使得python程序看上去简单易懂,初学者容易入门,学习成本更低。但随着学习的不但深入,python一样可以满足胜任复杂场景的开发需求。引用一个说法,Python的哲学是就是简单优雅,尽量写容易看明白的代码,尽量写少的代码。
2. 开发效率高
python作为一种高级语言,具有丰富的第三方库,官方库中也有相应的功能模块支持,覆盖了网络、文件、GUI、数据库、文本等大量内容。因此开发者无需事必躬亲,遇到主流的功能需求时可以直接调用,在基础库的基础上施展拳脚,可以节省你很多功力和时间成本,大大降低开发周期。
3. 无需关注底层细节
Python作为一种高级开发语言,在编程时无需关注底层细节(如内存管理等)。
4. 功能强大
Python是一种前端后端通吃的综合性语言,功能强大,php能胜任的角色它都能做,至于后端如何胜任,需要在后续学习中逐步领悟。
5. 可移植性
Python可以在多种主流的平台上运行,开发程序时只要绕开对系统平台的依赖性,则可以在无需修改的前提下运行在多种系统平台上,具体有待后续学习中深入展开。其他优点有待继续发掘。
Python缺点:
1. 代码运行速度慢
因为Python是一种高级开发语言,不像c语言一样可以深入底层硬件最大程度上挖掘榨取硬件的性能,因此它的运行速度要远远慢于c语言。另外一个原因是,Python是解释型语言,你的代码在执行时会一行一行地翻译成CPU能理解的机器码,这个翻译过程非常耗时,所以很慢。而C程序是运行前直接编译成CPU能执行的机器码,所以非常快。
但需要注意的是,这种慢对于不需要追求硬件高性能的应用场合来讲根本不是问题,因为它们比较的数量级根本不是用户能直观感受到的!想想程序执行所需的时间数量级?例如开发一个下载MP3的网络应用程序,C程序的运行时间需要0.001秒,而Python程序的运行时间需要0.1秒,慢了100倍,但由于网络更慢,需要等待1秒,用户体验几乎没有差别,除非你用非常精确的计时器来计时。
2. 发布程序时必须公开源代码
什么?有没有搞错?是的,发布程序时我们必须公开源代码!还是因为Python是一种解释性语言,没有编译打包的过程(据说最新的python可以打包,但本质上还是把源代码和解释器打在一起,没有太大实际意义)。想想我们的shell脚本是不是也是这个情况,你能在不发布源代码的情况下发布一个黑盒子程序来让别人正常使用么?
这个缺点仅限于你想单纯靠卖开发出来的软件产品挣钱的时候。但在这个开发互联的时代,不靠卖产品本身来赚钱的商业模式越来越主流了,所以问题也不是没法解决。
B.网站结构设计
网站的结构设计是体现内容设计与创意设计的关键环节,在内容设计完成之后,网站的目标及内容主题等有关问题已经确定。结构设计要做的事情就是如何将内容划分为清晰合理的层次体系,比如栏目的划分及其关系、网页的层次及其关系、链接的路径设置、功能在网页上的分配等等,以上这些都仅仅是前台结构设计,而前台结构设计的实现需要强大的后台支撑,后台也应有良好的结构设计以保证前台结构设计的实现。在我看来,根据开发量来说,Flask小巧简单易上手,同时具有强大的扩展能力,使其功能可以不弱于django、Tornado等框架,我最终选择了Flask。从 建表设计 到 浏览器前端展示 整体的结构,后台连接数据库,整体布局是否美观,都是从网站结构分析这方面出发要考虑的问题.
C.模块详细设计
模块详细设计这一方面,我是从
- 网站父模板统一布局:头部导航条、底部图片导航、中间主显示区域布局
- 注册、登录、注销
- 发布、列表显示
- 详情页
- 评论、列表显示
- 个人中心
- 搜索,条件组合搜索
- 文章分类、显示
- 点赞、收藏
- 修改密码、头像、上传头像
- 我的发布、点赞、收藏、评论
- 高级搜索
- 热门文章、推荐文章
这几方面来规划我的整个网站的,以及考虑实现功能所需的类及具体的方法函数,包括涉及到的sql语句、Python+Flask+MysqL的web建设技术等。
D.数据库设计
一直以来,在数据库库方面我掌握的不是很好,有些细节的东西我会不小心忽略。但在这一次大作业设计中,感觉自己能力有所提高,对数据库也有了更进一步的掌握。
数据库设计的设计内容包括:需求分析、概念结构设计、逻辑结构设计、物理结构设计、数据库的实施和数据库的运行和维护。
数据库设计是指对于一个给定的应用环境,构造最优的数据库模式,建立数据库及其应用系统,使之能够有效地存储数据,满足各种用户的应用需求(信息要求和处理要求)。在数据库领域内,常常把使用数据库的各类系统统称为数据库应用系统。
我们要搭建后台,与MySQL相连接,可能是由于我电脑的问题,MySQL经常自动关闭,这个时候要打开电脑的管理,去服务那里设置为自动。有时候百度能解决很多问题。
连接数据库前,要先确认以下事项:
- 已经创建了数据库 TESTDB.
- 在TESTDB数据库中您已经创建了表 EMPLOYEE
- EMPLOYEE表字段为 FIRST_NAME, LAST_NAME, AGE, SEX 和 INCOME。
- 连接数据库TESTDB使用的用户名为 "testuser" ,密码为 "test123",你可以可以自己设定或者直接使用root用户名及其密码,Mysql数据库用户授权请使用Grant命令。
- 在你的机子上已经安装了 Python MySQLdb 模块。
再者,数据库要明确步骤,需求分析、概念设计、逻辑设计、物理设计、验证设计和运行维护设计,这些都缺一不可。
from flask import Flask
from exts import db #数据库使用方法
import config #数据库连接文件
from apps.front import bp as front_bp #连接前端数据文件
E.系统实现的关键算法与数据结构
def create_app():
app = Flask(__name__)
app.config.from_object(config)
app.register_blueprint(front_bp)
db.init_app(app)
return app
if __name__ == '__main__':
app = create_app()
app.run(port=8000)
#点赞功能
@bp.route('/dianzan/',methods=['GET','POST'])
@login_required
def dianzan():
user_id=g.front_user.id
post_id=request.form.get('post_id')
dianzan=DianzanModel(user_id=user_id,post_id=post_id)
db.session.add(dianzan)
db.session.commit()
return redirect(url_for('front.post_detail',post_id=post_id))
#用户上传头像
@bp.route('/avatar/<user_id>',methods=['POST'])
@login_required
def updata_acatar(user_id):
user = FrontUser.query.filter(FrontUser.id == user_id).first()
f = request.files['img']
basepath = os.path.dirname(__file__) # 当前文件所在路径
upload_path = os.path.join('F:/godlike/static/img', f.filename) # 注意:没有的文件夹一定要先创建,不然会提示没有该路径
f.save(upload_path)
user.avatar = 'img/' + f.filename
db.session.commit()
return redirect(url_for('front.usercenter',user_id=user.id,tag=1))
F.主要代码:
#搜索功能
@bp.route('/search/')
def search():
qu = request.args.get('q')
ques = PostModel.query.filter(
and_(
PostModel.title.contains(qu)
)
).order_by('-create_time')
board_id = request.args.get('bd', type=int, default=None)
page = request.args.get(get_page_parameter(), type=int, default=1)
boards = BoardModel.query.all()
start = (page - 1) * config.PER_PAGE
end = start + config.PER_PAGE
total = 0
query_obj = PostModel.query.order_by(PostModel.create_time.desc())
if board_id:
query_obj = query_obj.filter_by(board_id=board_id)
posts = query_obj.slice(start, end)
total = query_obj.count()
else:
posts = query_obj.slice(start, end)
total = query_obj.count()
pagination = Pagination(bs_version=3, page=page, total=total, outer_window=0, inner_window=2)
context = {
'boards': boards,
'posts': ques,
'pagination': pagination,
'current_board': board_id
}
return render_template('front/front_index.html',**context)
#个人中心
@bp.route('/usercenter/<user_id>/<tag>')
@login_required
def usercenter(user_id,tag):
user = FrontUser.query.filter(FrontUser.id==user_id).first()
posts = PostModel.query.filter(PostModel.author_id == user_id).all()
context = {
'user':user,
'posts':posts
}
if tag == '1':
return render_template('front/front_usercenter.html',**context)
if tag == '2':
return render_template('front/front_user_apost.html',**context)
#点赞功能
@bp.route('/dianzan/',methods=['GET','POST'])
@login_required
def dianzan():
user_id=g.front_user.id
post_id=request.form.get('post_id')
dianzan=DianzanModel(user_id=user_id,post_id=post_id)
db.session.add(dianzan)
db.session.commit()
return redirect(url_for('front.post_detail',post_id=post_id))
#用户上传头像
@bp.route('/avatar/<user_id>',methods=['POST'])
@login_required
def updata_acatar(user_id):
user = FrontUser.query.filter(FrontUser.id == user_id).first()
f = request.files['img']
basepath = os.path.dirname(__file__) # 当前文件所在路径
upload_path = os.path.join('F:/godlike/static/img', f.filename) # 注意:没有的文件夹一定要先创建,不然会提示没有该路径
f.save(upload_path)
user.avatar = 'img/' + f.filename
db.session.commit()
return redirect(url_for('front.usercenter',user_id=user.id,tag=1))
#用户修改个人信息
@bp.route('/user_updata/<user_id>',methods=['GET','POST'])
@login_required
def user_updata(user_id):
if request.method == 'GET':
user= FrontUser.query.filter(FrontUser.id==user_id).first()
return render_template('front/front_user_updata.html',user=user)
else:
form = UserupdataForm(request.form)
if form.validate():
username = form.username.data
realname = form.realname.data
signature = request.form.get('signature')
user = g.front_user
user.username =username
user.realname = realname
user.signature = signature
db.session.commit()
return restful.success()
else:
return restful.params_error(form.get_error())
#用户修改密码
@bp.route('/resetpwd/',methods=['GET','POST'])
@login_required
def resetpwd():
if request.method == 'GET':
return render_template('front/front_resetpwd.html')
else:
form = ResetpwdForm(request.form)
if form.validate():
oldpwd = form.oldpwd.data
newpwd = form.newpwd.data
user = g.front_user
if user.check_password(oldpwd):
user.password = newpwd
db.session.commit()
# {"code":200,message=""}
# return jsonify({"code":200,"message":""})
return restful.success()
else:
return restful.params_error("旧密码错误!")
else:
return restful.params_error(form.get_error())
#注销
@bp.route('/logout/')
@login_required
def logout():
del session[config.FRONT_USER_ID]
return redirect(url_for('front.index'))
#注册功能后台视图
class SignupView(views.MethodView):
def get(self):
return_to = request.referrer
if return_to and return_to != request.url and safeutils.is_safe_url(return_to):
return render_template('front/front_signup.html',return_to=return_to)
else:
return render_template('front/front_signup.html')
def post(self):
form = SignupForm(request.form)
if form.validate():
email = form.email.data
username = form.username.data
password = form.password1.data
user = FrontUser(email=email,username=username,password=password)
db.session.add(user)
db.session.commit()
return restful.success()
else:
print(form.get_error())
return restful.params_error(message=form.get_error())
#登录功能后台视图
class SigninView(views.MethodView):
def get(self):
return_to = request.referrer
if return_to and return_to != request.url and return_to != url_for("front.signup") and safeutils.is_safe_url(
return_to):
return render_template('front/front_signin.html', return_to=return_to)
else:
return render_template('front/front_signin.html')
def post(self):
form =SigninForm(request.form)
if form.validate():
email = form.email.data
password = form.password.data
remember = form.remeber.data
user = FrontUser.query.filter_by(email=email).first()
if user and user.check_password(password):
session[config.FRONT_USER_ID]=user.id
if remember:
session.permanent= True
return restful.success()
else:
return restful.params_error(message='邮箱或密码错误!')
else:
return restful.params_error(message=form.get_error())
首页代码:
{% from "common/_macros.html" import static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
{% include "common/_heads.html" %}
<link rel="stylesheet" href="{{ static('front/css/front_base.css') }}">
<title>
{% block title %}{% endblock %}
</title>
{% block head %}{% endblock %}
</head>
<body>
<div class="banner">
<ul style="">
<li class="first"><a href="{{ url_for("front.index") }}">论坛首页</a></li>
<li class="first"><a href="{{ url_for("front.index") }}">所有文章</a></li>
<li class="first"><a href="">热门精选</a></li>
<li class="first"><a href="{{ url_for("front.apost") }}">发布帖子</a></li>
{# <!--<li class="first"><a href=""></a></li>-->#}
</ul>
<div class="banner_search">
<form action="{{ url_for('front.search') }}" method="get">
<input type="text" name="q" id="" value="" placeholder="请输入关键字"/>
<button type="submit">搜索</button>
</form>
</div>
<div class="banner_right">
{% if g.front_user %}
<span id="login-tag" data-is-login="1" style="display: none;"></span>
<a href="{{ url_for('front.usercenter',user_id=g.front_user.id,tag="1") }}">{{ g.front_user.username }}</a>
<span>or</span>
<a href="{{ url_for('front.logout') }}">注销</a>
{% else %}
<a href="{{ url_for('front.signin') }}">登录</a>
<span>or</span>
<a href="{{ url_for("front.signup") }}">注册</a>
{% endif %}
</div>
</div>
<div class="main-container">
{% block body %}{% endblock %}
</div>
</body>
</html>
帖子加精:
{% from "common/_macros.html" import static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>帖子加精</title>
<!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
{% include "common/_heads.html" %}
<script src="{{ static("front/js/jiajing.js") }}"></script>
</head>
<body>
<div style="width: 1000px; margin: 50px auto; ">
<table class="table table-bordered" style="text-align: center">
<thead>
<tr>
<th>帖子标题</th>
<th>作者</th>
<th>发布时间</th>
<th>所属板块</th>
<th>操作</th>
</tr>
</thead>
{% for foo in post %}
<tr data-id="{{ foo.id }}" data-highlight="{{ 1 if foo.highlight else 0}}">
<th><a target="_blank" href="{{ url_for("front.post_detail",post_id=foo.id) }}">{{ foo.title }}</a></th>
<th>{{ foo.author.username }}</th>
<th>{{ foo.board.name }}</th>
<th>{{ foo.create_time }}</th>
<th>
{% if foo.highlight %}
<button type="button" class="btn btn-default highlight-btn">取消加精</button>
{% else%}
<button type="button" class="btn btn-danger highlight-btn">加精</button>
{% endif %}
</th>
</tr>
{% endfor %}
</table>
</div>
</body>
</html>
G.成品展示
论坛首页:
注册页面:
格式不标准时:
登录界面:
登录成功:
:
发布帖子:
发布成功:
如果要设置帖子等级,需要数据库后台改id:
点赞和评论功能:
个人中心:
修改密码:
密码不一致时:
:
搜索帖子:
个人总结:在本学期的课程设计当中,尽管是基于上学期的知识上的改进,但还是有点不完美的。在一开始要搭建各种虚拟环境,虽然有视频教学,但大部分还是要靠自己去领悟理解。如何让页面布局更加美观,完善具体功能,如何熟练运用Python+Flask+MysqL的web建设技术,都是要靠自己去摸索领悟的。不要害怕代码报错,一步步解决才能学到更多。