代码改变世界

期末作品检

2018-01-03 15:28  055李小锐  阅读(373)  评论(0)    收藏  举报

1.总结Python+Flask+MysqL的web建设技术过程。对所学知识的梳理。对初学入门者的简单教程。作为自己以后复习的向导。一种向外展示能力的途径。

                                                                                                                                               个人学期总结

      岁月飞逝,时光如梭,很快,一个学期即将过去,在这一学期里,学习了不少关于信息管理的知识,其中很关键的一个内容就是对python语言基础的学习。之前想学python的基本知识的时候,只是在网上查找资料,看看别人博客上的内容,没有整体性的学习和深入的探讨,学的东西很凌乱。而通过本学对python基础知识的学习,发现其实python语言比起其他语言的学习要好入手很多。比如python有很库、获取数据方便、数据运算方便、表达的语句简而易懂、与其他语言交互很方便、信息处理也很方便。就如本学期所画的一个五星红旗,几个循环语句就能将其呈现在屏幕上,这是其他语言做不到的事情。

       总的来说,python语言非常简单,阅读一个良好的Python程序就感觉像是在读英语一样,尽管这个对英语的要求非常严格!Python的这种伪代码本质是它最大的优点之一。它使你能够专注于解决问题而不是去搞明白语言本身。在当今的大数据时代,更是需要这种易懂、方便学习的编程语言来处理大数据和得出最优的结论出来。但是python也有缺点,很多时候不能将程序连写成一行,如import sys;for i in sys.path:print i。而perl和awk就无此限制,可以较为方便的在shell下完成简单程序,不需要如Python一样,必须将程序写入一个主.py文件。既是优点也是缺点,python的开源性是的Python语言不能加密。总体来说,python语言还算是比较优秀的,吸引的人才多,项目也多。而本学期就实现了Python+Flask+Mysql的web建设技术的过程,以下是详细解析该技术的实现过程。

具备python基本知识之后,就可以编写web基础

1、先是认识URL,观察常用网址,因为一个网址里面有不同的组成成分,可以利用h标签来编辑不同文本,可以用div来修饰文本样式。用img标签将图片上传至网页,用a标签可以对文字或图片添加链接

<body>

<h1>MIS问答平台</h1>
<h3>数学</h3>
<h6>语文</h6>
<p>英语</p>
<hr>

<P>友情链接</P>
  <a href="http://www.gzcc.cn/">广州商学院
      <br>
      <img src="http://www.gzcc.cn/2016/images/banner.png" width="258" height="39" alt="gzcc.cn"/></a>
</body>

2、对于一个网址,里面有下拉列表选择框,无序列表,有序列表,可以分别通过select标签嵌套option标签、ul标签嵌套li标签、ol标签嵌套li标签的方法来实现该功能,需要注意的是select标签外需要增加一个form表单,from表单可以向后台传递数据

<from>
    <select>
        <option>问答</option>
        <option>提问</option>
        <option>收藏</option>
    </select>


</from>
    <ul>
        <li>教师常用表格</li>
        <li>学生常用表格</li>
        <li>教学管理表格</li>
        <li>教学管理文件</li>
        <li>参考资料</li>

    </ul>
    <ol>
        <li>教师常用表格</li>
        <li>学生常用表格</li>
        <li>教学管理表格</li>
        <li>教学管理文件</li>
        <li>参考资料</li>
    </ol>>

3、<base>可以定义页面链接标签的默认链接地址。<style>定义html文档的样式文件<link>定义一个文档和外部资源之间的关系。而且这三个部分均要放入head里面。可以用url_for加载静态文件<script src="{{ url_for('static',filename='js/login.js') }}"></script>,flask从static文件夹开始寻找,可用于加载css,js,imag文件

<head>
    <meta charset="UTF-8">
    <title>MISS</title>
    <base href="http://i1.sinaimg.cn/dy/weather/main/index14/007/icons_32_yl/"target="_blank">
    <link rel="stylesheet" type="text/css" href="T5.css">
    <style type="text/css">
        p{
            color:darkcyan;font-size: 10px;
        }
        .textblue{
            color:blue;
            text-decoration: underline;
        }
    
    </style>

</head>

4、继承和扩展:把一些公共的代码放在父模板中,避免每个模板写同样的内容。子模板的继承:每个字模板都要有继承语句 {% extends 'base.html’ %},子模板位置及名称{% block title %}{% endblock %}   {% block head %}{% endblock %}       {% block main %}{% endblock %}每个部分部分根据自己的需求增加内容。数据库配置信息config.py

 


SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:@127.0.0.1:3306/mis_db?charset=utf8'
SQLALCHEMY_TRACK_MODIFICATIONS = False
 

5、登录与注册功能:

新建Flask项目,使用Flask中render_template,用不同的路径,返回首页、登录员、注册页,用视图函数反转得到URL,{{url_for(‘login’)}},完成导航条里的链接,登录输入框中用户名必须在6-12位,首字母不是数字,整个用户名只能是数字,密码控制在6-12位,注册的时候还要判断输入的两次密码是否一致。登录按钮和注册按钮都得返回onclick="return myLogin(),return myregister()。    从flask中导入session、设置secret_key、操作字典一样操作session增加用户名`session['username']=`username。在主py文件定义注册和登录的视图函数。

.注册js

function myLogin() {
        var oUname = document.getElementById("uname");
        var oError = document.getElementById("error_box");
        var opassword = document.getElementById("upass");
        var ophone = document.getElementById("phone");
        var ocpassword=document.getElementById("cpassword");

        oError.innerHTML=="<br>";

         if(oUname.value.length<6||oUname.value.length>12){
                oError.innerHTML="number of uname6-12";
                return false;
            }
         else if((oUname.value.charCodeAt(0) >= 48) && (oUname.value.charCodeAt(0)<= 57)){
                oError.innerHTML = "first number";
               return false;
            }
          else for(var i=0; i<oUname.value.length;i++){
             if((oUname.value.charCodeAt(i)<48||oUname.value.charCodeAt(i)>57)&&(oUname.value.charCodeAt(i)<97||oUname.value.charCodeAt(i)>122)){
               oError.innerHTML="only letter or number";
                     return false;
             }
            }
         if(ophone.value.length<11||ophone.value.length>11){
                oError.innerHTML="number of phone11";
                return false;
             }
         if(opassword.value.length<6||opassword.value.length>12){
                oError.innerHTML="number of password6-12";
                     return false;
           }
         else if (opassword.value!=ocpassword.value){
        oError.innerHTML="cpassword error";
                return false;
         }
              return true;
         window.alert("注册成功")
         }

登录js

 function myLogin() {
        var oUname = document.getElementById("uname");
        var oError = document.getElementById("error_box");
        var opassword = document.getElementById("upass");
        var isError=true;
        oError.innerHTML="<br>";


         if(oUname.value.length<6||oUname.value.length>12){
                oError.innerHTML="number of uname6-12";
                isError=false;
                return isError;
            }
         else if((oUname.value.charCodeAt(0) >= 48) && (oUname.value.charCodeAt(0)<= 57)){
                oError.innerHTML = "first number";
                isError=false;
                return isError;
            }
          else for(var i=0; i<oUname.value.length;i++){
             if((oUname.value.charCodeAt(i)<48||oUname.value.charCodeAt(i)>57)&&(oUname.value.charCodeAt(i)<97||oUname.value.charCodeAt(i)>122)){
               oError.innerHTML="only letter or number";
                isError=false;
                return isError;
             }

             }
         if(opassword.value.length<6||opassword.value.length>12){
                oError.innerHTML="number of password6-12";
                isError=false;
                return isError;
           }
           return isError;
            window.alert("登录成功!")
         }

@app.route('/zhuce/', methods=['GET','POST'])
def zhuce():
    if request.method == 'GET':
        return render_template('zhuce.html')
    else:
        username = request.form.get('username')
        nickname = request.form.get('nickname')
        phone = request.form.get('phone')
        password = request.form.get('password')
        user = User.query.filter(User.username == username).first()
        if user:
            return 'username existed'
        else:
            user = User(username=username, password=password, nickname=nickname, phone=phone)
            db.session.add(user)
            db.session.commit()
            return redirect(url_for('login'))

@app.route('/login/', methods=['GET','POST'])
def login():
    if request.method == 'GET':
        return render_template('login.html')
    else:
        username = request.form.get('username')
        password1 = request.form.get('password')
        user = User.query.filter(User.username == username).first()
        if user:
            if user.check_password(password1):
                session['user'] = username
                session['userid'] = user.id
                session.permanent=True
                return redirect(url_for('index'))
            else:
                return u'password error'
        else:
            return u'username is not existed'

6、新建python与数据库的连接,可以对数据库进行增删改操作

from flask_sqlalchemy import SQLAlchemy
import config

app = Flask(__name__)
app.config.from_object(config)
#增加
user=User(username='mis1234',password='111111')
db.session.add(user)
db.session.commit()
#删除
user = User.query.filter(User.username == 'mis1234').first()
db.session.delete(user)
db.session.commit()
#修改
user = User.query.filter(User.username=='mis114').first()
user.password='499679642'
db.session.commit()
#查询
user = User.query.filter(User.username == 'mis1234').first()
print(user.id,user.password)

7、用上下文处理器app_context_processor定义函数、获取session中保存的值,返回字典。注销功能:消除session,跳转至首页。但是对于发布问题的功能,发布前需要登录,则需要编写要求登录的装饰器。def loginFirst(func): #参数是函数,登录后可以发布,在question装饰器调用@loginFist函即可。发布问题时,需要建立发布内容的对象关系映射 class Question(db.Model):跟注册用户一样的写法。

登录装饰器

def login_re(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        if session.get('user'):
            return func(*args,**kwargs)
        else:
            return redirect(url_for('login'))
    return wrapper

发布视图函数

@app.route('/question/',methods=['GET','POST'])
@loginFirst
def question():
    if request.method == 'GET':
        return render_template('question.html')
    else:
        title = request.form.get('title')
        detail = request.form.get('detail')
        author_id = User.query.filter(User.username == session.get('user')).first().id
        question = Question(title=title, detail=detail, author_id=author_id)
        db.session.add(question)
        db.session.commit()
    return redirect(url_for('index'))

注销

@app.route('/logout/')
def logout():
    session.clear()
    return  redirect(url_for('index'))

发布问答

8、对于首页显示的全部问答,可以通过数据库查询结果传递到前端页面Question.query.all(),前端页面循环显示整个list,问答按发布时间排序。问答的详情布局包括问答的全部信息、评论区、以往评论内容。在首页点击问答可以标题,可以跳转至相应的详情<a href="{{url_for('detail')}}" class="title">{{ foo.title }}</a>。{{ ques.title}}{{ ques.id  }}{{  ques.creat_time }}      {{ ques.author.username }}   {{ ques.detail }}在详情页将数据的像是在恰当的位置。定义评论关系,为后续的发布评论做铺垫

首页获取问答的代码

<p1>Answer Information</p1>
    <br><br>
{% for foo in questions %}
<li class="list-group-item" >
    <span class="glyphicon glyphicon-align-leaf" aria-hidden="true"></span>
<img  src="{{ url_for('static',filename='images/touxiang.png') }}"  alt="lz" width="20px" style="border-radius: 80px;">{{ foo.author.username }}<br>
    <a href="{{url_for('detail',question_id=foo.id)}}">{{ foo.title }}</a>

    <span class="badge" style="margin-left: 60%">{{ foo.creat_time }}</span>

<p style="text-indent: 18px">{{ foo.detail }}</p>
    <img  src="{{ url_for('static',filename='images/dianzhan.png') }}" alt="lz" width="20px" style="border-radius: 20%;">12
     <img  src="{{ url_for('static',filename='images/yuedu.png') }}" alt="lz" width="20px"style="margin-left: 2%;border-radius: 20%;">86
<span style="margin-left:4%">评论:({{ foo.comments|length }})</span>
</li>
{% endfor %}

问答详情页

<p1>Comment Information</p1>
<li class="list-group-item">
<h3>{{ ques.title}}<br>{{ ques.detail }}<br>
    <img  src="{{ url_for('static',filename='images/touxiang.png') }}"  alt="lz" width="20px" style="border-radius: 80px;"><small>{{ ques.author.username }}<span class="badge">{{ ques.creat_time }}</span> </small></h3>

    <hr>

    <form action="{{url_for('comment')}}" method="post">
    <div class="form-group">
        <textarea name="new_comment" class="form-control" rows="3" id="new_comment" placeholder="评论内容" name="detail"></textarea>
        <input name="question_id" type="hidden" value="{{ ques.id }}"/>
    </div>
    <button type="submit" class="btn btn-default">发送</button>
    </form>
    <hr>
    评论:({{ ques.comments|length }})

    {% for foo in ques.comments %}
    <li class="list-group-item">
    <span class="glyphicon glyphicon-align-leaf" aria-hidden="true"></span>
        <img  src="{{ url_for('static',filename='images/touxiang.png') }}"  alt="lz" width="20px" style="border-radius: 80px;">
    <a href="{{ url_for('usercenter',user_id=foo.author.id,tag=1) }}">{{ foo.author.username }}</a>
    <span class="badge">{{ foo.creat_time }}</span>
    <p>{{ foo.detail }}</p>
</li></li>

{% endfor %}
</ul>

定义详情页视图函数

@app.route('/detail/<question_id>')#详情页
def detail(question_id):
    quest=Question.query.filter(Question.id==question_id).first()
    return render_template('detail.html',ques=quest)

定义评论的映射关系

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'))
   detail=db.Column(db.DateTime,default=datetime.now)
   question=db.relationship('Question',backref=db.backref('comments',order_by=creat_time.desc))
   author=db.relationship('User',backref=db.backref('comments'))

9、定义评论的视图函数@app.route('/comment/',methods=['POST'],读取前端页面数据,并存入数据库中。此外,用<input type="hidden" 方法获取前端的"question_id" ,可以用于显示评论次数。

详情页下显示评论的代码。

{% for foo in ques.comments %}
    <li class="list-group-item">
    <span class="glyphicon glyphicon-align-leaf" aria-hidden="true"></span>
        <img  src="{{ url_for('static',filename='images/touxiang.png') }}"  alt="lz" width="20px" style="border-radius: 80px;">
    <a href="{{ url_for('usercenter',user_id=foo.author.id,tag=1) }}">{{ foo.author.username }}</a>
    <span class="badge">{{ foo.creat_time }}</span>
    <p>{{ foo.detail }}</p>

 10、完成个人中心的页面布局、定义视图函数def usercenter(user_id):,向前段页面传递参数、页面显示相应数据,其中包括发布问答的全部问答、发布的全部评论、发布者的个人信息。新页面userbase.html,用<ul ><li role="presentation"> 实现标签页导航,让userbase.html继承base.html,重写title,head,main块。原个人中心就自动有了标签页导航。制作个人中心的三个子页面,重写userbase.html中定义的user块,分别用于显示问答、评论、个人信息。标签页导航到达不同的个人中心子页面。个人中心视图函数带标签页面参数tag,个人中心导航标签链接增加tag参数,个人中心有链接到个人中心的url增加tag参数。

个人中心视图函数

@app.route('/usercenter/<user_id>/<tag>')#个人中心
@login_re
def usercenter(user_id,tag):
    user=User.query.filter(User.id==user_id).first()
    context={
         'user':user
    }
    if tag=='1':
        return render_template('user1.html',**context)
    elif tag=='2':
        return render_template('user2.html', **context)
    else:
        return render_template('user3.html', **context)

usercenter.html

{% extends 'userbase.html' %}

{% block head %}
    <link rel="stylesheet" href="{{ url_for('static',filename='css/userbase.css') }}" >
    <script src="{{ url_for('static',filename='js/usercenter.js') }}" type="text/javascript"></script>
{% endblock %}


<ul class="list-group " style="width: 50%; margin:0 auto">
{% block user %}


<br>
  <h3>{{ username }}<br>全部问答</h3>

{% for foo in user.question %}
<li class="list-group-item">
    <span class="glyphicon glyphicon-align-leaf" aria-hidden="true"></span>
    <a href="#">{{ foo.author.username }}</a>
    <br>
    <span class="badge" style="margin-left: 60%">{{ foo.creat_time }}</span>

<p style="text-indent: 18px">{{ foo.detail }}</p>
</li>
{% endfor %}
<hr>
   <h3>全部评论</h3>


    {% for foo in user.comments %}
    <li class="list-group-item">
    <span class="glyphicon glyphicon-align-leaf" aria-hidden="true"></span>
    <a href="#">{{ foo.author.username }}</a>

    <span class="badge">{{ foo.creat_time }}</span>
    <p>{{ foo.detail }}</p>
</li>
{% endfor %}

    <hr>
    <h3>个人信息</h3>

    <span class="glyphicon glyphicon-align-leaf" aria-hidden="true"></span>
    <li class="list-group-item">用户:{{user.username}}<br>
                                   编号:{{user.id}}<br>
                                   昵称:{{user.nickname}}<br>
                                   文章篇数:{{ user.question|length }}<br>
                                   评论数:{{ user.comments|length }}
</li>


</ul>

userbase.html

{% extends 'base.html' %}
{% block title %}Infobase{% endblock %}
{% block head %}

    <link rel="stylesheet" href="{{ url_for('static',filename='css/userbase.css') }}" >
    <script src="{{ url_for('static',filename='js/userbase.js') }}" type="text/javascript"></script>

{% endblock %}

{% block main %}
<ul class="list-group " style="width: 50%; margin:3rem auto">

<ul class="nav_ul ">
    <lia role="presentation"><a href="{{ url_for('usercenter',user_id=user.id,tag='1') }}">Questions</a> </lia>
    <lia role="presentation"><a href="{{ url_for('usercenter',user_id=user.id,tag='2') }}">Comments</a> </lia>
    <lia role="presentation"><a href="{{ url_for('usercenter',user_id=user.id,tag='3') }}">Info</a> </lia>
</ul>

{% block user %}{% endblock %}
</ul>
{% endblock %}

user1.html,user2.html,user3.html原理相同,只需把main里面的传递内容修改一下即可,下面是user1.html的代码

{% extends 'userbase.html' %}

    <link rel="stylesheet" href="{{ url_for('static',filename='css/usercenter.css') }}" >
    <script src="{{ url_for('static',filename='js/usercenter.js') }}" type="text/javascript"></script>

{% block user %}

<br><br>
  <h3>{{ username }}全部问答</h3>
{% for foo in user.question %}
<li class="list-group-item">
    <span class="glyphicon glyphicon-align-leaf" aria-hidden="true"></span>
    <img  src="{{ url_for('static',filename='images/touxiang.png') }}"  alt="lz" width="20px" style="border-radius: 80px;">
    <a href="#">{{ foo.author.username }}</a>
   <p style="text-indent: 18px">{{ foo.title }}</p>
<p style="text-indent: 18px">{{ foo.detail }}</p>
     <img  src="{{ url_for('static',filename='images/dianzhan.png') }}" alt="lz" width="20px" style="border-radius: 20%;">23
     <img  src="{{ url_for('static',filename='images/yuedu.png') }}" alt="lz" width="20px"style="margin-left: 2%;border-radius: 20%;">66
    <span class="badge" style="margin-left: 60%">{{ foo.creat_time }}</span>
</li>
{% endfor %}

{% endblock %}

 

 

11、准备视图函数search(),增加base.html中搜索输入框的action="{{ url_for('search') }}  按钮增加name=“q”,视图函数需要获取搜索关键字、增加条件查询、加载查询结果。return render_template('index.html', question=qu)。

search视图函数

@app.route('/search/')
def search():
    qu=request.args.get('q')
    ques=Question.query.filter(
        or_(
            Question.title.contains(qu),
            Question.detail.contains(qu)
         )
    ).order_by('-creat_time')
    return render_template('index.html',questions=ques)

12、密码保护功能实现步骤:更新user对象,设置对内的_password,编写对外的password,密码验证、登录验证

内置对内的_password:
    _password = db.Column(db.String(200), nullable=False) #内部使用

编写对外的passoword:

from werkzeug.security import generate_password_hash, check_password_hash

    @property

    def password(self):  #外部使用,取值

        return self._password

@password.setter

    def password(self, row_password):#外部使用,赋值

        self._password = generate_password_hash(row_password)

密码验证:
 def check_password(self, row_password): #密码验证

        result = check_password_hash(self._password,row_password)

        return result

登录验证:
        password1 = request.form.get('password')

        user = User.query.filter(User.username == username).first()

        if user:

            if user.check_password(password1):