期末作品检查

  1. 个人学期总结
  2. 总结Python+Flask+MysqL的web建设技术过程,标准如下:
    1. 即是对自己所学知识的梳理
    2. 也可作为初学入门者的简单教程
    3. 也可作为自己以后复习的向导
    4. 也是一种向外展示能力的途径

个人学期总结:

    一开始接触python我们学的是简单的输出输入交互和一些数字的计算,python语言优点在于它的简洁灵活,所以很多时候它都用到符号代替,接着我们import turtle库,并绘制出多种多样的图形,学习了字符串基本操作,凯撒密码,自制九九乘法表,中英文词频统计等等,虽然语句都挺简单,但这激发了我们对学习python的兴趣,并提升了我们对编程语言的思维能力,有助于下半学期我们构建Flask框架制作网页的学习。

    学习初期第一方面,我认为学习每一知识点的开始则是了解其知识点的概念及基础。首先则是认识URL,观察那些常用网站的网址,区分它们不同组成部分。然后,观察web的浏览过程。最后,最为重要的则是实操,了解HTML基础并联系使用标签制作最简单的页面。自行了解各个标签的用法以及整体标签的规范。第二方面,认识div块与form表单的作用,利用div块与form表单制作登录页面。同时,练习使用各种列表,例如下拉列表选择框、无序列表、有序列表以及定义列表。 观察常用网页的HTML元素,并在实操过程中,用已学的标签模仿制作。通过网络搜索补充自己所想要的知识点,不要仅仅依赖于课堂。

    Python语法简洁清晰,特色之一是强制用空白符(white space)作为语句缩进。Flask是一个面向简单需求小型应用的“微框架(microframework)”,Flask选择组件的额外工作给那些使用案例不适用标准ORM的开发者提供了更多的灵活性,同样也给使用不同工作流和模版化系统的开发者们带来了灵活性。MySQL是一个关系型数据库管理系统MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件。MySQL是一种关系数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。

      制作网页初期,应制作一个有主题性的导航条。首先认识HTML头部元素:<base>  定义了页面链接标签的默认链接地址;<style>  定义了HTML文档的样式文件;<link>  定义了一个文档和外部资源之间的关系。其次练习样式表:行内样式表;内嵌样式表;外部样式表。最后分别练习定义三类选择器:HTML 选择器;CLASS 类选择器;ID 选择器。在进行连接时要用到url_for的语句,尤其是在连接图片时,像这个学期学到的调用两个父模板,当调用到第二个父模板的时候就会出现图片调用不过来,这是就要用到url_for的语句。

      这个学期中的来说还是蛮有收获的,学习到了网页如何制作,怎么调用图片,如何运用css来设计style,怎么通过使用js来设置密码,用户名,等等,怎么使用div,ul,li等等来完善网页的内容和调整网页的规模,如何进行模块分离,如何让多个数据库表连接等等。python虽然是一门使用语句比较少的一种程序语言,但我们还是亟需多加练习。

一、使用工具

主要工具有:pycharm64.exe + Python 3.6 64-bit + MySQL + Navicat for MySQL(辅助工具)

      

 

实现此页面所有的static文件、templates文件与py文件

  

二、页面设计

1.导航条(父模板)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}父模板{% endblock %}</title>
    <script src="{{ url_for('static',filename='js/base.js') }}" type="text/javascript"></script>
    <link href="{{ url_for('static' ,filename='css/base.css') }}" rel="stylesheet" type="text/css">
    {% block head %}
    {% endblock %}
</head>
<body id="myBody">
<nav class="body">
    <div style="background-color: floralwhite;top: 0">
        <form action="{{ url_for('search') }}" method="get">
            <img id="imgs" src="{{ url_for('static',filename='images/touxiang.jpg') }}">&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp
            <a class="s" href="{{ url_for('index') }}">首页</a>&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp
            <a class="ss" href="{{ url_for('question') }}">发布问答</a>&nbsp&nbsp&nbsp&nbsp
            <input id="sousuo" type="text" name="q" placeholder="请输入搜索内容:">
            <button id="sou" type="submit">查找</button>

            {% if username %}
                <a class="login"
                   href="{{ url_for('usercenter',user_id = session.get('userid'),tag=1) }}">{{ session.get('user') }}</a>
                {#            <a class="login" href="#">{{ username }}</a>#}
                <a class="register" href="{{ url_for('logout') }}">注销</a>
            {% else %}
                <a class="login" href="{{ url_for('login') }}">登录</a>
                <a class="register" href="{{ url_for('register') }}">注册</a>
            {% endif %}
            <img id="myOn_Off" onclick="mySwitch()" src="{{ url_for('static',filename='images/taiyang.png') }}" width="50" height="50">
        </form>
    </div>
</nav>
{% block main %}
{% endblock %}
<footer>
    <div class="footer_box">
        Copyright@2017-2027 Create by JZX
    </div>
</footer>
</body>
</html>

 

这里的界面都为继承父模板后的界面.后面将会有相关介绍

2.登录界面。完成登录功能:与注册一样完成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')
        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('base'))
            else:
                return 'password error.'
        else:
            return 'username is not existed.'

进入相关的页面时要先登陆。

# 行动前需要登录,定义装饰器
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

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

@app.route('/register/', methods=['GET', 'POST'])
def register():
    if request.method == 'GET':
        return render_template('register.html')
    else:
        usern = request.form.get('username')
        telep = request.form.get('telephone')
        passw = request.form.get('password')
        user = User.query.filter(User.username == usern).first()
        if user:
            return 'username existed.'
        else:
            user1 = User(username=usern, password=passw, telephone=telep)
            db.session.add(user1)  # 数据库操作
            db.session.commit()
            return redirect(url_for('login'))

 

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

login.html:

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

{% block main %}
    <body>
    <form action="{{ url_for('login') }}" method="post">
        <div class="box">
            <div>
                <a href="{{ url_for('login') }}">登录</a>
                <a style="color: antiquewhite">*</a>
                <a href="{{ url_for('register') }}">注册</a>
            </div>
            <br>
            <div class="name" align="center">
                <svg class="iconphone" width="20px" height="20px" viewBox="0 0 20 20">
                    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"
                       sketch:type="MSPage">
                        <g id="2-copy-2" sketch:type="MSArtboardGroup"
                           transform="translate(-505.000000, -357.000000)" fill="#666">
                            <path d="M517.388314,366.868305 C519.068314,366.001784 520.220053,364.252653 520.220053,362.231784 C520.220053,359.350479 517.883966,357.014392 515.002662,357.014392 C512.121357,357.014392 509.78527,359.350479 509.78527,362.231784 C509.78527,364.252653 510.936575,366.001784 512.616575,366.868305 C508.246575,367.938305 505.002662,371.879175 505.002662,376.57961 C505.002662,376.81961 505.197009,377.014392 505.437444,377.014392 C505.677444,377.014392 505.872227,376.81961 505.872227,376.57961 C505.872227,371.537001 509.960053,367.449175 515.002662,367.449175 C520.04527,367.449175 524.133096,371.537001 524.133096,376.57961 C524.133096,376.81961 524.327444,377.014392 524.567879,377.014392 C524.807879,377.014392 525.002662,376.81961 525.002662,376.57961 C525.002662,371.879175 521.758749,367.938305 517.388314,366.868305 L517.388314,366.868305 Z M510.654835,362.231784 C510.654835,359.830479 512.601357,357.883957 515.002662,357.883957 C517.403966,357.883957 519.350488,359.830479 519.350488,362.231784 C519.350488,364.632653 517.403966,366.57961 515.002662,366.57961 C512.601357,366.57961 510.654835,364.632653 510.654835,362.231784 L510.654835,362.231784 Z"
                                  id="id" sketch:type="MSShapeGroup"></path>
                        </g>
                    </g>
                </svg>
                <input
                        id="uname" type="text" placeholder="请输入用户名:" name="username">

            </div>
            <br>
            <div class="email" align="center">
                <svg class="iconphone" width="20px" height="20px" viewBox="0 0 20 20">
                    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"
                       sketch:type="MSPage">
                        <g id="2-copy-2" sketch:type="MSArtboardGroup"
                           transform="translate(-505.000000, -407.000000)" fill="#666">
                            <path d="M515,418.304324 C514.12782,418.304324 513.421091,418.888119 513.421091,419.608723 C513.421091,419.995004 513.624357,420.341947 513.947394,420.580774 L513.947394,421.782554 C513.947394,422.262857 514.418637,422.652187 515.00003,422.652187 C515.581302,422.652187 516.052667,422.262857 516.052667,421.782554 L516.052667,420.580774 C516.375703,420.341947 516.579,419.995004 516.579,419.608723 C516.57897,418.888119 515.87221,418.304324 515,418.304324 L515,418.304324 L515,418.304324 Z M522.368454,414.391327 L521.315788,414.391327 L521.315788,412.217421 C521.315788,409.335657 518.488418,407 515,407 C511.511582,407 508.684212,409.335657 508.684212,412.217421 L508.684212,414.391327 L507.631576,414.391327 C506.178003,414.391327 505,415.364503 505,416.565234 L505,424.826193 C505,426.026824 506.178003,427 507.631576,427 L522.368424,427 C523.821422,427 525,426.026899 525,424.826193 L525,416.565234 C525.00003,415.364478 523.821422,414.391327 522.368454,414.391327 L522.368454,414.391327 L522.368454,414.391327 Z M515,407.869583 C517.906571,407.869583 520.263152,409.816309 520.263152,412.217396 L520.263152,414.391302 L509.737544,414.391302 L509.737544,412.217396 L509.736848,412.217396 C509.736848,409.816309 512.093459,407.869583 515,407.869583 L515,407.869583 L515,407.869583 Z M523.947364,424.826093 C523.947364,425.546622 523.240604,426.130392 522.368454,426.130392 L507.631606,426.130392 C506.759396,426.130392 506.052667,425.546622 506.052667,424.826093 L506.052667,416.565234 C506.052667,415.84468 506.759426,415.260835 507.631606,415.260835 L522.368454,415.260835 C523.240635,415.260835 523.947364,415.844705 523.947364,416.565234 L523.947364,424.826093 L523.947364,424.826093 L523.947364,424.826093 Z"
                                  id="pw" sketch:type="MSShapeGroup"></path>
                        </g>
                    </g>
                </svg>
                <input
                        type="password" id="upass" placeholder="请输入密码:" name="password">

            </div>
            <br>

            <div>
                <div id="error_box"></div>
                <button id="login" onclick=" return myLogin()">登录</button>

            </div>
            <br>

            <div>
                <input value="1" name="remember" id="remember" type="checkbox">
                <label for="remember" style="color: darkmagenta">保存登录信息</label>&nbsp;&nbsp;&nbsp;&nbsp;
                <input value="2" name="remember" id="remember" type="checkbox">
                <label for="remember" style="color: darkmagenta">记住我</label>
            </div>

            <br>
            <a class="register-login" href="{{ url_for('register') }}">进入注册界面</a>

            <div id="footer" style="background-color: transparent;clear:both;text-align:center;">版权 . duym@jzx</div>

        </div>
        <script>
            document.getElementById("demo").innerHTML = Date();
            document.write(Date())
        </script>
    </form>
    </body>
{% endblock %}

 

login.js:

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

    //uname
    if (oUname.value.length > 20 || oUname.value.length < 6) {
        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 = "只能是字母或者数字。";
            isError = false;
            return isError;
        }

    }
    //upass
    if (oUpass.value.length > 20 || oUpass.value.length < 6) {
        oError.innerHTML = "密码为6到20位。";
        isError = false;
        return isError;
    }
return isError;
    //window.alert("登录成功!!");

}

register.html:

{% extends'base.html' %}
{% block title %}
    注册
{% endblock %}
{% block head %}
    <link rel="stylesheet" href="{{ url_for('static',filename='css/register.css') }}" type="text/css">
    <script src="{{url_for('static',filename='js/register.js') }}"></script>
{% endblock %}
{% block main %}

    <body>
    <form action="{{ url_for('register') }}" method="post">
    <div class="box">
        <div>
            <a href="{{ url_for('login') }}">登录</a>
            <a style="color: antiquewhite">*</a>
            <a href="{{ url_for('register') }}">注册</a>
        </div>
        <br>

        <div class="name" align="center">
            <input id="uname" type="text" placeholder="登录账号:" name="username">
        </div>
        <br>
        <div class="telephone" align="center">

            <input type="tel"
                   id="uuser"
                   placeholder="请输入你的手机号:" name="telephone">
        </div>
        <br>

        <div class="email" align="center">
            <input
                    type="password" id="upass" placeholder="设置你的密码:"name="password">
        </div>
        <br>
        <div class="email" align="center">
            <input
                    type="password" id="upass2" placeholder="请输入你的密码:"name="password">
        </div>
        <br>
        <div>
            <div id="error_box"></div>
            <div>
                <button id="register" onclick=" return myRegister()">注册</button>

            </div>
            <a class="login-register" href="{{ url_for('login') }}">进入登录界面</a>


            <div id="footer" style="background-color: transparent;clear:both;text-align:center;">版权 . duym@jzx</div>
        </div>
    </div>
    </form>
    </body>

{% endblock %}

 

register.js:

function myRegister() {
    var oUname = document.getElementById("uname");
    var oUpass = document.getElementById("upass");
    var oError = document.getElementById("error_box");
    var oUuser = document.getElementById("uuser");
    var oUpass2 = document.getElementById("upass2");
    var isError = true;

    oError.innerHTML = "<br>";
    //uname
    if (oUname.value.length > 20 || oUname.value.length < 6) {
        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 = "昵称只能是字母或者数字。";
            isError = false;
            return isError;
        }
    }
    for (var i = 0; i < 12; i++) {
        if (((oUuser.value.charCodeAt(i) < 48) || (oUuser.value.charCodeAt(i) > 57)) || oUuser.value.length != 11) {
            oError.innerHTML = "请输入正确手机号";
            isError = false;
            return isError;
        }
    }

    //upass
    if (oUpass.value.length > 20 || oUpass.value.length < 6) {
        document.getElementById('error_box').innerHTML = "密码必须在6-20个字符之间";
        isError = false;
        return isError;
    }
    if (oUpass2.value != oUpass.value) {
        oError.innerHTML = "两次输入的密码必须一致";
        isError = false;
        return isError;
    }
    return isError
    window.alert("注册成功!!");

}

4.发布问答界面

detail.html:

{% extends'base.html' %}
{% block title %}
    问答详情
{% endblock %}
{% block head %}
    <link rel="stylesheet" href="{{ url_for('static',filename='css/detail.css') }}" type="text/css">
{% endblock %}
{% block main %}
    <body id="myBody">
    <div class="total">
        <div class="page-header" style="text-align: left">
            <h3 style="font-family: 楷体;color: cornflowerblue;">{{ ques.title }}<br>
                <small>读者:{{ ques.author.username }}&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp<span
                        class="badge"
                        style="border: hidden;border-radius: 0px">{{ ques.creat_time }}</span>
                </small>
            </h3>
            <hr>
        </div>
        <p class="lead">{{ ques.detail }}</p>
        <hr>
        <form method="post" action="{{ url_for('comment') }}">
            <div class="form-group" style="text-align: left">
                <textarea name="new_comment" class="form-control" rows="3" placeholder="Write your comment"
                          id="new_comment"></textarea>
                <input name="question_id" type="hidden" value="{{ ques.id }}"/>
            </div>
            <button type="submit" class="btn btn-default" style="border-radius: inherit;font-family: 幼圆">发送</button>
        </form>


        <h3 style="text-align: left">评论:({{ ques.comments|length }})</h3>
        <ul class="list-group">
            {% for foo in ques.comments %}
                <li class="list-group-item">
                    <span class="glyphicon glyphicon-left" aria-hidden="true"></span>
                    <br>
                    <a href="{{ url_for('usercenter',user_id = ques.author.id,tag=1) }}" style="font-family: 楷体;color: cornflowerblue;text-align: left">作者:{{ foo.author.username }}</a>&nbsp&nbsp&nbsp
                    <span class="badge"
                          style="font-family: 楷体;color: cornflowerblue;text-align: right">评论时间:{{ foo.creat_time }}</span>
                    <p style="text-align: left;font-family: 楷体;color: cornflowerblue">{{ foo.detail }}
                    </p>
                </li>
            {% endfor %}
        </ul>
    </div>
    </body>
    </html>
{% endblock %}

 

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

 

<img id="myOn_Off" onclick="mySwitch()" src="{{ url_for('static',filename='images/taiyang.png') }}" width="50" height="50">

 

function mySwitch() {
            var myele=document.getElementById("myOn_Off");
            if(myele.src.match("taiyang")){
                myele.src="../static/images/yuliang.jpg";
                document.getElementById("myBody").style.background="gray";
                document.getElementById("demo").style.color="white";
            }else {
                myele.src = "../static/images/taiyang.png";
                document.getElementById("myBody").style.background = "white";
                document.getElementById("demo").style.color = "gray" ;
            }
        }

 

 

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

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


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

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

 

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

 

{% 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 %}
    <body id="myBody">
    <div class="indexone">
        {#    <img src="{{ url_for('static',filename = 'images/heben.jepg' }} alt='qa'">#}
        <ul class="list-group">
            {% for foo in questions %}
                <li class="list-group-item">
                    <span class="glyphicon glyphicon-leaf" aria-hidden="true"></span>
                    <a href="#" style="font-family: 幼圆;color: crimson">读者:{{ foo.author.username }}</a><br>
                    <a href="{{ url_for('detail',question_id = foo.id) }}"
                       style="font-family: 幼圆;color: crimson">{{ foo.title }}</a><br>
                    <span class="badge" style="font-family: 幼圆;color: crimson">发布时间:{{ foo.creat_time }}</span><br>
                    <p class="container" style="font-family: 幼圆;color: #002D54;">{{ foo.detail }}</p>
                    <span class="glyphicon glyphicon-leaf" aria-hidden="true"></span>
                    <a href="{{ url_for('usercenter',user_id = foo.author_id,tag=1) }}">{{ foo.author.username }}评论({{ foo.comments|length }})</a>
                    <div class="meta">
                        <a class="collection-tag">
                            <span style="font-family: 幼圆">社会热点</span>
                        </a>
                        <a class="collection-tag">
                            <span style="font-family: 幼圆"> 浏览: </span><span
                                style="font-family: 幼圆;color: red"> 555 </span>
                        </a>
                        <a class="collection-tag">
                            <span style="font-family: 幼圆"> 评论: </span><span
                                style="font-family: 幼圆;color: red"> 890 </span>
                        </a>
                        <span style="font-family: 幼圆"> 点赞: </span><span
                            style="font-family: 幼圆;color: red"> 1234 </span>
                    </div>
                </li>
            {% endfor %}
        </ul>
    </div>

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

 

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

 

@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')
        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('base'))

 

8、主PY文件写视图函数,带id参数。 首页标题的标签做带参数的链接,在详情页将数据的显示在恰当的位置。建立评论的对象关系映射,尝试实现发布评论。 

完成评论功能:定义评论的视图函数,读取前端页面数据,保存到数据库中 ,显示评论次数,要求评论前登录(调用登录装饰器),尝试实现详情页面下的评论列表显示。

 

{% extends'base.html' %}
{% block title %}
    问答详情
{% endblock %}
{% block head %}
    <link rel="stylesheet" href="{{ url_for('static',filename='css/detail.css') }}" type="text/css">
{% endblock %}
{% block main %}
    <body id="myBody">
    <div class="total">
        <div class="page-header" style="text-align: left">
            <h3 style="font-family: 楷体;color: cornflowerblue;"><a href="{{ url_for('usercenter',user_id=ques.author_id,tag=3) }}">{{ ques.title }}</a><br>
                <small><a href="{{ url_for('usercenter',user_id=ques.author_id,tag=3) }}">读者:{{ ques.author.username }}&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp<span
                        class="badge"
                        style="border: hidden;border-radius: 0px">{{ ques.creat_time }}</span>
                </a></small>
            </h3>
            <hr>
        </div>
        <p class="lead">{{ ques.detail }}</p>
        <hr>
        <form method="post" action="{{ url_for('comment') }}">
            <div class="form-group" style="text-align: left">
                <textarea name="new_comment" class="form-control" rows="3" placeholder="Write your comment"
                          id="new_comment"></textarea>
                <input name="question_id" type="hidden" value="{{ ques.id }}"/>
            </div>
            <button type="submit" class="btn btn-default" style="border-radius: inherit;font-family: 幼圆">发送</button>
        </form>


        <h3 style="text-align: left">评论:({{ ques.comments|length }})</h3>
        <ul class="list-group">
            {% for foo in ques.comments %}
                <li class="list-group-item">
                    <span class="glyphicon glyphicon-left" aria-hidden="true"></span>
                    <br>
                    <a href="{{ url_for('usercenter',user_id = ques.author.id,tag=1) }}" style="font-family: 楷体;color: cornflowerblue;text-align: left">作者:{{ foo.author.username }}</a>&nbsp&nbsp&nbsp
                    <span class="badge"
                          style="font-family: 楷体;color: cornflowerblue;text-align: right">评论时间:{{ foo.creat_time }}</span>
                    <p style="text-align: left;font-family: 楷体;color: cornflowerblue">{{ foo.detail }}
                    </p>
                </li>
            {% endfor %}
        </ul>
    </div>
    </body>
    </html>
{% endblock %}

 

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

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

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

@app.route('/usercenter/<user_id>/<tag>')
@loginFirst
def usercenter(user_id, tag):
    user = User.query.filter(User.id == user_id).first()
    mycontext = {
        'user': user,
    }
    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)
{% extends'base.html' %}
{% block title %}
    个人中心
{% endblock %}

{% block head %}
{% endblock %}

{% block main %}
    <body id="myBody">
    <ul class="nav">
        <li role="presentation"><a href={{ url_for('usercenter',user_id=user.id,tag='1') }} >全部问答</a></li>
        <li role="presentation"><a href={{ url_for('usercenter',user_id=user.id,tag='2') }}>全部评论</a></li>
        <li role="presentation"><a href={{ url_for('usercenter',user_id=user.id,tag='3') }}>个人信息</a></li>
    </ul>
    {% block user %}

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

 user1.html:

{% extends'userbase.html' %}
{% block head %}
    <link rel="stylesheet" href="{{ url_for('static',filename='css/user.css') }}" type="text/css">
{% endblock %}
{% block user %}
    <body id="myBody">
    <div class="total">
        <div class="page-header" style="text-align: left">
            <h3 style="font-family: 楷体;color: cornflowerblue;width:100px"><span class="glyphicon glyphicon-leaf" aria-hidden="true"></span>{{ username }}<br>
                <small>全部问答<span class="badge"></span></small>
            </h3>
            <ul class="list-group">
                {% for foo in user.question %}
                    <li class="list-group-item">
                        <span class="glyphicon glyphicon-leaf" aria-hidden="true"></span>
                        <a href="#" style="font-family: 幼圆;color: cornflowerblue">读者:{{ foo.author.username }}</a><br>
                        <span class="badge"
                              style="font-family: 幼圆;color: cornflowerblue">发布时间:{{ foo.creat_time }}</span><br>
                        <p style="font-family: 幼圆;color: #002D54;">{{ foo.detail }}</p>
                    </li>
                {% endfor %}
            </ul>

        </div>
    </div>
    </body>
{% endblock %}

 user2.html:

{% extends'userbase.html' %}
{% block head %}
    <link rel="stylesheet" href="{{ url_for('static',filename='css/user.css') }}" type="text/css">
{% endblock %}
{% block user %}
    <body id="myBody">
    <div class="total">
        <div class="page-header" style="text-align: left">
            <h3 style="font-family: 楷体;color: cornflowerblue;width:100px"><span class="glyphicon glyphicon-leaf"
                                                              aria-hidden="true"></span>{{ username }}<br>
                <small>全部评论<span class="badge"></span></small>
            </h3>
            <ul class="list-group">
                {% for foo in user.comments %}
                    <li class="list-group-item">
                        <span class="glyphicon glyphicon-leaf" aria-hidden="true"></span>
                        <a href="#" style="font-family: 幼圆;color: cornflowerblue">读者:{{ foo.author.username }}</a><br>
                        <span class="badge"
                              style="font-family: 幼圆;color: cornflowerblue">发布时间:{{ foo.creat_time }}</span><br>
                        <p style="font-family: 幼圆;color: #002D54;">{{ foo.detail }}</p>
                    </li>
                {% endfor %}
            </ul>
        </div>
    </div>
    </body>
{% endblock %}

 user3.html:

{% extends'userbase.html' %}
{% block head %}
    <link rel="stylesheet" href="{{ url_for('static',filename='css/user.css') }}" type="text/css">
{% endblock %}
{% block user %}
    <body id="myBody">
    <div class="total">
        <div class="page-header" style="text-align: left">
            <h3 style="font-family: 楷体;color: cornflowerblue;width:100px"><span class="glyphicon glyphicon-leaf" aria-hidden="true"></span>{{ username }}<br>
                <small>个人信息<span class="badge"></span></small>
            </h3>
            <ul class="list-group" style="font-family: 幼圆;color: #002D54;">
                <li class="list-group-item">用户:{{ user.username }}</li>
                <li class="list-group-item">编号:{{ user.id }}</li>
                <li class="list-group-item">文章篇:{{ user.question|length }}</li>
                <li class="list-group-item">评论数:{{ user.comments|length }}</li>
            </ul>
        </div>
    </div>
    </body>
{% endblock %}

10、实现搜索功能:准备视图函数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)

 11、最后实现密码保护功能。

    @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

配置链接数据库信息,建立mysql和app的连接,创建用户模型。通过用户模型,学习对数据库进行增删改查操作。

import os
SECRET_KEY = os.urandom(24)
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:@127.0.0.1:3306/mis?charset=utf8'
SQLALCHEMY_TRACK_MODIFICATIONS = False

三、加载静态文件,父模板与其他界面的继承

 1.登陆用url_for加载静态文件

  1.<script src="{{ url_for('static',filename='js/login.js') }}"></script>

  2.flask 从static文件夹开始寻找

  3.可用于加载css, js, image文件

2.继承和扩展

  1.把一些公共的代码放在父模板中,避免每个模板写同样的内容。base.html

  2.子模板继承父模板 {% extends 'base.html’ %}

3.父模板提前定义好子模板可以实现一些自己需求的位置及名称。block

  1.<title>{% block title %}{% endblock %}-MIS问答平台</title>

  2.{% block head %}{% endblock %}

  3.{% block main %}{% endblock %}

4.子模板中写代码实现自己的需求。block 

   {% block title %}登录{% endblock %}

四、数据库

1、数据库工具:mysql

2、建立mysql和app的连接(模块分离后的)

from datetime import datetime
from werkzeug.security import generate_password_hash,check_password_hash
from exts import db

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)#内部使用
    telephone = db.Column(db.String(11), nullable=False)


    @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):
    __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'))
    author = db.relationship('User', backref=db.backref('question'))  # 这个不会在表单里面出现,只是与user建立一个映射关系

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

3、通过用户模型,对数据库进行增删改查

增加数据

user=User(username = 'mis1234',password = '111111',telephone = '12345678900')
db.session.add(user)
db.session.commit()

查询数据

user=User.query.filter(user.username == 'mis1234').first()
print(user.username,user.password)


修改数据
user=User.query.filter(user.username == 'mis1234').first()
user.password = '000000'
db.session.commit()

删除数据
user=User.query.filter(user.username == 'mis1234').first()
db.session.delete(user)
db.session.commit()

以上就是这个学期完成的登录、注册、发布问答等简单功能的基本项目系统。

转载于:https://www.cnblogs.com/jzx-089/p/8177939.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值