实现一个简单的Flask项目

该博客围绕Python项目展开,目标是实现包含用户注册、登陆、任务查询等功能的系统。详细介绍了项目结构,包含多个Python文件和HTML文件,还提及在MySQL创建数据库。按步骤说明了从初始化到编写视图函数、表单,最后编写HTML文件的开发流程。

目标:

实现一个项目,包括用户注册、登陆、登出、用户查询任务列表、任务完成进度、以及任务分类。
创建结构:

.
├── app
│ ├── forms.py
│ ├── init.py
│ ├── models.py
│ ├── pycache
│ │ ├── forms.cpython-36.pyc
│ │ ├── init.cpython-36.pyc
│ │ ├── init.cpython-37.pyc
│ │ ├── models.cpython-36.pyc
│ │ └── views.cpython-36.pyc
│ ├── static
│ │ ├── css
│ │ │ └── main.css
│ │ └── js
│ │ └── echarts.min.js
│ ├── templates
│ │ ├── base.html
│ │ ├── login.html
│ │ ├── register.html
│ │ └── todo
│ │ ├── add_todo.html
│ │ ├── edit_todo.html
│ │ ├── list_todo.html
│ │ ├── new_show_todo.html
│ │ └── show_todo.html
│ └── views.py
├── config.py
├── doc(编写所需文档)
├── manage.py
└── migrations
├── alembic.ini
├── env.py
├── pycache
│ └── env.cpython-36.pyc
├── README
├── script.py.mako
└── versions

11 directories, 30 files

第一步:

__init __

初始化app对象、db对象、manager对象、bt对象、migrate对象以及moment对象,
并读取config.py中的设置信息:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bootstrap import Bootstrap
from flask_script import Manager
from flask_migrate import Migrate
from flask_moment import Moment
import pymysql

app = Flask(__name__)

# 数据库报错问题
pymysql.install_as_MySQLdb()

# 读取配置文件的配置信息
app.config.from_pyfile('../config.py')
db = SQLAlchemy(app)
manager = Manager(app)
bt = Bootstrap(app)
migrate = Migrate(app, db)
moment = Moment(app)

第二步:

config.py

在mysql中创建Todo的database,编写创建数据表所需要的基本设置:

SQLALCHEMY_DATABASE_URI = 'mysql://root:westos@localhost/Todo'
SQLALCHEMY_TRACK_MODIFICATIONS = True
SECRET_KEY = 'westos'
PER_PAGE = 5

第三步:

models.py

定义三个模型,分别是用户(User)、任务(Todo)、以及任务分类(Category)。
我们需要首先确定:
一个用户对应多个任务;
一个任务分类对应多个任务;
一个用户对应多个任务分类。
(外键写在多的一端)

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

class User(db.Model):
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    username = db.Column(db.String(20), unique=True)
    password_hash = db.Column(db.String(100), nullable=False)
    email = db.Column(db.String(30), unique=True)
    # datetime.now()你当前所在时区的时间
    # 使用协调时间时 (Coordinated Universal Time, UTC) 协调世界各地的时差问题
    # 美国时间: 2019-3-15 00:00   北京时间: 2019-03-16 12:00
    add_time = db.Column(db.DateTime, default=datetime.utcnow())  # 账户创建时间
    # 1). User添加属性todos; 2). Todo添加属性user;
    todos = db.relationship('Todo', backref="user")
    categories = db.relationship('Category', backref='user')

@property
def password(self):
    """u.password"""
    raise AttributeError("密码属性不可以读取")

@password.setter
def password(self, password):
    """u.password = xxxxx """
    self.password_hash = generate_password_hash(password)

def verify_password(self, password):
    """验证密码是否正确"""
    return check_password_hash(self.password_hash, password)
# *********************************************************************

def __repr__(self):
    return "<User %s>" % (self.username)


class Todo(db.Model):
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    content = db.Column(db.String(100))  # 任务内容
    status = db.Column(db.Boolean, default=False)  # 任务的状态
    add_time = db.Column(db.DateTime, default=datetime.utcnow())  # 任务创建时间
    # 任务的类型, 关联另外一个表的id
    category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
    # 任务所属用户
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

def __repr__(self):
    return "<Todo %s>" % (self.content[:6])


class Category(db.Model):
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    name = db.Column(db.String(20), unique=True)
    add_time = db.Column(db.DateTime, default=datetime.utcnow())  # 任务创建时间
    # 1). Category添加一个属性todos; 2). Todo添加属性category;
    todos = db.relationship('Todo', backref='category')
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

def __repr__(self):
    return "<Category %s>" % (self.name)

第四步:

manage.py

编写需要运行的主函数:

from app import manager, db
from app.views import *
from flask_migrate import MigrateCommand
# 添加数据库操作的命令信息
from app.models import User, Category, Todo


@manager.command
def dbinit():
    """数据库初始化信息"""
    db.drop_all()
    db.create_all()
    u = User(username='admin', email="admin@qq.com")
    u.password = 'admin'
    db.session.add(u)
    db.session.commit()
    print("用户%s创建成功......." % (u.username))

c = Category(name="学习", user_id=1)
db.session.add(c)
print("分类%s创建成功...." % (c.name))

t = Todo(content="学习Flask", category_id=1, user_id=1)
db.session.add(t)
print("任务%s添加成功....." % (t.content))
db.session.commit()


manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
    manager.run()

第五步:

view.py

编写视图函数,定义页面:

import json
from functools import wraps
from app import app, db
# 网站首页
from app.forms import RegisterForm, LoginForm, AddTodoForm, EditTodoForm
from flask import render_template, flash, redirect, url_for, session, request
from app.models import User, Todo


def is_login(f):
    """用来判断用户是否登录成功"""
    @wraps(f)
    def wrapper(*args, **kwargs):
        # 判断session对象中是否有seesion['user'],
        # 如果包含信息, 则登录成功, 可以访问主页;
        # 如果不包含信息, 则未登录成功, 跳转到登录界面;;
        if session.get('user', None):
            return f(*args, **kwargs)
        else:
            flash("用户必须登录才能访问%s" % (f.__name__))
            return redirect(url_for('login'))
    return wrapper


# 主页信息
@app.route('/')
def index():
    return redirect(url_for('list'))


# 注册页面
@app.route('/register/', methods=['POST', 'GET'])
def register():
    form = RegisterForm()
    if form.validate_on_submit():
        # 1. 从前端获取用户输入的值;
        email = form.email.data
        username = form.username.data
        password = form.password.data
        # 2. 判断用户是否已经存在? 如果返回位None,说明可以注册;
        u = User.query.filter_by(username=username).first()
        if u:
            flash("用户%s已经存在" % (u.username))
            return redirect(url_for('register'))
        else:
            u = User(username=username, email=email)
            u.password = password
            db.session.add(u)
            db.session.commit()
            flash("注册用户%s成功" % (u.username))
            return redirect(url_for('login'))
    return render_template('register.html',
                           form=form)


# 登录页面
@app.route('/login/', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        username = form.username.data
        password = form.password.data
        # 1. 判断用户是否存在?
        u = User.query.filter_by(username=username).first()
        if u and u.verify_password(password):
            session['user_id'] = u.id
            session['user'] = u.username
            flash("登录成功!")
            return redirect(url_for('index'))
        else:
            flash("用户名或者密码错误!")
            return redirect(url_for('login'))
    return render_template('login.html',
                           form=form)


# 退出页面
@app.route('/logout/')
@is_login
def logout():
    session.pop('user_id', None)
    session.pop('user', None)
    return redirect(url_for('login'))


# 添加任务
@app.route('/todo/add/', methods=['GET', 'POST'])
@is_login
def todo_add():
    form = AddTodoForm()
    if form.validate_on_submit():
        # 获取用户提交的内容
        content = form.content.data
        category_id = form.category.data
        # 添加到数据库中
        # 用户登录才可以添加任务,
        todo = Todo(content=content,
                    category_id=category_id,
                    user_id=session.get('user_id'))
        db.session.add(todo)
        db.session.commit()
        flash("任务添加成功")
        return redirect(url_for('todo_add'))
    return render_template('todo/add_todo.html',
                           form=form)


# 编辑任务
@app.route('/todo/edit/<int:id>/', methods=['GET', 'POST'])
@is_login
def todo_edit(id):
    form = EditTodoForm()
    # *****重要: 编辑时需要获取原先任务的信息, 并显示到表单里面
    todo = Todo.query.filter_by(id=id).first()
    form.content.data = todo.content
    form.category.data = todo.category_id
    if form.validate_on_submit():
        # 更新时获取表单数据一定要使用request.form方法获取, 而form.content.data并不能获取用户更新后提交的表单内容
        # print(request.form)
        # content = form.content.data   # error
        # category_id = form.category.data   # error
        content = request.form.get('content')
        category_id = request.form.get('category')
        # 更新到数据库里面
        todo.content = content
        todo.category_id = category_id
        db.session.add(todo)
        db.session.commit()
        flash("更新任务成功")
        return redirect(url_for('list'))
    return render_template('todo/edit_todo.html',
                           form=form)


# 删除任务: 根据任务id删除
@app.route('/todo/delete/<int:id>/')
@is_login
def todo_delete(id):
    todo = Todo.query.filter_by(id=id).first()
    db.session.delete(todo)
    db.session.commit()
    flash("删除任务成功")
    return redirect(url_for('list'))


# 查看任务
@app.route('/todo/list/')
@app.route('/todo/list/<int:page>/')
@is_login
def list(page=1):
    # 任务显示需要分页
    # Todo.query.paginate(page, per_page=5)
    todoPageObj = Todo.query.filter_by(user_id=session.get('user_id')).paginate(page, per_page=app.config[
        'PER_PAGE'])  # 在config.py文件中有设置
    return render_template('todo/list_todo.html',
                           todoPageObj=todoPageObj,
                           )


# 修改任务状态为完成
@app.route('/todo/done/<int:id>/')
@is_login
def done(id):
    todo = Todo.query.filter_by(id=id).first()
    todo.status = True
    db.session.add(todo)
    db.session.commit()
    flash("修改状态成功")
    return redirect(url_for('list'))


# 修改任务状态为未完成
@app.route('/todo/undo/<int:id>')
@is_login
def undo(id):
    todo = Todo.query.filter_by(id=id).first()
    todo.status = False
    db.session.add(todo)
    db.session.commit()
    flash("修改状态成功")
    return redirect(url_for('list'))


# 任务信息显示
@app.route('/showTodo/')
@is_login
def showTodo():
    done_count = Todo.query.filter_by(status=True).count()
    undone_count = Todo.query.filter_by(status=False).count()
    return render_template('todo/show_todo.html',
                           info={
                               '已完成': done_count,
                               '未完成': undone_count
                           })


# 另一种任务信息显示
@app.route('/newShowTodo/')
@is_login
def newShowTodo():
    return render_template('todo/new_show_todo.html')


@app.route('/get_data/')
@is_login
def get_data():
    done_count = Todo.query.filter_by(status=True).count()
    undone_count = Todo.query.filter_by(status=False).count()
    info = {
        'info': ["已完成", "未完成"],
        'count': [done_count, undone_count]
    }
    # 解决中文编码问题
    return json.dumps(info, ensure_ascii=False)

第六步:

form.py

编写所需要的表单信息:

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, ValidationError, SelectField, DateTimeField
from wtforms.validators import DataRequired, Email, Length, EqualTo

# 注册表单

from app.models import User, Category


class RegisterForm(FlaskForm):
    email = StringField(
        label="邮箱",
        validators=[
            DataRequired(),
            Email(),

    ]
)
username = StringField(
    label="用户名",
    validators=[
        DataRequired(),

    ],
)
password = PasswordField(
    label='密码',
    validators=[
        DataRequired(),
        Length(6, 12, "密码必须是6-12位")
    ]
)

repassword = PasswordField(
    label='确认密码',
    validators=[
        EqualTo("password", "密码与确认密码不一致")
    ]
)

submit = SubmitField(
    label="注册"
)

# *****************************************************
# 默认情况下validate_username会验证用户名是否正确, 验证的规则写在函数里面
def validate_username(self, field):
    # filed.data ==== username表单提交的内容
    u = User.query.filter_by(username=field.data).first()
    if u:
        raise ValidationError("用户名%s已经注册" % (u.username))

def validate_email(self, field):
    u = User.query.filter_by(email=field.data).first()
    if u:
        raise ValidationError("邮箱%s已经注册" % (u.email))


# 登录表单

class LoginForm(FlaskForm):
    username = StringField(
        label="用户名",
        validators=[
            DataRequired(),
    ],
)
password = PasswordField(
    label='密码',
    validators=[
        DataRequired(),
        # Length(6, 12, "密码必须是6-12位")
    ]
)
submit = SubmitField(
    label="登录"
)


# 关于任务的基类
class TodoForm(FlaskForm):
    content = StringField(
        label="任务内容",
        validators=[
            DataRequired()
        ]
    )
    # 任务类型
    category = SelectField(
        label="任务类型",
        coerce=int,
        choices=[(item.id, item.name) for item in Category.query.all()]
    )


class AddTodoForm(TodoForm):
    finish_time = DateTimeField(
        label="任务终止日期"
    )
    submit = SubmitField(
        label="添加任务",
    )


class EditTodoForm(TodoForm):
    submit = SubmitField(
        label="编辑任务",
    )

第七步:

根据view.py中的内容,编写html文件:
首先在static/css/main.css文件中新建main.css文件,并写入配置信息
.navbar {
font-size: 130%;
background: whitesmoke;
margin-top: 10px;
padding-top: 5px;
box-shadow: 2px 2px 2px 2px lightgray;
height: 60px;
}

并导入echarts.min.js文件。

base.html

{% extends 'bootstrap/base.html' %}

{% block styles %}
    {#  先继承父类的css样式导入   #}
    {{ super() }}
    <link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
{% endblock %}


{% block scripts %}

{{ super() }}
{#    实质使导入moment.js库的, 通过Flask-moment集成了起来#}
{{ moment.include_moment() }}
<script src="{{ url_for('static', filename='js/echarts.min.js') }}"></script>

{% endblock %}
{% block navbar %}
    <nav class="navbar navbar-default">
        <div class="container-fluid">
            <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                        data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                    <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="#">任务管理</a>
            </div>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
            <ul class="nav navbar-nav">
                <li class="active"><a href="#">主页 <span class="sr-only">(current)</span></a></li>
                <li><a href="{{ url_for('list') }}">用户信息</a></li>
                <li><a href="#">监控</a></li>
                <li><a href="#">新闻</a></li>
                <li><a href="#">音乐</a></li>
                <li><a href="{{ url_for('newShowTodo') }}">数据分析</a></li>

            </ul>

            <ul class="nav navbar-nav navbar-right">
                {#       分类讨论:
                        1. 如果没有登录, 显示登录和注册按钮;
                        2. 如果登录成功, 显示用户名称和注销按钮

        #}
                {% if not session.user %}
                    <li><a href="{{ url_for('login') }}">登录</a></li>
                    <li><a href="{{ url_for('register') }}">注册</a></li>
                {% else %}
                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
                           aria-haspopup="true"
                           aria-expanded="false">当前用户:{{ session.user }} <span class="caret"></span></a>
                        <ul class="dropdown-menu">
                            <li role="separator" class="divider"></li>
                            <li><a href="{{ url_for('logout') }}">注销</a></li>
                        </ul>
                    </li>

                {% endif %}
            </ul>


        </div><!-- /.navbar-collapse -->
    </div><!-- /.container-fluid -->
</nav>


{#让每个页面都可以获取闪现信息闪现#}
{% for item in get_flashed_messages() %}

    <div class="alert alert-warning alert-dismissible" role="alert">
        <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span
                aria-hidden="true">&times;</span></button>
        {{ item }}
    </div>
{% endfor %}
{% endblock %}

register.html

{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block title %}注册页面{% endblock %}
{% block content %}
    <div class="container">
        <div class="col-lg-8 col-lg-offset-2">
            <div class="page-header">
                <h1>
                    注册
                    <small>
                        已有帐号
                        {#                <a href="/login/">登录</a>#}
                        <a href="{{ url_for('login') }}">登录</a>
                    </small>
                </h1>
            </div>
            {{ wtf.quick_form(form) }}
        </div>
    </div>
{% endblock %}

login.html

{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block title %}登录页面{% endblock %}
{% block content %}
    <div class="container">
        <div class="col-lg-8 col-lg-offset-2">
            <div class="page-header">
                <h1>
                    登录
                    <small>
                        没有帐号
                        {#                <a href="/login/">登录</a>#}
                        <a href="{{ url_for('register') }}">注册</a>
                    </small>

            </h1>

        </div>

        {{ wtf.quick_form(form) }}
    </div>


</div>
{% endblock %}

add_todo.html

{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block title %}添加任务{% endblock %}
{% block content %}
    <div class="container">
        <div class="col-lg-8 col-lg-offset-2">
            <div class="page-header">
                <h1>
                  添加任务

            </h1>

        </div>

        {{ wtf.quick_form(form) }}
    </div>


</div>
{% endblock %}

edit_todo.html

{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block title %}编辑任务{% endblock %}
{% block content %}
    <div class="container">
        <div class="col-lg-8 col-lg-offset-2">
            <div class="page-header">
                <h1>
                    编辑任务
                </h1>
            </div>
            {{ wtf.quick_form(form) }}
        </div>
    </div>
{% endblock %}

list_todo.html

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

任务显示
{% endblock %}

{% block content %}
<div class="container">
    <div class="col-lg-8 col-lg-offset-2">

        <div class="page-header">
            <h1>任务显示</h1>
        </div>
        <table class="table table-hover">
            <tr>
                <td>任务内容</td>
                <td>任务状态</td>
                <td>任务分类</td>
                <td>所属用户</td>
                <td>创建时间</td>
                <td>操作</td>
            </tr>

            {% for todo in todoPageObj.items %}

                <tr>
                    {% if todo.status %}
                        <td>
                            <del>{{ todo.content }}</del>

                        </td>
                    {% else %}

                        <td>{{ todo.content }}</td>
                    {% endif %}

                    <td>
                        {% if todo.status %}
                            <a href="{{ url_for('undo', id=todo.id) }}" style="color:green ">
                                <span class="glyphicon glyphicon-ok"
                                      aria-hidden="true">
                            </span></a>
                        {% else %}
                            <a href="{{ url_for('done', id=todo.id) }}" style="color: mediumvioletred"><span
                                    class="glyphicon glyphicon-remove"
                                    aria-hidden="true">

                            </span></a>
                        {% endif %}

                    </td>
                    <td>{{ todo.category.name }}</td>
                    <td>{{ todo.user.username }}</td>
                    {#                        <td>{{ moment(todo.add_time).format('L') }}</td>#}
                    <td>{{ moment(todo.add_time).fromNow(refresh=True) }}</td>
                    <td>
                        <a class="btn btn-success" href="{{ url_for('todo_edit', id=todo.id) }}"
                           role="button">编辑</a>
                        <a class="btn btn-danger" href="{{ url_for('todo_delete', id=todo.id) }}"
                           role="button">删除</a>

                    </td>
                </tr>
            {% endfor %}
        </table>


        {#        # Day36 templates/list.html#}

        <nav aria-label="Page navigation">
            <ul class="pagination">
                {#
1. 上一页的显示url获取
    /list/2/ ===== url_for('list', todoPageObj.prev_num)

2. 上一页信息逻辑判断
    1). 判断是否有上一页信息;
    2). 如果有, 创建链接;
    3). 如果没有, 该链接设为不可点击的链接

3. 上一页显示使用的类属性和方法:
    1). dataObj.has_prev:
        判断用户是否有上一页?
        如果有,返回True; 如果没有,返回False;

    2).dataObj.prev_num:
        获取上一页的页数编号;
#}
                    {% if todoPageObj.has_prev %}
                        <li>

                        <a href="{{ url_for('list', page=todoPageObj.prev_num) }}" aria-label="Previous">
                            <span aria-hidden="true">&laquo;</span>
                        </a>
                    </li>
                {% else %}
                    <li class="disabled">
                        <a href="#" aria-label="Previous">
                            <span aria-hidden="true">&laquo;</span>
                        </a>
                    </li>

                {% endif %}


                {#
                 详细页的显示
                 依次创建每个分页表框:
    1). 是否为none, 设置类名为diabled;
    2). 是否为当前页, 设置类名为active;
    3).其他,正常设置;




                {% for page in todoPageObj.iter_pages() %}
                    {% if page is none %}
                        <li class="disabled"><a href="#">......</a></li>
                    {% elif page == todoPageObj.page %}

                        <li class="active"><a href="{{ url_for('list', page=page) }}">{{ page }}</a></li>
                    {% else %}
                        <li><a href="{{ url_for('list', page=page) }}">{{ page }}</a></li>
                    {% endif %}
                {% endfor %}


                {#
1.下一页信息判断逻辑
    1). 判断是否有下一页信息;
    2). 如果有, 创建链接;
    3). 如果没有, 该链接设为不可点击的链接

2. 使用的方法:
    1). dataObj.has_next:
        判断用户是否有下一页?
        如果有,返回True; 如果没有,返回False;
    2).dataObj.next_num: 获取下一页的页数编号;
#}
                    {% if todoPageObj.has_next %}
                        <li>
                            <a href="{{ url_for('list', page=todoPageObj.next_num) }}" aria-label="Next">
                                <span aria-hidden="true">&raquo;</span>
                            </a>
                        </li>
                {% else %}
                    <li class="disabled">
                        <a href="#" aria-label="Next">
                            <span aria-hidden="true">&raquo;</span>
                        </a>
                    </li>
                {% endif %}

            </ul>
        </nav>


    </div>

</div>

   {% endblock %}

show_todo.html

{% extends 'base.html' %}

{% block title %}

    图表分析
{% endblock %}


{% block scripts %}
    {{ super() }}
    <script type="text/javascript">
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('main'));

        // 指定图表的配置项和数据
        var option = {
            title: {
                text: '任务完成度分析',

            },
            tooltip: {
                trigger: 'item',
                formatter: "{a} <br/>{b}: {c} ({d}%)"
            },
            legend: {
                orient: 'vertical',
                x: 'right',
                data: ['已完成', '未完成',]
            },
            series: [
                {
                    name: '访问来源',
                    type: 'pie',
                    radius: ['50%', '70%'],
                    avoidLabelOverlap: false,
                    label: {
                        normal: {
                            show: false,
                            position: 'center'
                        },
                        emphasis: {
                            show: true,
                            textStyle: {
                                fontSize: '20',
                                fontWeight: 'bold'
                            }
                        }
                    },
                    labelLine: {
                        normal: {
                            show: false
                        }
                    },
                    data: [
                        {value: 20, name: '已完成'},
                        {value: 80, name: '未完成'},

                    ]
                }
            ]

        };

        // 使用刚指定的配置项和数据显示图表。
        myChart.setOption(option);
    </script>

{% endblock %}
{% block content %}
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
    <div id="main" style="width: 500px;height:500px;
    border: 1px solid gray"></div>

{% endblock %}

new_show_todo.html

{% extends 'base.html' %}

{% block title %}

图表分析
{% endblock %}


{% block scripts %}
    {{ super() }}
    <script type="text/javascript">


        $(function () {
            // 基于准备好的dom,初始化echarts实例
            var myChart = echarts.init(document.getElementById('main'));
            $.ajax({
                url: '/get_data/',
                success: function (data) {
                    json_data = JSON.parse(data)

                    // 指定图表的配置项和数据
                    var option = {
                        title: {
                            text: '任务统计分析'
                        },
                        tooltip: {
                            trigger: 'item',
                            formatter: "{a} <br/>{b}: {c} ({d}%)"
                        },
                        legend: {
                            orient: 'vertical',
                            x: 'right',
                            data: json_data['info']
                        },
                        series: [
                            {
                                name: '访问来源',
                                type: 'pie',
                                radius: ['50%', '70%'],
                                avoidLabelOverlap: false,
                                label: {
                                    normal: {
                                        show: false,
                                        position: 'center'
                                    },
                                    emphasis: {
                                        show: true,
                                        textStyle: {
                                            fontSize: '20',
                                            fontWeight: 'bold'
                                        }
                                    }
                                },
                                labelLine: {
                                    normal: {
                                        show: false
                                    }
                                },
                                data: json_data['count']
                            }
                        ]

                    };
                    // 使用刚指定的配置项和数据显示图表。
                    myChart.setOption(option);

                }
            })


        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('cpu'));
        $.ajax({
            url: '/get_cpu/',
            success: function (data) {
                json_data = JSON.parse(data)

                // 指定图表的配置项和数据
                var option = {
                    title: {
                        text: 'CPU占有率'
                    },
                    tooltip: {
                        trigger: 'item',
                        formatter: "{a} <br/>{b}: {c} ({d}%)"
                    },
                    legend: {
                        orient: 'vertical',
                        x: 'right',
                        data: json_data['info']
                    },
                    series: [
                        {
                            name: '访问来源',
                            type: 'pie',
                            radius: ['50%', '70%'],
                            avoidLabelOverlap: false,
                            label: {
                                normal: {
                                    show: false,
                                    position: 'center'
                                },
                                emphasis: {
                                    show: true,
                                    textStyle: {
                                        fontSize: '20',
                                        fontWeight: 'bold'
                                    }
                                }
                            },
                            labelLine: {
                                normal: {
                                    show: false
                                }
                            },
                            data: json_data['count']
                        }
                    ]

                };
                // 使用刚指定的配置项和数据显示图表。
                myChart.setOption(option);

            }
        })
    })


</script>

{% endblock %}
{% block content %}

<div class="container">
    <div class="col-lg-8 col-lg-offset-2">

        <div class="page-header">
            任务完成度分析
        </div>
        <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
        <div id="main" style="width: 500px;height:500px;
border: 1px solid gray"></div>

    </div>
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
    <div id="cpu" style="width: 500px;height:500px;
border: 1px solid gray"></div>

</div>

</div>

{% endblock %}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值