1 系统概要说明
1.1开发目的
如今音乐已经成为人们尤其是年轻人的日常必备。走路,坐车,逛街,我们都能看到戴着耳机听音乐的人。古风曲、日韩风、欧美风、hippop等等各种音乐风格多样。随着媒体的发展,微博微信公众号媒体采访等等的发展,人们对音乐的理解也开始不只是限于听,越来越多的人开始了解歌曲背后的含义的故事。每首歌曲背后都有着不一样的情感和故事,每首歌都代表着不一样的经历和成长。总有歌曲里似乎有着我们的身影和故事,在某个瞬间已是如同曲中人。
发现歌曲背后的故事,聊聊属于我们的感受和想法,分享藏着我们记忆和故事的那些歌。在音乐的世界中,放松自己,了解自己,也学会好好爱自己和珍惜身边的人。
2 网站结构设计
1.网站允许不登录的游客访问,游客可以在网站首页查看网站用户发布的相关帖子,可以查看音乐榜单,但是只能看当前页的帖子,不可以过页查看,并且不允许评论和发布帖子。
2.网站用户先注册后登录,注册需要填写不少于3字符的用户名、设置密码;注册后可用用户名和密码登录。密码错误或者用户名错误都无法登录。
3.网站用户登录后,导航栏会显示用户名,用户如若需要下线或者切换帐号可以注销帐号重新登录。
4.网站用户登录后,可以查看网站用户发布的所有帖子,可以进行评论、点赞和收藏,网站也会根据浏览记录推荐相关的帖子。
5.网站用户登录后,可以浏览自己发布过的帖子,发过的评论和查看自己的个人信息,也可以重新修改头像和密码。
6.网站访问者可以通过网站右侧的分类浏览需要的类别帖子,也可以通过搜索关键词浏览帖子,网站也会将热度前五的帖子标题显示在左侧方便浏览。
3.模块详细设计
导航栏(父模版):
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>{% block title %}{% endblock %}Music世界</title>{% block link %}{% endblock %}<link rel="stylesheet" href="http://cdn.static.runoob.com/libs/bootstrap/3.3.7/css/bootstrap.min.css"><script src="https://cdn.bootcss.com/jquery/2.1.1/jquery.min.js"></script><script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script><link rel="stylesheet" type="text/css" href="../static/css/base.css">{% block head %}{% endblock %} </head> <body id="body"> <nav class="navbar navbar-default" role="navigation"><div class="container-fluid dao"><ul class="nav nav-pills nav2"><li><img src="{{ url_for('static',filename='image/logo.png') }}" style="margin-left: 20px;" ></li><li class="active"><a href="{{ url_for('index') }}">首页</a></li><li><a href="#">音乐分享</a></li><li><a href="#">音乐榜单</a></li><li><a href="#">我的音乐</a></li><li><a href="#">音悦世界</a></li><li><a href="{{ url_for('question') }}">发帖</a></li>{% if user_id %}<li style="float: right;margin-right: 100px"><a href="{{ url_for('logout') }}">注销</a></li><li style="float: right"><a href="{{ url_for('comment',user_id=user.id,num='1') }}">{{ user.username }}</a></li>{% else %}<li style="float: right;margin-right: 150px"><a href="{{ url_for('regist') }}" style="color: hotpink">注册</a></li><li style="float: right"><a href="{{ url_for('login') }}">登录</a></li>{% endif %}<div ><form action="{{ url_for('search') }}" method="get" class="bs-example bs-example-form" role="form"><div class="col-lg-6" style="width: 250px;padding-bottom: 30px"><div class="input-group"><input name="q" type="text" class="form-control" style="margin-top: 0" placeholder="请输入关键字"><span class="input-group-btn"><button class="btn btn-default" type="submit">搜索</button></span></div><!-- /input-group --></div><!-- /.col-lg-6 --></form> </div></ul></div></nav><div class="box">{% block box %}{% endblock %} </div> {% block script %}{% endblock %} </body> </html>
首页:
{% extends 'base.html' %} {% block title %}首页 {% endblock %}{% block link %} <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/shouye.css') }}"><script src="https://cdn.bootcss.com/jquery/2.1.1/jquery.min.js"></script><script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> {% endblock %}{% block box %}<div ><div class="col-md-2 column"></div><div style="margin-left: 150px;"><ul class="list-group">{% for foo in questions %}<div class="info"><li class="list-group-item" style="width: 800px"><a href="{{ url_for('comment',user_id=foo.author.id ,num='1') }}" target="_blank"><img src="{{ url_for('static',filename=foo.author.icon) }}" width="50px"></a><a href="{{ url_for('comment',user_id=foo.author.id ,num='1') }}" style="color: #337ab7"target="_blank">{{ foo.author.username }}</a><h4><a href="{{ url_for('detail',question_id=foo.id) }}">{{ foo.title }}</a></h4><span class="badge">{{ foo.creat_time }}</span><p style="">{{ foo.detail[0:50] }}...</p><div><strong>浏览:<small>{{ foo.look }}</small></strong><strong> 分类:{{ foo.cfClass.name }}</strong><strong style="padding-left: 10px;"> 点赞:{{ foo.click }}</strong></div></li></div>{% endfor %}</ul><div style="width: 200px;float: right;margin-right: 80px;margin-top:-900px;text-align: center"><a href="#" class="list-group-item " style="background-color: #337ab7;color: #fff" >帖子分类</a>{% for c in cf %}<a href="{{ url_for('c',cf=c.id) }}" class="list-group-item">{{ c.name }}</a>{% endfor %}</div></div><div class="flo"><a href="#" class="list-group-item" style="width: 200px;background-color: #337ab7;color: #fff;text-align: center;">热门推荐</a>{% for q in hot %}<a href="{{ url_for('detail',question_id=q.id) }}" class="list-group-item" style="width: 200px;"><span style="font-size: 16px;color: red;padding-right: 10px;width:105px;">{{ loop.index }}</span>{{ q.title }}</a>{% endfor %}</div></div> </div>{% endblock %}{% block script %}<script>{% if info %}alert('{{ info }}'){% endif %}</script> {% endblock %}
注册:
{% extends 'base.html' %} {% block title %}注册 {% endblock %}{% block link %}<link rel="stylesheet" type="text/css" href="../static/css/style.css"><link href='http://fonts.googleapis.com/css?family=Oleo+Script' rel='stylesheet' type='text/css'> {% endblock %}{% block box %}<div class="lg-container"><h1 style="color:deeppink;">注册</h1><form action="{{ url_for('regist') }}" method="post" id="lg-form" name="lg-form" ><div><label for="username">Username:</label><input class="shuru" type="text" name="username" autocomplete="off" placeholder="请输入用户名"></div><div><label for="password">Password:</label><input class="shuru" type="password" id="Password1" name="password" autocomplete="off" placeholder="设置密码" ></div><div><label for="password">Password1:</label><input class="shuru" type="password" id="Password2" name="password" autocomplete="off" placeholder="确认密码" ></div><div id="error_box"></div><button type="submit" id="regist" οnclick="return aaa()">注册</button></form></div>{% endblock %}{% block script %}<script>function aaa() {var p1 = document.getElementById('Password1')var p2 = document.getElementById('Password2')if (p1.value != p2.value){alert('两次密码不一样!')return false;}return true;}</script> {% endblock %}
登录:
{% extends 'base.html' %} {% block title %}登录 {% endblock %}{% block link %}<link rel="stylesheet" type="text/css" href="../static/css/style.css"><link href='http://fonts.googleapis.com/css?family=Oleo+Script' rel='stylesheet' type='text/css'> {% endblock %}{% block box %}<div class="lg-container" ><h1 style="color:deeppink;">登录</h1><form action="{{ url_for('login') }}" method="post" id="lg-form" name="lg-form" ><div><label for="username">Username:</label><input class="shuru" id="inputEmail3" type="text" name="username" placeholder="请输入用户名"><br></div><div><label for="password">Password:</label><input class="shuru" id="inputPassword3" type="password" name="password" placeholder="请输入密码" ></div><input type="checkbox" name="vehicle" value="true" ><span>记住密码</span><a class="right" href="">登录遇到问题?</a><div id="error_box"></div><button type="submit" value="login" id="login" οnclick="return fnLogin()">登录</button></form><div id="message"></div> </div> {% endblock %}
发布帖子:
{% extends 'base.html' %} {% block title %}发布问答 {% endblock %}<link rel="stylesheet" type="text/css" href="../static/css/release.css"> <script src="https://cdn.bootcss.com/jquery/2.1.1/jquery.min.js"></script><script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>{% block box %}<div class="container" style="background-image: url(/static/image/back.jpg);width: 500px" ><div class="row clearfix"><div class="col-md-4 column"></div><div class="col-md-4 column"></div><div class="lg-container"><h1 align="center" style="color: salmon">发布帖子</h1><form role="form" action="{{ url_for('question') }}" method="post"><br/><div class="q"><label for="inputEmail3">标题</label><br><input type="text" name="author_id" value="{{ user.id }}" hidden><textarea id="title" name="title" class="form-control" cols="80" rows="1"></textarea></div><div class="form-group"><label for="name">内容</label><br> {# <textarea class="form-control" id="questionDetail" name="questionDetail" cols="60" rows="5" ></textarea>#}<textarea placeholder="详情" class="form-control" rows="5" id="detail" name="detail" style="width: 500px"></textarea></div><div class="form-group" style="margin-left:-115px"><div class="col-sm-offset-2 col-sm-5"><select name="cf" id="" class="form-control"><option value="">--选择分类--</option>{% for c in cf %}<option value="{{ c.id }}">{{ c.name }}</option>{% endfor %}</select></div></div><br><div style="margin-top: 30px"><button type="submit" class="btn btn-primary" οnclick="{{ url_for('question') }}" >发布</button></div></form></div><div class="col-md-4 column"></div></div> </div>{% endblock %}
帖子详情:
{% extends 'base.html' %} {% block title %}帖子详情 {% endblock %}{% block link %} <link rel="stylesheet" href="../static/css/detail.css"><script src="https://cdn.bootcss.com/jquery/2.1.1/jquery.min.js"></script><script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> {% endblock %}{% block box %}<div class="container"><div class="row clearfix"><div class="col-md-2 column"></div><div class="col-md-8 column"><h3>{{ ques.title }}</h3><div style="padding: 10px;"><span style="padding-left: 5px;">作者:{{ ques.author.username }}</span><span style="padding-left: 10px;">浏览:{{ ques.look }}</span><span style="padding-left: 10px;">点赞:{{ ques.click }}</span><form method="post" style="display: inline-block;padding-left: 10px;"><input name="click" value="1" type="hidden"><button>点赞</button></form><form method="post" style="display: inline-block;padding-left: 10px;"><input name="collection" value="1" type="hidden">{% if col %}<button type="button" disabled>已收藏</button>{% else %}<button>收藏</button>{% endif %}</form><br><small class="badge">时间:{{ ques.creat_time }}</small></div><div style="padding: 20px 20px;margin-bottom: 50px;border:1px solid #eee;"><p>{{ ques.detail }}</p></div><hr><form class="form-horizontal" role="form" method="post" action="{{ url_for('answer') }}" style="margin-left: 0"><div class="form-group"><label for="inputEmail3" class="col-sm-2 control-label" style="text-align: left;font-size: medium;color: #337ab7;">评论</label><br><div class="col-sm-10" style="margin-left:7px"><input type="text" name="author_id" value="{{ user.id }}" hidden><input type="text" name="question_id" value="{{ ques.id }}" hidden><textarea class="form-control" name="detail" rows="10" placeholder="发表评论"></textarea></div></div><div class="form-group"><div class="col-sm-offset-2 col-sm-10" style="margin-left:7px"><button type="submit" class="btn btn-default">发布</button></div></div></form><hr><h4>用户评论</h4>{% for com in comment %}<ul style="padding-left: 0;margin-bottom: 0;"><li class="list-group-item" style="width: 900px"><a href="#">{{ com.author.username }}</a><span class="badge">评论时间:{{ com.creat_time }}</span><p>{{ com.detail }}</p></li></ul>{% endfor %}<hr><div ><h3>推荐帖子</h3><br>{% for foo in questions %}<li class="list-group-item" style="width: 700px"><a class="wrap-img" href="#" target="_blank"><img src="{{ url_for('static',filename=foo.author.icon) }}" width="50px"></a><span class="glyphicon glyphicon-left" aria-hidden="true"></span><a href="{{ url_for('comment',user_id=foo.author.id ,num='1') }}"target="_blank">{{ foo.author.username }}</a><br><a href="{{ url_for('detail',question_id=foo.id) }}">{{ foo.title }}</a><span class="badge">{{ foo.creat_time }}</span><p style="">{{ foo.detail[0:50] }}...</p></li>{% endfor %}</div></div><div class="col-md-2 column"></div></div></div> {% endblock %}
个人发帖:
{% extends 'comment.html' %} {% block head %}<link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/geren.css') }}"><script src="https://cdn.bootcss.com/jquery/2.1.1/jquery.min.js"></script><script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> {% endblock %} {% block subComment %}<ul class="list-group" style=""><h4>{{username }}<small> 全部帖子</h4><hr>{% for foo in questions %}<li class="list-group-item" style="width: 800px"><a class="wrap-img" href="#" target="_blank"><img src="{{ url_for('static',filename=foo.author.icon) }}" width="50px"></a><span class="glyphicon glyphicon-left" aria-hidden="true"></span><a href="{{ url_for('comment',user_id=foo.author.id ,num='1')}}"target="_blank">{{ foo.author.username }}</a><br><a href="{{ url_for('detail',question_id=foo.id) }}">{{ foo.title }}</a><span class="badge">{{ foo.creat_time }}</span><p style="">{{ foo.detail[0:50] }}...</p></li>{% endfor %}</ul> </div> {% endblock %}
个人评论:
{% extends 'comment.html' %}{% block head %}<link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/geren.css') }}"><script src="https://cdn.bootcss.com/jquery/2.1.1/jquery.min.js"></script><script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>{% endblock %} {% block subComment %}<div><h4>{{ username }}<small> 全部评论</small></h4><hr>{% for com in comment %}<ul style="padding-left: 0;margin-bottom: 0;"><li class="list-group-item" style="width: 900px"><a href="#">{{ com.author.username }}</a><span class="badge">评论时间:{{ com.creat_time }}</span><p>{{ com.detail }}</p></li></ul>{% endfor %}</div> {% endblock %}
个人资料:
{% extends 'comment.html' %} {% block head %}<link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/geren.css') }}"><script src="https://cdn.bootcss.com/jquery/2.1.1/jquery.min.js"></script><script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> {% endblock %} {% block subComment %}<div ><h4>{{ username }}<small> 个人资料</small></h4><hr><a href="#" class="list-group-item " style="background-color: pink">用户:{{ user.username }}</a> {# <a href="#" class="list-group-item" style="background-color: pink">编号:{{ user.id }}</a>#}<a href="#" class="list-group-item" style="background-color: pink">昵称:{{user.user.name}} </a><a href="#" class="list-group-item " style="background-color: pink">帖子数:{{ questions|length }}</a><a href="#" class="list-group-item " style="background-color: pink">评论数:{{ comment|length }}</a></div> {% endblock %}
修改信息:
% extends 'base.html' %} {% block title %}个人信息修改 {% endblock %}{% block box %}<div class="container" style="padding-top: 10px;"><h2 align="center" style="color: salmon">修改信息</h2><div class="row clearfix"><div class="col-md-2 column"></div><div class="col-md-8 column"><h4 style="color: red">头像上传</h4><div style="margin: 5px 0px;margin-left: 70px;"><form class="form-horizontal" role="form" method="post" enctype="multipart/form-data" action="{{ url_for('uploadLogo',user_id=user_id) }}" style="padding-top: 20px"><div class="form-group"><div class="col-sm-10"><input type="file" id="exampleInputFile" name="logo" required><button type="submit" class="btn btn-default">上传头像</button><img src="{{ url_for('static',filename=user.icon) }}" width="100px"/></div></div></form></div><h4 style="color: red">修改密码</h4><form class="form-horizontal" role="form" method="post" style="width: 500px;padding-top: 20px"> {# <div class="form-group" >#} {# <label for="inputEmail3" class="col-sm-2 control-label">原密码</label>#} {# <div class="col-sm-10">#} {# <input type="password" name="old" class="form-control" id="p1" disabled/>#} {# </div>#} {# </div>#}<div class="form-group"><label for="inputPassword3" class="col-sm-2 control-label">新密码</label><div class="col-sm-10"><input type="password" name="new1" class="form-control" id="p2" required/></div></div><div class="form-group"><label for="inputPassword3" class="col-sm-2 control-label">确认密码</label><div class="col-sm-10"><input type="password" class="form-control" id="p3" required/></div></div><div class="form-group"><div class="col-sm-offset-2 col-sm-10"><button type="submit" class="btn btn-success" οnclick="return f()">确认修改</button></div></div></form></div><div class="col-md-2 column"></div></div></div>{% endblock %}{% block script %}<script>function f() {if ($('#p2').val() == $('#p3').val())return true;alert('密码不一样');return false;}</script> {% endblock %}
4.数据库设计
设计5个数据表分别为:
1.User表:用于存储用户注册的用户数据
class User(db.Model):__tablename__ = 'user'# 建立一个表userid = db.Column(db.Integer, primary_key=True, autoincrement=True)username = db.Column(db.String(20), nullable=False)_password = db.Column(db.String(200), nullable=False)say = db.Column(db.String(50))icon = db.Column(db.String(50))collection = db.relationship('Question', secondary=Collection, backref=db.backref('user', lazy='dynamic'),lazy='dynamic')
2.Question表:用于存储用户发布帖子的数据,包括帖子的标题、内容、发贴时间、发帖用户、类别、点赞数和浏览量
class Question(db.Model):__tablename__ = 'question'id = db.Column(db.Integer, primary_key=True, autoincrement=True)title = db.Column(db.String(100), nullable=False)detail = db.Column(db.Text, nullable=False)creat_time = db.Column(db.DateTime, default=datetime.now)author_id = db.Column(db.Integer, db.ForeignKey('user.id'))cf = db.Column(db.Integer, db.ForeignKey('cf.id'))look = db.Column(db.Integer)click = db.Column(db.Integer)author = db.relationship('User', backref=db.backref('question'))cfClass = db.relationship('Cf', backref=db.backref('question'))
3.Comment表:用于存储用户的评论数据,包括评论内容、评论时间、评论的用户、评论的帖子
class Comment(db.Model):__tablename__ = 'comment'id = db.Column(db.Integer, primary_key=True, autoincrement=True)author_id = db.Column(db.Integer, db.ForeignKey('user.id'))question_id = db.Column(db.Integer, db.ForeignKey('question.id'))creat_time = db.Column(db.DateTime, default=datetime.now())detail = db.Column(db.TEXT, nullable=False)question = db.relationship('Question', backref=db.backref('comment'))author = db.relationship('User', backref=db.backref('comment', order_by=creat_time.desc))
4.Cf表:识别和存储帖子的类型
class Cf(db.Model):__tablname__ = 'cf'id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(30)) context = db.Column(db.TEXT)
5.Collection表:存储对应用户收藏的帖子
Collection = db.Table('collection',db.Column('id', db.Integer, primary_key=True, autoincrement=True)db.Column('book_id', db.Integer, db.ForeignKey('question.id'))
db.Column('collection', db.Integer, db.ForeignKey('user.id'))db.Column('createdate', db.DATETIME) )
5.系统展示的关键算法与数据结构
1.登录注册:
@app.route('/login/', methods=['GET', 'POST']) def login():if request.method == 'GET':return render_template('login.html')else:username = request.form.get('username')password = request.form.get('password')user = User.query.filter(User.username == username).first()if user:if user.check_password(password):session['username'] = user.usernamesession['user_id'] = user.idsession.permanent = True# 重新定位到首页return redirect(url_for('index'))else:# 重新定位到注册return '用户不存在或密码错误'else:return redirect(url_for('login'))# 注册 @app.route('/register/', methods=['GET', 'POST']) def regist():if request.method == 'GET':return render_template('regist.html')else:username = request.form.get('username')password = request.form.get('password')user = User.query.filter(User.username == username).first()if user:return "账号已存在"else:user = User(username=username, password=password)db.session.add(user)db.session.commit()return redirect(url_for('login'))
2.发布帖子:
@app.route('/question', methods=['GET', 'POST']) @loginFirst def question():if request.method == 'GET':cf = Cf.query.all()return render_template('question.html', cf=cf)else:title = request.form.get('title')detail = request.form.get('detail')# author_id = request.form.get('author_id')author_id = User.query.filter(User.username == session.get('username')).first().idcf = request.form.get('cf')question = Question(title=title, detail=detail, author_id=author_id, cf=cf)db.session.add(question) # 加入数据库 db.session.commit()return redirect(url_for('index'))
3.详情页跳转:
@app.route('/detail/<question_id>', methods=['GET', 'POST']) # @loginFirst def detail(question_id):quest = Question.query.filter(Question.id == question_id).first()u = User.query.filter(User.id == session.get('user_id')).first()if request.method == 'POST':if request.form.get('click') == '1':quest.click = quest.click + 1if request.form.get('collection') == '1':user = uuser.collection.append(quest)db.session.add(user)col = u.collection.filter_by(id=question_id).first()if col is None:col = {}comment = Comment.query.filter(Comment.question_id == question_id).order_by('-creat_time').all()quest.look = quest.look + 1content = {'ques': quest,'comment': comment,'col': col,'questions': Question.query.filter(Question.cf == quest.cf).all(),}return render_template('detail.html',**content)
4.发表评论:
@app.route('/answer/', methods=['GET', 'POST']) def answer():if request.method == 'POST':question_id = request.form.get('question_id')author_id = request.form.get('author_id')detail = request.form.get('detail')comment = Comment(question_id=question_id, author_id=author_id, detail=detail)db.session.add(comment)db.session.commit()return redirect(url_for('detail', question_id=question_id))
5.搜索:
@app.route('/search') def search():qu = request.args.get('q')c = '' if request.args.get('c') == '' else request.args.get('c')y = '' if request.args.get('y') == '' else request.args.get('y')query = Question.query.filter(or_(Question.title.contains(qu),Question.detail.contains(qu),),Question.cf.like('%' + c + '%'),Question.creat_time.like('%' + y + '%'),).order_by('-creat_time').all()context = {'questions': query,'cf': Cf.query.all(),'hot': Question.query.order_by('-click').all()[0:5]}return render_template('index.html', **context)
6.上传头像:
@app.route('/uploadLogo/<user_id>', methods=['GET', 'POST']) def uploadLogo(user_id):user = User.query.filter(User.id == user_id).first()f = request.files['logo']basepath = os.path.dirname(__file__) upload_path = os.path.join(basepath, 'static/uploads', f.filename) f.save(upload_path)user.icon = 'uploads/' + f.filenamedb.session.commit()return redirect(url_for('setPassword', id=user_id))
6.成品展示
1.首页
(未登录)
(已登录)
2.登录
3.注册
4.搜索
5.分类
6.发布帖子
7.帖子详情
8.收藏
9.评论
10.个人帖子
11.个人评论
12.个人信息
13.修改信息