返回顶部
扩大
缩小

Zhang_derek

BBS论坛(二)

2.1.cms后台登录界面完成

(1)templates/cms/cms_login.html

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <meta name="description" content="">
    <meta name="author" content="">

    <title>CMS登录界面</title>

    <!-- Bootstrap core CSS -->
    <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">


    <!-- Custom styles for this template -->
    <link href="{{ url_for('static',filename='cms/css/signin.css') }}" rel="stylesheet">


  </head>

  <body>

    <div class="container">

      <form class="form-signin">
        <h2 class="form-signin-heading">请登录</h2>
        <label for="inputEmail" class="sr-only">邮箱:</label>
        <input type="email" id="inputEmail" class="form-control" placeholder="邮箱" required autofocus>
        <label for="inputPassword" class="sr-only">密吗</label>
        <input type="password" id="inputPassword" class="form-control" placeholder="密码" required>
        <div class="checkbox">
          <label>
            <input type="checkbox" value="remember-me"> 记住我
          </label>
        </div>
        <button class="btn btn-lg btn-primary btn-block" type="submit">立即登录</button>
      </form>

    </div> <!-- /container -->

  </body>
</html>

(2)static/cms/css/signin.css

body {
  padding-top: 40px;
  padding-bottom: 40px;
  background-color: #eee;
}

.form-signin {
  max-width: 330px;
  padding: 15px;
  margin: 0 auto;
}
.form-signin .form-signin-heading,
.form-signin .checkbox {
  margin-bottom: 10px;
}
.form-signin .checkbox {
  font-weight: normal;
}
.form-signin .form-control {
  position: relative;
  height: auto;
  -webkit-box-sizing: border-box;
     -moz-box-sizing: border-box;
          box-sizing: border-box;
  padding: 10px;
  font-size: 16px;
}
.form-signin .form-control:focus {
  z-index: 2;
}
.form-signin input[type="email"] {
  margin-bottom: -1px;
  border-bottom-right-radius: 0;
  border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
  margin-bottom: 10px;
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

(3)cms/views.py

# cmd/views.py
__author__ = 'derek'

from flask import Blueprint,views,render_template

bp = Blueprint("cms",__name__,url_prefix='/cms')

@bp.route('/')
def index():
    return 'cms index'

class LoginView(views.MethodView):
    def get(self):
        return render_template('cms/cms_login.html')

    def post(self):
        pass

bp.add_url_rule('/login/',view_func=LoginView.as_view('login'))

浏览器访问:http://127.0.0.1:5000/cms/login/

 

2.2.cms后台登录功能完成

(1)cms/cms_login.html

  <form class="form-signin" method="post">
        <h2 class="form-signin-heading">请登录</h2>
        <label for="inputEmail" class="sr-only">邮箱:</label>
        <input type="email" id="inputEmail" class="form-control" name="email" placeholder="邮箱" required autofocus>
        <label for="inputPassword" class="sr-only">密吗</label>
        <input type="password" id="inputPassword" class="form-control" name="password" placeholder="密码" required>
        <div class="checkbox">
          <label>
            <input type="checkbox" value="1" name="remember"> 记住我
          </label>
        </div>
        <button class="btn btn-lg btn-primary btn-block" type="submit">立即登录</button>
      </form>
        {% if message %}
            <p style="text-align: center" class="text-danger">{{ message }}</p>
        {% endif %}

(2)cms/forms.py

# cmd/forms.py

from wtforms import Form,StringField,IntegerField
from wtforms.validators import Email,InputRequired,Length

class LoginForm(Form):
    email = StringField(validators=[Email(message='请输入正确的邮箱格式'),
                                    InputRequired(message='请输入邮箱')])
    password = StringField(validators=[Length(6,20,message='密码长度不够或超出')])
    remember = IntegerField()

(4)cms/views.py

# cmd/views.py
__author__ = 'derek'

from flask import Blueprint,views,render_template,request,session
from flask import url_for,redirect
from .forms import LoginForm
from .models import CMSUser

bp = Blueprint("cms",__name__,url_prefix='/cms')

@bp.route('/')
def index():
    return 'cms index'

class LoginView(views.MethodView):
    def get(self,message=None):
        return render_template('cms/cms_login.html',message=message)

    def post(self):
        form = LoginForm(request.form)
        if form.validate():
            email = form.email.data
            password = form.password.data
            remember = form.remember.data
            user = CMSUser.query.filter_by(email=email).first()
            if user and user.check_password(password):
                session['user_id'] = user.id
                if remember:
                    # 31天后过期
                    session.permanent = True
                return redirect(url_for('cms.index'))
            else:
                return self.get(message='用户名或密码错误')

        else:
            #form.errors的错误信息格式,是一个字典,value是列表的形式
            # {'email': ['请输入正确的邮箱格式'], 'password': ['密码长度不够或超出']}
            message = form.errors.popitem()[1][0]
            return self.get(message=message)

bp.add_url_rule('/login/',view_func=LoginView.as_view('login'))

(4)config.py

import os
SECRET_KEY = os.urandom(24)

 

2.3.cms后台登录限制

(1)config.py

CMS_USER_ID = 'abcdefg'    #随便写一值,这样session更加安全

(2)修改LoginView

session[config.CMS_USER_ID] = user.id

(3)cms/decorators.py

# cms/decorators.py

from flask import session,redirect,url_for
from functools import wraps
import config

def login_required(func):
    @wraps(func)
    def inner(*args,**kwargs):
        if config.CMS_USER_ID in session:
            return func(*args,**kwargs)
        else:
            return redirect(url_for('cms.login'))
    return inner

(4)cms/cms_login.py

@bp.route('/')
@login_required
def index():
    return 'cms index'

 

2.4.cms后台模板渲染完成

 (1)static/cms/css/base.css

/*
 * Base structure
 */

/* Move down content because we have a fixed navbar that is 50px tall */
body {
    padding-top: 50px;
    overflow: hidden;
}

/*
 * Global add-ons
 */

.sub-header {
  padding-bottom: 10px;
  border-bottom: 1px solid #eee;
}

/*
 * Top navigation
 * Hide default border to remove 1px line.
 */
.navbar-fixed-top {
  border: 0;
}

/*
 * Sidebar
 */

/* Hide for mobile, show later */
.sidebar {
  display: none;
}
@media (min-width: 768px) {
  .sidebar {
    position: fixed;
    top: 51px;
    bottom: 0;
    left: 0;
    z-index: 1000;
    display: block;
    padding: 20px;
    overflow-x: hidden;
    overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
    background-color: #363a47;
    border-right: 1px solid #eee;
    margin-top: -1px;
  }
}

.nav-sidebar{
    padding: 5px 0;
    margin-left: -20px;
    margin-right: -20px;
}

.nav-sidebar > li{
    background: #494f60;
    border-bottom: 1px solid #363a47;
    border-top: 1px solid #666;
    line-height: 35px;
}

.nav-sidebar > li > a {
    background: #494f60;
    color: #9b9fb1;
    margin-left: 25px;
    display: block;
}

.nav-sidebar > li a span{
    float: right;
    width: 10px;
    height:10px;
    border-style: solid;
    border-color: #9b9fb1 #9b9fb1 transparent transparent;
    border-width: 1px;
    transform: rotate(45deg);
    position: relative;
    top: 10px;
    margin-right: 10px;
}

.nav-sidebar > li > a:hover{
    color: #fff;
    background: #494f60;
    text-decoration: none;
}

.nav-sidebar > li > .subnav{
    display: none;
}

.nav-sidebar > li.unfold{
    background: #494f60;
}

.nav-sidebar > li.unfold > .subnav{
    display: block;
}

.nav-sidebar > li.unfold > a{
    color: #db4055;
}

.nav-sidebar > li.unfold > a span{
    transform: rotate(135deg);
    top: 5px;
    border-color: #db4055 #db4055 transparent transparent;
}

.subnav{
    padding-left: 10px;
    padding-right: 10px;
    background: #363a47;
    overflow: hidden;
}

.subnav li{
    overflow: hidden;
    margin-top: 10px;
    line-height: 25px;
    height: 25px;
}

.subnav li.active{
    background: #db4055;
}

.subnav li a{
    /*display: block;*/
    color: #9b9fb1;
    padding-left: 30px;
    height:25px;
    line-height: 25px;
}

.subnav li a:hover{
    color: #fff;
}

.nav-group{
    margin-top: 10px;
}


.main {
  padding: 20px;
}
@media (min-width: 768px) {
  .main {
    padding-right: 40px;
    padding-left: 40px;
  }
}
.main .page-header {
  margin-top: 0;
}


/*
 * Placeholder dashboard ideas
 */

.placeholders {
  margin-bottom: 30px;
  text-align: center;
}
.placeholders h4 {
  margin-bottom: 0;
}
.placeholder {
  margin-bottom: 20px;
}
.placeholder img {
  display: inline-block;
  border-radius: 50%;
}

.main_content{
    margin-top: 20px;
}



.top-group{
    padding: 5px 10px;
    border-radius: 2px;
    background: #ecedf0;
    overflow: hidden;
}
.top-box{
        overflow: hidden;
        background: #ecedf0;
        padding: 10px 5px;
    }

(2)static/cms/js/base.js

/**
 * Created by Administrator on 2018/6/2.
 */
/**
 * Created by Administrator on 2016/12/17.
 */

$(function () {
    $('.nav-sidebar>li>a').click(function (event) {
        var that = $(this);
        if(that.children('a').attr('href') == '#'){
            event.preventDefault();
        }
        if(that.parent().hasClass('unfold')){
            that.parent().removeClass('unfold');
        }else{
            that.parent().addClass('unfold').siblings().removeClass('unfold');
        }
        console.log('coming....');
    });

    $('.nav-sidebar a').mouseleave(function () {
        $(this).css('text-decoration','none');
    });
});


$(function () {
    var url = window.location.href;
    if(url.indexOf('profile') >= 0){
        var profileLi = $('.profile-li');
        profileLi.addClass('unfold').siblings().removeClass('unfold');
        profileLi.children('.subnav').children().eq(0).addClass('active').siblings().removeClass('active');
    } else if(url.indexOf('resetpwd') >= 0){
        var profileLi = $('.profile-li');
        profileLi.addClass('unfold').siblings().removeClass('unfold');
        profileLi.children('.subnav').children().eq(1).addClass('active').siblings().removeClass('active');
    } else if(url.indexOf('resetemail') >= 0){
        var profileLi = $('.profile-li');
        profileLi.addClass('unfold').siblings().removeClass('unfold');
        profileLi.children('.subnav').children().eq(2).addClass('active').siblings().removeClass('active');
    } else if(url.indexOf('posts') >= 0){
        var postManageLi = $('.post-manage');
        console.log(postManageLi);
        postManageLi.addClass('unfold').siblings().removeClass('unfold');
    }else if(url.indexOf('boards') >= 0){
        var boardManageLi = $('.board-manage');
        boardManageLi.addClass('unfold').siblings().removeClass('unfold');
    }else if(url.indexOf('permissions') >= 0){
        var permissionManageLi = $('.permission-manage');
        permissionManageLi.addClass('unfold').siblings().removeClass('unfold');
    }else if(url.indexOf('fusers') >= 0){
        var userManageLi = $('.user-manage');
        userManageLi.addClass('unfold').siblings().removeClass('unfold');
    }else if(url.indexOf('cusers') >= 0){
        var cmsuserManageLi = $('.cmsuser-manage');
        cmsuserManageLi.addClass('unfold').siblings().removeClass('unfold');
    }else if(url.indexOf('croles') >= 0){
        var cmsroleManageLi = $('.cmsrole-manage');
        cmsroleManageLi.addClass('unfold').siblings().removeClass('unfold');
    }else if(url.indexOf('comments') >= 0) {
        var commentsManageLi = $('.comments-manage');
        commentsManageLi.addClass('unfold').siblings().removeClass('unfold');
    }else if(url.indexOf('banners')>=0){
        var bannerManageLi=$('.banner-manage');
        bannerManageLi.addClass('unfold').siblings().removeClass('unfold');
    }
});

(3)templates/common/_macros.html

创建一个宏

{#“-”表示去掉换行#}

{% macro static(filename) -%}
    {{ url_for("static",filename=filename) }}
{%- endmacro %}

(4)templates/cms/cms_index.html

{% from "common/_macros.html" import static %}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>标题</title>
    <script src="http://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
    <link href="http://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <script src="http://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <link rel="stylesheet" href="{{ static('cms/css/base.css') }}">
    <script src="{{ static('cms/js/base.js')}}"></script>
</head>
<body>
     <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Zhang_derek论坛管理后台</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
          <ul class="nav navbar-nav navbar-right">
            <li><a href="#">derek<span>[超级管理员]</span></a></li>
            <li><a href="#">注销</a></li>
          </ul>
          <form class="navbar-form navbar-right">

            <input type="text" class="form-control" placeholder="查找...">
          </form>
        </div>
      </div>
    </nav>

    <div class="container-fluid">
      <div class="row">
          <div class="col-sm-3 col-md-2 sidebar">
              <ul class="nav-sidebar">
                <li class="unfold"><a href="#">首页</a></li>
                <li class="profile-li">
                    <a href="#">个人中心<span></span></a>
                    <ul class="subnav">
                        <li><a href="#">个人信息</a></li>
                        <li><a href="#">修改密码</a></li>
                        <li><a href="#">修改邮箱</a></li>
                    </ul>
                </li>

                      <li class="nav-group post-manage"><a href="#">帖子管理</a></li>

                      <li class="comments-manage"><a href="#">评论管理</a></li>


                      <li class="board-manage"><a href="#">板块管理</a></li>

                      <li class="nav-group user-manage"><a href="#">用户管理</a></li>

                        <li class="nav-group cmsuser-manage"><a href="#">CMS用户管理</a></li>

                      <li class="cmsrole-manage"><a href="#">CMS组管理</a></li>

            </ul>
          </div>
          <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
            <h1>我的论坛</h1>
          </div>
      </div>
    </div>
</body>
</html>

(5)app/cms/views.py

@bp.route('/')
@login_required
def index():
    return render_template('cms/cms_index.html')

访问:http://127.0.0.1:5000/cms/

 

posted on 2018-06-05 23:46  zhang_derek  阅读(1038)  评论(0编辑  收藏  举报

导航