期末作品检查

 

1.个人学期总结

      Python语言近些年越来越火,其特点是开发迅速,语法简单,可移植等。Python是一门面向对象的解释性语言(脚本语言),这一类语言的特点就是不用编译,程序在运行的过程中,由对应的解释器向CPU进行翻译,个人理解就是一边编译一边执行。而JAVA这一类语言是需要预先编译的。没有编译最大的痛苦就是无法进行断点调试,唯一的办法就是在有疑问的地方打印各个变量的值来进行调试。这一类语言也没用类型,也就是说一个变量即可能是int型,但是也可能是String型,而且可以随时变化。 

       Python对于代码格式要求也相当严格,通过对于缩进的距离来判断代码是否处于同一个代码块。这样做的好处在于代码编写看上去很统一。Python Web开发框架常用的包括Django,Flask,Tornado,Bottle等。Django功能比较全面,比较重,相对来说,Flask更加轻巧,适合新手学习和上手。Flask是一个基于Python的web框架,它的设计目的是提供Web开发所需的最小功能子集。Flask与别的框架(尤其是采用其他编程语言的框架)的不同之处在于:它没有绑定诸如数据库查询或者表单处理等功能库,以及它们所组成的整个生态系统。它倾向于对这些功能的实现方式不做任何限定。

本学期在老师的带领下,首先进行了一些python的基础练习,比如学习turtle库;条件、循环、函数的相关定义;字符串的基本操作;中英文词频统计的实例等。然后,开始学习做项目的前期准备工作,比如认识URL,观察常用网站网址,区分不同组成部分;学习HTML基础,练习使用标签制作简单的页面;结合实例,学习css样式的制作;学习JavaScript基础。接下来,就是开始做Flask项目了。

2.总结Python+Flask+MysqL的web建设技术过程

本学期实现了Python+Flask+Mysql的web建设技术的过程,以下是详细解析该技术的实现过程。

(1)父模板的制作

     制作网站网页共有元素的父模板html,包括顶部导航,中间区块划分,底部导航,底部说明等;汇总相关的样式形成独立的css文件;汇总相关的js代码形成独立的js文件;形成完整的base.html+css+js文件模式。

html

<body>
<div class="dhl" >
<div>
                <img src="http://p5.so.qhimgs1.com/bdr/_240_/t0121d7bb41fe5c36bb.jpg" width="100" height="70" >
                <a class="dhg" href="{{ url_for('index') }}">首页</a>
        {% if username %}
        <a class="dll" href="{{url_for('usercenter',user_id = session.get('userid'),tag=1)}}">{{ session.get('user') }}</a>
        <a class="dll" href="{{ url_for('logout') }}">注销</a>
      {% else %}
        <a class="dll" href="{{ url_for('ll') }}">登录</a>
        <a class="dll" href="{{ url_for('zc') }}">注册</a>
      {% endif %}
             <a class="dll" href="{{ url_for('question') }}" >问答</a>
    </div>
           <form action="{{url_for('search')}}" method="get" >

                    <input name="q" type="text" cols="40" rows="1" class="soua" placeholder="请输入关键字">

                    <button type="submit" class="soub">查找</button>
                </form>
</div>
<div>
    <nav>
          <div class="hs">
              <a href="">联系我们·</a>
              <a href="">加入我们·</a>
               <a href="">帮助中心</a>
              <p>版权 @ whl</p>
    </nav>
</div>

css

body{
    background-image: url(../imges/mao.jpg);
    background-size:cover;

}
.dll{
    margin-top:10px;
    color:black;
    text-decoration:none;
    font-weight:bold;
    float:right;
    font-family: "宋体";
    font-size: xx-large;
        }
.dhg{
    margin-top:120px;
    color:#C0C0C0;
    text-decoration:none;
    font-weight:bold;
    font-family: "隶书";
    font-size:xx-large;
        }
.dhl{
    background-color: #FFFAFA;
}
 .hs {
     width: 100%;
     height: 60px;
     color:#008080;
     background-color:none;
     position: fixed;
     bottom: 0; /**距离底部为0*/
     left: 41%;
     z-index: 1;
 }

js

 function myswitch() {
            var oBody = document.getElementById("myBody");
            var oOnoff = document.getElementById("myOnOff");
            if(oOnoff.src.match("bulbon")){
                oOnoff.src="http://www.runoob.com/images/pic_bulboff.gif";
                oBody.style.background="black";
                oBody.style.color ="white";
            }else{
                oOnoff.src="http://www.runoob.com/images/pic_bulbon.gif";
                oBody.style.background="white";
                oBody.style.color ="black";
            }
        }

 (2)登录注册页面

1.完成登录与注册页面的HTML+CSS+JS,其中的输入项检查包括:1.用户名6-12位;2.首字母不能是数字;3.只能包含字母和数字;4.密码6-12位;5.注册页两次密码是否一致。

登录页面html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
    <link href="../static/ll.css" rel="stylesheet" type="text/css">
    <script src="../static/ll.js"></script>

</head>

<body>
 <div class="box">
     <h2 class="d">登录</h2>
     <div class="input_box">
            <input style="background-color: deepskyblue;" id="uname" type="text" placeholder="请输入用户名">
        </div>
        <br>
        <div class="input_box">
            <input style="background-color: deepskyblue;" id="upass" type="password" placeholder="请输入密码">
        </div>
        <br>
        <div id="error_box"><br></div>
        <div class="input_box">
            <button class="dl" onclick="fnLogin()">enter</button>

        </div>
        <br>
    </div>
</div>
</body>
</html>

登录页面js

function fnLogin() {
        var oUname=document.getElementById("uname")
        var oUpass=document.getElementById("upass");
        var oError=document.getElementById("error_box")
        oError.innerHTML="<br>"
        if(oUname.value.length<6|| oUname.value.length > 20){
            oError.innerHTML="用户名至少6-20位"
            return;
        }else if((oUname.value.charCodeAt(0)>=48) && (oUname.value.charCodeAt(0)<=57)){
            oError.innerHTML="first.number."
            return;
        }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;
            }
        }
        if(oUpass.value.length<6|| oUpass.value.length > 20){
            oError.innerHTML="密码至少6-20位"
            return;
        }
        if((oUname.value.length < 6 || oUname.value.length > 20) && (oUpass.value.length < 6 || oUpass.value.length > 20)){
            oError.innerHTML="用户名密码至少6-20位"
            return;
        }
        window.alert("登录成功!")
    }

注册页面html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册</title>
    <link href="../static/ll.css" rel="stylesheet" type="text/css">


</head>

<body>
 <div class="box">
     <h2 class="d">注册</h2>
     <div class="input_box">
            <input style="background-color: deepskyblue;" id="uname" type="text" placeholder="请输入你的昵称">
        </div>
        <br>
     <div class="input_box">
            <input style="background-color: deepskyblue;" id="uname" type="text" placeholder="请输入你的密码">
        </div>
        <br>
        <div class="input_box">
            <input style="background-color: deepskyblue;" id="upass" type="password" placeholder="请再输入密码">
        </div>
        <br>
        <div id="error_box"><br></div>
        <div class="input_box">
            <button class="dl" onclick="fnLogin()">注册</button>

        </div>
        <br>
    </div>
</div>
</body>
</html

注册页面js

function tnlogin() {
    var oUname = document.getElementById("uname")
    var oError = document.getElementById("error_box")
    var oUpass = document.getElementById("upass")
    var oUpass1 = document.getElementById("upass1")

    oError.innerHTML = "<br>"
    if (oUname.value.length < 6 || oUname.value.length > 20) {
        oError.innerHTML = "用户名必须在6-20之间";
        return;
    } else if ((oUname.value.charCodeAt(0) >= 48) && (oUname.value.charCodeAt(0) <= 57)) {
        oError.innerHTML = "首字母不能为数字";
        return;
    } 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 = "只能填写数字或字母";
            return;
        }
    }
    // oUpass
    if (oUpass.value.length > 20 || oUpass.value.length < 6) {
        oError.innerHTML = "密码必须在6-20之间";
        return;
    } else if (oUpass.value!= oUpass1.value) {
        oError.innerHTML = "两次密码不一致"
        return;
    }
    window.alert("注册成功!")
}

登录和注册页面的css

.d
{ font-size: 22px;
    padding-left: 40px;
    background:none;
    margin-right: 20px;
    color: #9932CC    ;
}
.box{
 align-content: center;
    background-color:#BBFFEE;height:250px;width:400px;float:left;
    text-align: center;
    vertical-align: middle;
    position: absolute;
    top: 50%;
    left: 50%;
    margin: -150px 0 0 -150px;
    border: 1px solid #ccc;
    width: 340px;

}
.input_box{
   width: 325px;
    height: 40px;
    padding-left: 5px;
    padding-right: 5px;
 border: 1px #BBFFEE solid;
    border-radius: 4px;
    background: none;
    line-height: 40px;
    font-size: 14px;
    color: #6699FF;
    vertical-align: middle;

}
.dl
{
text-align: center;
    color: #9932CC;
    background: deepskyblue;
    width: 50%;
    padding: 9px 18px;
    font-size: 18px;
    border: none;
    border-radius: 25px;
    cursor: pointer;
}
.body {
    background-color: burlywood;
}

2.登录和注册界面

 

(3)连接mysql数据库,创建用户模型。

1.在mysq中l创建数据库

 

2.数据库配置信息,创建config.py文件

import os
DEBUG=True
SQLALCHEMY_DATABASE_URI='mysql+pymysql://root:123456@127.0.0.1:3306/misdb?charset=utf8'
SQLALCHEMY_TRACK_MODIFICATTONS = False
SECRET_KEY=os.urandom(24)

3.建立mysql和app的连接

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import config

app = Flask(__name__)
app.config.from_object(config)
db = SQLAlchemy(app)

4.创建用户模型

class User(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    username = db.Column(db.String(20),nullable=False)
    password = db.Column(db.String(20),nullable=False)
db.create_all()

(4)完成登录功能

1.在主py文件定义注册和登录的视图函数。

登录按钮和注册按钮都得返回onclick="return myLogin(),return myregister()。    从flask中导入session、设置secret_key、操作字典一样操作session增加用户名`session['username']=`username。

//登录
@app.route('/ll/',methods=['GET','POST']) def ll(): if request.method=='GET': return render_template('ll.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'error username or password' //注册 @app.route('/zc/',methods=['GET','POST']) def zc(): if request.method=='GET': return render_template('zc.html') else: username=request.form.get('username') password=request.form.get('password') user = User.query.filter(User.username==username).first() if user: return u'username existed' else: user = User(username=username, password= password) db.session.add(user) db.session.commit() return redirect(url_for('ll'))

2.登录之后更新导航

制作首页显示列表。

{% if username %}
        <a href="#">{{ username }}</a>
        <a href="{{ url_for('logout') }}">注销</a>
    {% else %}
        <a href="{{ url_for('login') }}">登录</a>
        <a href="{{ url_for('regist') }}">注册</a>

在主py文件中定义登出的视图函数。

@app.context_processor
def mycontent():
    usern=session.get('user')
    if usern:
        return{
            'username':usern
        }
    else:
        return{}

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

3.注销功能界面

 

(5)完成发布问答功能及其详情页。

1.问答html页面

<form action="{{ url_for('wd') }}" method="post">
<div class="label">
    <h1 >发布问答</h1>
        <div class="form-group">
            <label for="question">标题</label>
            <textarea id="question" cols="40" rows="1" placeholder="请输入标题" name='title'></textarea>
        </div>
        <div class="form-group">
            <label for="questionDetail">内容</label>
            <textarea class="form-control" id="questionDetail" cols="50" rows="5" placeholder="请输入内容" name='detail'></textarea>
        </div>
       <br>
        <div class="input-area">
            <button onclick="fnQuestion">发布问答</button>
        </div>
    </div>
</body>
</html>
</form>

2.编写要求登录的装饰器,完成发布函数。

def loginFirst(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        if session.get('user'):
            return func(*args, **kwargs)
        else:
            return redirect(url_for('ll'))
    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'))

3.建立发布内容的对象关系映射

class Question(db.Model):
    __tablename__='wd'
    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'))
    author=db.relationship('User',backref=db.backref('wd'))
db.create_all()

4.问答详情页html

<body>
<div class="post">

<h3 class="title ">{{ques.title}}<br><small>{{ ques.author.username }}<span>{{ ques.create_time }} </span>  </small></h3>
</div>
    <p style="color: #333;">{{ ques.detail }}</p>
    <hr>
    <form action="{{ url_for('comment') }}"method="post">
    <div class="new-comment">
        <textarea name="new_comment" id="new-comment" cols="85" rows="5" placeholder="write your comment"></textarea>
        <input name="question_id" type="hidden" value="{{ ques.id }}" />
    </div>
    <button class="btn-send" type="submit">发送</button>
    </form>

<h4>评论:({{ ques.comment | length }})</h4>
 <ul class="list">
       {% for foo in ques.comments %}
       <li class="post_item">
           <a href="{{ url_for('usercenter',user_id=ques.author.id,tag=1) }}" class="light">{{foo.author.username }}</a>
           <br>
           <p class="post_item">{{ foo.detail }}</p>
           <span class="foot">发布于  {{ foo.create_time }}</span>
       </li>
       <hr>

5.定义详情页视图函数。

主PY文件写视图函数,带id参数。 

@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)

6.问答页及其详情页的界面

 

(6)首页列表显示全部问答,完成问答详情页布局

1.首页列表显示全部问答

{% extends 'base.html' %}
{% block title %}
首页
{% endblock %}
{% block head %}
   <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/index.css') }}">

{#    <p>{{ user }}context</p>#}
{% endblock %}

{% block main %}
  <img width="150" height="100" class="pfs" src="https://img3.doubanio.com/lpic/s7625404.jpg" alt="">
  <ul class="list-group">
        {% for foo in wd %}
            <li class="list-group-item">
                <span class="glyphicon glyphicon-leaf" aria-hidden="true"></span>
                <a href="{{ url_for('detail',question_id = foo.id)}}">{{foo.title}}</a>
                <p style="">{{foo.detail}}</p>
                 <span class="glyphicon glyphicon-user" aria-hidden="true"></span>
                <a href="{{url_for('userconter',user_id = foo.author_id)}}">{{foo.author.username}}评论:({{foo.comments length}})</a>
                <span class="badge">{{foo.creat_time}}</span>

            </li>

  </ul>


{% endblock %}

2.在首页点击问答标题,链接到相应详情页

@app.route('/')
def base():
    context={
        'questions': Question.query.all()
    }
    return render_template('home.html',**context)

3.首页界面

 

(7)完成评论功能。

1.建立评论的对象关系映射

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'))
    create_time = db.Column(db.DateTime, default=datetime.now)
    detail = db.Column(db.Text, nullable=False)
    question = db.relationship('Question', backref=db.backref('comments'))
    author = db.relationship('User', backref=db.backref('comments'))
db.create_all()

2.定义评论的视图函数,读取前端页面数据,保存到数据库中。

@app.route('/comment/',methods=['POST'])
@loginFirst
def comment():
        comment = request.form.get('new_comment')
        ques_id = request.form.get('question_id')
        auth_id = User.query.filter(User.username == session.get('user')).first().id
        comm = Comment( detail=comment, question_id=ques_id,author_id=auth_id)
        db.session.add(comm)
        db.session.commit()
        return redirect(url_for('detail',question_id = ques_id))

3.尝试实现详情页面下的评论列表显示

<h4>评论:({{ ques.comment | length }})</h4>
 <ul class="list">
       {% for foo in ques.comments %}
       <li class="post_item">
           <a href="#" class="light">{{foo.author.username }}</a>
           <br>
           <p class="post_item">{{ foo.detail }}</p>
           <span class="foot">发布于  {{ foo.create_time }}</span>
       </li>
       <hr>

4.评论列表显示界面

 

(8)完成个人中心的页面布局

1.定义视图函数def usercenter(user_id)

@app.route('/usercenter/<user_id>/<tag>')
@loginFirst
def usercenter(user_id,tag):
    user=User.query.filter(User.id==user_id).first()
    context={
        'questions': user.question,
        'comments': user.comments,
        'user':user

    }
    if tag == '1':
        return render_template('usercenter1.html',**context)
    elif tag == '2':
        return render_template('usercenter2.html',**context)
    else:
         return render_template('usercenter3.html',**context)

2.个人中心html

{% extends'base.html' %}
{% block title %}个人中心 {% endblock %}
{% block head %}
<link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/detail.css') }}">
    <style>
        .nav_ul li{
            float: left;
            list-style: none;
            margin: 10px;
            border-bottom: outset;
        }
    </style>
{% endblock  %}
{% block main %}
    <h3 class="title"><span class="glyphicon glyphicon-user" aria-hidden="true"></span>{{ user.username }}</h3>
<ul class="nav_ul">
    <li role="presentation" class="active"><a href="{{ url_for('usercenter',user_id=user.id,tag= 1) }}" class="current_nav">全部问答</a> </li>
    <li role="presentation"><a href="{{ url_for('usercenter',user_id=user.id,tag = 2) }}" class="current_nav">全部评论</a> </li>
    <li role="presentation"><a href="{{ url_for('usercenter',user_id=user.id,tag = 3) }}" class="current_nav">个人信息</a> </li>
</ul>
    {% block user %}{% endblock %}
{% endblock %}

3.新页面userbase.html,用<ul ><li role="presentation"> 实现标签页导航。


{% extends "base.html" %}
{% block title %}个人中心{% endblock %}
{% block head %}
    <style>
        .nav_ul li{
            list-style: none;
            float: left;
            margin: 10px;
        }
    </style>
{% endblock %}

{% block main %}
<ul class="nav_ul">
    <li role="presentation"><a href="{{url_for'usercenter',user_id = user.id }}">questions</a> </li>
    <li role="presentation"><a href="#">comments</a> </li>
    <li role="presentation"><a href="#">information</a> </li>
</ul>

{% block user %}{% endblock %}

{% endblock %}
 

4.实现点标签页导航到达不同的个人中心子页面

usercenter1.html
{% extends'usercenter.html' %} {% block user %}
<div class="post"> <ul class="list"> {% for foo in questions %} <li class="post_item"> <p class="post_item">标题:{{ foo.title }}</p> <p class="post_item">内容:{{ foo.detail }}</p> <span class="foot">发布于 {{ foo.create_time }}</span> </li> <hr> {% endfor %} </ul> </div> {% endblock %}



usercenter2.html
{% extends'usercenter.html' %}

{% block user %}

<div class="post">
<ul class="list">
{% for foo in comments %}
<li class="post_item">
<p class="post_item">标题:{{ foo.detail }}</p>
<p class="post_item">评论:{{ foo.detail }}</p>
<span class="foot">发布于 {{ foo.create_time }}</span>
</li>
<hr>
{% endfor %}
</ul>
</div>

{% endblock %}


usercenter3.html
{% extends'usercenter.html' %}

{% block user %}

<div class="post">
<ul class="list">
<li class="post_item">用户:{{ username }}</li>
<li class="list-group-item">编号:{{userid}}</li>
<li class="list-group-item">问答条数:{{ questions|length }}</li>
<li class="list-group-item">评论条数:{{ comments|length }}</li>
</ul>
</div>

{% endblock %}
 

5.个人中心界面

(9)完成搜索功能

1.定义视图函数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('-create_time')
    return render_template('index.html',question = ques)

2.修改base.html 中搜索输入框所在的代码

<form action="{{url_for('search')}}" method="get" class="navbar-form navbar-left">

                    <input name="q" type="text" cols="40" rows="1" class="soua" placeholder="请输入关键字">

                    <button type="submit" class="soub">查找</button>
                </form>

3.实现搜索功能界面

 

(8)密码保护

1.实现密码保护功能

更新User对象,设置对内的_password;编写对外的password;写密码验证的方法。

class User(db.Model):
    __tablename__ = 'user'
    id = 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)
    nickname = db.Column(db.String(50))
    db.create_all()

    @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

2.进行登录验证

@app.route('/ll/',methods=['GET','POST'])
def ll():
    if request.method=='GET':
        return render_template('ll.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['user']=username
            session['userid'] = user.id
            session.permanent=True
            return redirect(url_for('index'))
          else:
              return u'password error'
        else:
            return u'error username '

 

 

 

 

 

 

 

 

 



 

 





 

 

 

 

 

 

  

 

posted on 2018-01-05 16:11  020吴惠琳  阅读(270)  评论(0)    收藏  举报