期末作品检查

一、个人学期总结

   这学期刚开始接触到python,python的简洁,以及丰富的模块,广阔的应用领域吸引了我。学习python以来,觉得python还是比较简单,容易上手的,就基本语法而言,但是有些高级特性掌握起来还是有些难度,需要时间去消化。python给我最大的印象就是语法简洁,就像写伪代码一样,很多其他语言要用很多行才能实现的操作python可能几行就搞定了,这让人摆脱了繁杂的语法而专注于问题本身,这也正是我为什么不太喜欢Java的原因之一,虽然它很强大。

  刚开始学习很多疑惑,到底该如何学python,该从何下手?我回想了一下,根据自己的个人经验,总结了一下。首先,学习一门语言,语言基础很重要,我们需要了解该语言的特性,以及所有的语法规则,关键词等内容,所以,我们需要先把python基础过一遍,我建议去菜鸟教程去过一遍,这里不是广告,只是本人一般都在菜鸟官方看各种语言的编程入门。在基础学习的过程中,我建议快速的过一遍,把能理解的理解消化掉,比较难理解的不要浪费太多的时间去揣摩,因为有些语法或者特性在基础学习中根本不能很好的展示,没有实际操作单靠文字描述,是很难理解,死记硬背下来的东西不利于长期记忆和使用,所以快速浏览一遍,真正的学习放到后面的模块学习和项目实战,在模块学习和实战操作中能看到实实在在的执行效果,更利于理解。

  总的来说,这个学期学习到了这么有趣的网页制作,不过现在本人的经验还是匮乏,只是学习到简单的基础知识,还应该继续加强学习,让自己的网页布局更加美化。在这里还要感谢老师这一学期的指导,让我们了解到python的奥妙。

 

 

二、总结Python+Flask+MysqL的web建设技术过程

  1. 所需工具: pycharm64.exe + Python 3.6 64-bit + MySQL + Navicat for MySQL 
  2. 在自己所在的项目创建py文件、 html文件、css文件、js文件,如下图:

 

  (1)主py 文件所需库

from flask import Flask,render_template,request,redirect,url_for,session
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
from functools import wraps
import config
from sqlalchemy import or_
from werkzeug.security import generate_password_hash,check_password_hash

  

(2)创建数据库

A、数据库连接,创建数据库,配置链接数据库信息,建立mysql和app的连接。

    

import os

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

SECRET_KEY = os.urandom(24)
app = Flask(__name__)
app.config.from_object(config)
db = SQLAlchemy(app)

 

B、创建用户模型。

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(20))

    @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


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

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

 

C、通过用户模型,学习对数据库进行增删改查操作。

#增
user = User(username='su0001',password='123456')
db.session.add(user)
db.session.commit()

#改
user=User.query.filter(User.username=='su0002').first()
user.password='1234567'
db.session.commit()
#删
user=User.query.filter(User.username=='su0002').first()
db.session.delete(user)
db.session.commit()
#查
user=User.query.filter(User.username=='su0001').first()
print(user.id,user.password)

 #增、改                                  

                                  #删、查

 

     

  D、实现密码保护功能

 

(3)页面设计

A、网站父模板统一布局:头部导航条、底部图片导航、中间主显示区域布局

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}{% endblock %}Title</title>
    <link rel="stylesheet"type="text/css"href="{{ url_for('static',filename='css/base.css') }}">
    <script src="{{ url_for('static',filename='js/base.js') }}"></script>
    <base target="_blank" />

    {% block head %}{% endblock %}
</head>
<body background="http://p0.so.qhimgs1.com/t01d2e82c8c8f2be36c.jpg" id="myBody">
    <nav class="nav">
        <ul>
            <li><a href="{{ url_for('index') }}"><img src="../static/images/img1.png">首页</a></li>
            <li><a href=""><img src="../static/images/img2.png">下载</a></li>
            <li><a href="{{ url_for('question') }}"><img src="../static/images/img5.png">发布问答</a></li>
            <div>
                {% if user %}
                    <li><a href="{{ url_for('userbase',user_id = session.get('userid'),tag = 1) }}"><img src="../static/images/img3.png">{{ session.get('user') }}</a></li>
                    <li><a href="{{ url_for('logout') }}"><img src="../static/images/img4.png">注销</a></li>
                {% else %}
                    <li><a href="{{ url_for('login') }}"><img src="../static/images/img3.png">登录</a></li>
                    <li><a href="{{ url_for('regist') }}"><img src="../static/images/img4.png">注册</a></li>
                {% endif %}
             </div>
            <form action="{{ url_for('search') }}" method="get" class="navbar-form navbar-left">
            <img class="on_off" id="on_off" onclick="mySwitch()" src="../static/images/pic_bulbon.gif" width="50px">
            <button style="float: right;margin: 5px auto;border-radius: 5px;height: 26px" type="submit"><span class="glyphicon glyphicon-search" aria-hidden="true"></span>搜索</button>
            <input style="float: right;margin: 5px auto;border-radius: 8px;width: 200px;height: 20px;" type="text"name="q" placeholder="输入请关键字">
             </form>

        </ul>
    </nav>

<div id="bottom">
    <a href="">关于我们</a>
    <a href="">意见反馈</a>
    <a href="">安全保障</a>
</div>

<div class="copyright">
    <p>Copyright © 2017. Created by <a href="#" target="_blank">suxihong</a></p>
</div>

{% block main %}{% endblock %}
</body>
</html>

  夜间模式的开启与关闭。定义script开关切换函数,用onclick函数进行调用。

     

 

B、注册、登录、注销py文件:

  注册界面完成注册功能。在主py文件定义函数,获取form中的数据且判断用户名是否存在:存在报错,若不存在则存进数据库中,redirect重定向到登录页。

  登录界面。完成登录功能:与注册一样完成js文件,在主py文件定义函数,读取表单数据查询数据库。当用户名密码正确时,记住用户名并跳转到首页;当用户名密码不正确时,提示相应错误。同时,用session记住用户名。

#登录函数
@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 'password error'
        else:
            return 'username error'

#注册函数
@app.route('/regist/',methods=['GET','POST'])
def regist():
    if request.method == 'GET':
        return render_template('regist.html')
    else:
        username = request.form.get('username')
        nickname = request.form.get('nickname')
        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)
            db.session.add(user)
            db.session.commit()
            return  redirect(url_for('login'))

#注销函数
@app.route('/logout')
def logout():
    session.clear()
    return redirect(url_for('index'))

# 行动前需要登录,定义装饰器
def loginFirst(func):
    @wraps(func)
    def wrapper(*args,**kwargs):
        if session.get('user'):
            return func(*args,**kwargs)
        else:
            return redirect(url_for('login'))
    return wrapper

  定义JavaScript 函数,设置登录注册页面验证用户名与登录密码6-20位,注册还需包括验证用户名首字母不能是数字,只能包含字母和数字,输入的两次密码必须一致,并在各自html页面的button标签onclick调用这个函数。实现js文件,onclick函数return True时才提交表单,return False时不提交表单。

1)regist.html

{% extends 'base.html' %}
{% block title %}Regist{% endblock %}

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

{% block main %}
    <div class="box">
            <h2>注册页面</h2>
            <form action="{{ url_for('regist') }}" method="post">
            <div class="input_box">
                输入用户名: <input id="uname" type="text" placeholder="请输入用户名" name="username"></div>
                <div class="input_box">
                     昵称:<input id="unickname" type="text" placeholder="昵称" name="nickname">
        </div>
             <div class="input_box">
                 输入密码: <input id="upass" type="password" placeholder="请输入密码" name="password"></div>
                <div class="input_box">
                确认密码: <input id="checkpass" type="password" placeholder="请确认密码">
             </div>
        <div id="error_box"><br></div>
        <div class="input_box">
            <button onclick="fnRegist()">注册</button>
            <button onclick=window.alert("此页面询问您是否要离开:您输入的数据可能不会被保存")>取消</button></div>
            </form>
    </div>
{% endblock %}

  rejist.js

function fnRegist() {
    var oPass=document.getElementById("upass").value;
    var oPass1=document.getElementById("checkpass").value;

    if(oPass!=oPass1){
        document.getElementById("error_box").innerHTML="两次密码不一致!";
        return false;
    }
    return true;
}

  

2)login.html

{% extends 'base.html' %}
{% block title %}欢迎您的登录{% endblock %}

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

{% block main %}
    <div class="box">
            <h2>登录页面</h2>
            <form action="{{ url_for('login') }}" method="post">
            <div class="input_box">
               用户名: <input id="uname" name="username" type="text" placeholder="请输入用户名">
        </div>
             <div class="input_box">
                密码: <input id="upass" name="password" type="password" placeholder="请输入密码">
             </div>
        <div id="error_box"><br></div>
        <div class="input_box">
            <button onclick="return fnLogin()">登录</button>
            <button onclick=window.alert("此页面询问您是否要离开:您输入的数据可能不会被保存")>取消</button></div>
            </form>
    </div>
{% endblock %}

  

   login.js

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

    if(oUname.value.length<6||oUname.value.length>20){
        oError.innerHTML="用户名的长度:6-20位";
        isError=false;
        return isError;
    }else if((oUname.value.charCodeAt(0)>=48)&&(oUname.value.charCodeAt(0)<=57)){
        oError.innerHTML="首字母不能是数字。";
        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 = "只能包含字母或数字。";
                isNotError = false;
                return isError;
            }
        }
    }
    if (oUpass.value.length<6||oUpass.value.length>20){
        oError.innerHTML="密码的长度:6-20位";
        isError=false;
        return isError;
    }
    return isError;

}

  

  

  实现登录后更新导航:用上下文处理器app_context_processor定义函数,获取session中保存的值,返回字典。在父模板中更新导航,插入登录状态判断代码。注意用{% ... %}表示指令、{{ }}表示变量。完成注销功能:清除session并进行跳转页面。

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

        

 

C、发布、列表显示

  1)发布问答界面、编写要求登录的装饰器,定义函数将其返回。应用装饰器,要求在发布前进行登录,登录后可发布。建立发布内容的对象关系映射,完成发布函数。

@app.route('/question/',methods=['GET','POST'])
@loginFirst   # 把loginFirst放在要登录才能进入的界面中
def question():
    if request.method == 'GET':
        return render_template('question.html')
    else:
        title = request.form.get('title')
        detail = request.form.get('detail')
        user = User.query.filter(User.username == session.get('user')).first()
        author_id = user.id
        question = Question.query.filter(Question.title == title).first()
        if question:
            return 'question existed.'
        else:
            question = Question(title=title, detail=detail, author_id=author_id)
            question.author = user
            db.session.add(question)    # 数据库,添加操作
            db.session.commit()
            return redirect(url_for('index'))

  

  question.html

{% extends 'base.html' %}
{% block title %}发布问答{% endblock %}

{% block head %}
    <link rel="stylesheet" href="{{ url_for('static',filename='css/question.css')}}">
{% endblock %}

{% block main %}
    <div class="question">
    <p class="name">欢迎你,{{ user }}</p>
    <h3>发布问答</h3>
    <form class="box" action="{{ url_for('question') }}" method="post" >
        <div class="form-group">
            <label for="questionTitle">标题</label>
            <input type="text" name="title" class="form-control" id="questionTitle" placeholder="输入标题">
        </div>

        <div class="form-group">
            <label for="questionDetail">详情</label>
            <textarea name="detail" class="form-control" rows="5" id="questionDetail" placeholder="输入内容"></textarea>
        </div>

        <div class="checkbox">
            <label>
                <input type="checkbox">Check me out
            </label>
        </div>
        <button type="submit" class="btn-default">发布</button>
    </form>
     </div>
{% endblock %}

 

  

 

   2)在首页添加显示问答的列表,并定义好相应的CSS样式。首页列表显示全部问答:将数据库查询结果传递到前端页面,前端页面循环显示整个列表,进行问答排序。

@app.route('/')
def index():
    context = {
          'question': Question.query.order_by('-creat_time').all()
    }
    return render_template('index.html',**context)

  index.html

{% extends 'base.html' %}
{% block title %}首页{% endblock %}

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

{% block main %}
    <p>{{ user }}欢迎您来到首页!</p>

    <div class="list-container">
        <div id="content">
        <ul class="note-list" style="list-style: none">
            {% for foo in question %}
                <li class="note-list-item">
                    <span class="glyphion glyphion-leaf" aria-hidden="true"></span>
                    <a href="{{ url_for('detail',question_id = foo.id)}}">{{ foo.title }}</a>
                    <p style="width: 450px;"> 详情 {{ foo.detail }}</p>
                    <span class="glyphion glyphion-user" aria-hidden="true"></span>
                    <a href="{{ url_for('userbase',user_id = foo.author_id,tag = 1)}}">{{ foo.author.username }} 评论:({{ foo.comments|length }})</a>

                    <span class="badge">{{ foo.creat_time }}</span>

                </li>
            {% endfor %}
        </ul>
    </div>
</div>
{% endblock %}

 

  3)主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)

@app.route('/comment/',methods=['POST'])
@loginFirst   #把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(author_id = auth_id,question_id = ques_id,detail =comment)
    db.session.add(comm)    # 数据库,添加操作
    db.session.commit()
    return redirect(url_for('detail',question_id = ques_id))

 

  detail.html

{% extends 'base.html' %}
{% block title %}问答详情{% endblock %}

{% block head %}
<link rel="stylesheet" href="{{ url_for('static',filename='css/detail.css')}}">
{% endblock %}

{% block main %}
    <div class="detail">
        <h3 >{{ ques.title }}  <small>{{ ques.author.username }}
            <span class="badge">{{ ques.creat_time }}</span>
            </small>
        </h3>

        <p class="lead" >详情 {{ ques.detail }}</p>
    <hr>

    <form action="{{ url_for('comment') }}" method="post" class="box">
    <div class="form-group">
        <textarea name="new_comment" class="form-control" rows="5" id="new_comment" placeholder="write your comment"></textarea>
        <input name="question_id" type="hidden" value="{{ ques.id }}" />
    </div>
    <button type="submit" class="btn-default">发送</button>
     <br>

     <hr>
    <div class="form-group">
        <h4>评论:({{ ques.comments|length }})</h4>

        <ul class="list-group" style="list-style: none">
            {% for foo in ques.comments %}
                <li class="list-group-item">
                    <span class="glyphion glyphion-heart-empty" aria-hidden="true"></span>
                    <a href="{{ url_for('userbase',user_id = foo.author.id,tag = 1)}}">{{ foo.author.username }}</a>
                    <span class="badge">{{ foo.creat_time }}</span>
                    <p style="width: 450px;"> 详情 {{ foo.detail }}</p>

                </li>
            {% endfor %}
        </ul>
    </div>
    </form>
    </div>



{% endblock %}

 

 

D、个人中心:实现评论列表显示及排序。完成个人中心:个人中心的页面布局(html文件及相应的样式文件),定义视图函数向前端页面传递参数,页面显示相应数据:发布的全部问答、发布的全部评论、个人信息;各个页面链接到个人中心。

  实现标签页导航:利用嵌套继承,制作个人中心的三个子页面,重写userbase.html中定义的user块,分别用于显示问答、评论、个人信息。个人中心—视图函数、导航标签与HTML页面链接增加tag参数。

@app.route('/userbase/<user_id>/<tag>')
@loginFirst
def userbase(user_id,tag):
    user = User.query.filter(User.id == user_id).first()
    mycontext = {
        'user': user,
        #'user_name': user.username,
        #'questions': user.question,
        #'comments': user.comments
    }
    if tag == '1':
        return render_template('user1.html', **mycontext)
    elif tag == '2':
        return render_template('user2.html', **mycontext)
    else:
        return render_template('user3.html', **mycontext)

  

userbase.html

{% extends 'base.html' %}
{% block title %}个人中心{% endblock %}
{% block head %}
<link rel="stylesheet" href="{{ url_for('static',filename='css/index.css')}}">
{% endblock %}

{% block main %}
    <div id="content">
        <ul class="nav_ul" style="list-style:none;float:left">
            <li role="presentation"><a href="{{ url_for('userbase',user_id = user.id,tag = '1') }}">全部问答</a></li>
            <li role="presentation"><a href="{{ url_for('userbase',user_id = user.id,tag = '2') }}">全部评论</a></li>
            <li role="presentation"><a href="{{ url_for('userbase',user_id = user.id,tag = '3') }}">个人信息</a></li>
    </ul>
    </div>
    {% block user %}{% endblock %}
{% endblock %}

 

use1.html

{% extends 'userbase.html' %}
{% block title %}全部问答{% endblock %}
{% block head %}
<link rel="stylesheet" href="{{ url_for('static',filename='css/index.css')}}">
{% endblock %}
{% block user %}
  <div class="list-container">
        <ul class="note-list" style="list-style: none">
        {% for foo in user.question %}
            <li class="note-list-item">
                <span class="glyphion glyphion-leaf" aria-hidden="true"></span>
                <a href="{{ url_for('detail',question_id = foo.id)}}">{{ foo.title }}</a>
                <p style="font-family: 幼圆;color: black;"> 详情 {{ foo.detail }}</p>
                <span class="glyphion glyphion-user" aria-hidden="true"></span>
                <a href="{{ url_for('userbase',user_id = foo.author_id,tag = 1)}}">{{ foo.author.username }}</a>

                <span class="badge">{{ foo.creat_time }}</span>

            </li>
        {% endfor %}
    </ul>
  </div>
{% endblock %}

 

user2.html

{% extends 'userbase.html' %}
{% block title %}全部评论{% endblock %}
{% block head %}
<link rel="stylesheet" href="{{ url_for('static',filename='css/index.css')}}">
{% endblock %}
{% block user %}
    <div class="list-container">
        <h3 style="font-family:幼圆 ;color:black;width:100px"><span class="glyphion glyphion-user" aria-hidden="true"></span>{{ username }}
            <br><small>全部评论 <span class="badge"></span></small>
        </h3>
        <ul class="list-group" style="margin: 10px;list-style: none">
            {% for foo in user.comments %}
            <li class="note-list-item">
                <span class="glyphion glyphion-haert-empty" aria-hidden="true"></span>
                <a href="#">{{ foo.author.username }}</a>
                <span class="badge">{{ foo.creat_time }}</span>

                <p style="font-family: 幼圆;color: black;"> 详情 {{ foo.detail }}</p>
            </li>
        {% endfor %}
        </ul>
    </div>
{% endblock %}

 

user3.html

{% extends 'userbase.html' %}
{% block title %}个人信息{% endblock %}
{% block head %}
<link rel="stylesheet" href="{{ url_for('static',filename='css/index.css')}}">
{% endblock %}
{% block user %}
    <div class="list-container">
        <h3><span class="glyphion glyphion-user" aria-hidden="true"></span>{{ username }}
            <br><small>个人信息 <span class="badge"></span></small>
        </h3>
        <ul class="list-group" style="margin: 10px;list-style: nonefont-family: 幼圆;color:black;">
            <li class="list-group-item">用户:{{ user.username}}</li>
            <li class="list-group-item">编号:{{ user.id }}</li>
            <li class="list-group-item">昵称:{{ user.nickname}}</li>
            <li class="list-group-item">文章篇数:{{ user.question|length }}</li>
            <li class="list-group-item">评论数:{{ user.comments|length }}</li>
        </ul>
    </div>
{% endblock %}

 

 

 

 E、搜索,条件组合搜索:实现搜索功能:准备视图函数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',question = ques)

    

 

posted on 2018-01-07 01:04  072苏喜虹  阅读(251)  评论(0)    收藏  举报

导航