zoukankan      html  css  js  c++  java
  • (四)flask搭建博客系列之FlaskForm

    本篇博客介绍Flask中的表单工具FlaskForm的使用,并搭建一个简易的管理员后台。

    1.相关库安装

    pip install flask_wtf
    

    2.相关代码

    在myblog文件下建立forms.py用于存放表单类,在home目录下新建admin.py用于存放管理员相关的视图函数,在templates目录下新建admin文件夹,并在该文件夹下建立login.html、edit.html、add.html,分别为登录界面、博客管理界面和新建博客界面。项目目录变更如下:

    在forms.py中添加登录表单和新建博客表单:

    from flask_wtf import FlaskForm
    from wtforms import StringField, PasswordField, BooleanField, SubmitField, TextAreaField, SelectField
    from wtforms.validators import DataRequired, Length
    
    from myblog.models import Category
    
    
    class LoginForm(FlaskForm):
        username = StringField('Username', validators=[DataRequired(), Length(1, 20)])
        password = PasswordField('Password', validators=[DataRequired(), Length(1, 128)])
        remember = BooleanField('Remember me')
        submit = SubmitField('Log in')
    
    
    class AddForm(FlaskForm):
        title = StringField('Title', validators=[DataRequired(), Length(1, 20)])
        body = TextAreaField('Body', validators=[DataRequired()])
        category = SelectField('Category', coerce=int, default=1)
        submit = SubmitField()
    
        def __init__(self, *args, **kwargs):
            super(AddForm, self).__init__(*args, **kwargs)
            self.category.choices = [(category.id, category.name)
                                     for category in Category.query.order_by(Category.name).all()]
    

    由于表单提交会涉及跨域访问问题CSRF,所以需要在config.py中添加一个 SECRET_KEY 字段:

    class Config(object):
        SQLALCHEMY_DATABASE_URI = 'mysql+cymysql://root:root@localhost:3306/myflask?charset=utf8'
        SQLALCHEMY_TRACK_MODIFICATIONS = True
    
        SECRET_KEY = "you will never known it."
    

    存放视图函数的admin.py:

    from flask import request, Blueprint, render_template, redirect, url_for, flash
    
    from myblog.models import Article, Category, Comment, Admin
    from myblog.forms import LoginForm, AddForm
    from myblog.extensions import db
    
    
    admin_bp = Blueprint('admin', __name__)
    
    
    @admin_bp.route('/login', methods=['POST', 'GET']) 
    def login():
        form = LoginForm()
        if form.validate_on_submit():
            username = form.username.data
            password = form.password.data
            remember = form.remember.data
            admin = Admin.query.first()
    
            if username == admin.username and admin.validate_password(password):
                flash('登录成功', category='info')
                return redirect(url_for('admin.edit'))
            else:
                flash('登录失败', category='warning')
        return render_template('admin/login.html', form=form)
    
    
    @admin_bp.route('/edit')
    def edit():
        page = request.args.get('page', 1, type=int)
        articles = Article.query.order_by(Article.timestamp.desc()).paginate(page, 10, False)
    
        return render_template('admin/edit.html', articles=articles)
    
    
    @admin_bp.route('/delete/<int:article_id>')
    def delete(article_id):
        article = Article.query.filter(Article.id == article_id).first()
        db.session.delete(article)
        db.session.commit()
        flash('删除成功', category='info')
    
        return redirect(url_for('admin.edit')) 
    
    
    @admin_bp.route('/add', methods=['POST', 'GET'])
    def add():
        form = AddForm()
        if form.validate_on_submit():
            title = form.title.data
            body = form.body.data
            category = form.category.data
    
            article = Article(title=title, body=body, category_id=category)
            db.session.add(article)
            db.session.commit()
            flash('新建博客成功', category='info')
            return redirect(url_for('admin.edit'))
    
        return render_template('admin/add.html', form=form)
    

    初始化代码__init__.py中注册admin蓝本:

    from flask import Flask
    
    from myblog.home.blog import blog_bp
    from myblog.home.admin import admin_bp
    from myblog.extensions import db, migrate, bootstrap
    from myblog.config import Config
    
    
    def create_app():
        app = Flask(__name__)
        app.config.from_object(Config)
    
        register_blueprints(app)
        register_extensions(app)
    
        return app
    
    
    def register_blueprints(app):
        app.register_blueprint(blog_bp)
        app.register_blueprint(admin_bp, url_prefix='/admin')
    
    
    def register_extensions(app):
        db.init_app(app)
        db.create_all(app=app)
        migrate.init_app(app, db)
        bootstrap.init_app(app)
    

    登录页面login.html:

    {% extends 'base.html' %}
    
    {% block title %}
    Login
    {% endblock %}
    
    {% block content %}
    
    <br />
    {% from 'bootstrap/form.html' import render_form %}
    {{ render_form(form) }}
    
    {% endblock %}
    

    管理后台页面edit.html:

    {% extends 'base.html' %}
    
    {% block title %}
    Admin
    {% endblock %}
    
    {% block content %}
    
    <div class="col-sm-8">
        <br />
        <a class="btn btn-info" href="{{ url_for('admin.add') }}">新建博客</a>
        <br />
        <br />
    
        <ul class="list-group">
            {% for article in articles.items %}
            <li class="list-group-item">
                <h4 style="display:block;float:left;padding-top:2px">
                    {{ article.title }}
                </h4>
                <div style="display:block;float: right;">
                    <a class="btn btn-primary" href="{{ url_for('blog.article', article_id=article.id) }}">查看</a>
                    <a class="btn btn-danger" href="{{ url_for('admin.delete', article_id=article.id) }}">删除</a>
                </div>
            </li>
            {% endfor %}
        </ul>
    
        
        <nav aria-label="Page navigation example" class="m-4">
            <ul class="pagination justify-content-center">
                <li class="page-item {% if not articles.has_prev %}disabled{% endif %}">
                    <a class="page-link" href="{{ url_for('admin.edit', page=articles.prev_num) }}">上一页</a>
                </li>
    
                {% for page in articles.iter_pages(1,1,3,2) %} 
                    {% if page %}
                    <li class="page-item {%if page==articles.page%}active{%endif%}">
                        <a class="page-link" href="{{ url_for('admin.edit',page=page) }}">{{page}}</a>
                    </li>
                    {% else %}
                    <li class="page-item disabled">
                        <a class="page-link" href="#">&hellip;</a>
                    </li>
                    {% endif %} 
                {% endfor %}
    
                <li class="page-item {% if not articles.has_next %}disabled{% endif %}">
                    <a class="page-link" href="{{ url_for('admin.edit',page=articles.next_num) }}">下一页</a>
                </li>
            </ul>
        </nav>
    </div>
    
    {% endblock %}
    

    新建博客页面add.html:

    {% extends 'base.html' %}
    
    {% block title %}
    Add
    {% endblock %}
    
    {% block content %}
    
    <br />
    {% from 'bootstrap/form.html' import render_form %}
    {{ render_form(form) }}
    
    {% endblock %}
    

    将之前base.html中的登录链接地址修改为admin.login,并添加展示flash消息的代码:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        {% block head %}
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> 
            {% block styles %}
                <link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}"> {{ bootstrap.load_css() }} 
            {% endblock %} 
            <title>{% block title %}{% endblock %}</title>
        {% endblock %}
    </head>
    
    <body>
        {% for message in get_flashed_messages() %}
            <div class="alert alert-primary" role="alert">
                {{ message }}
            </div>
            {% endfor %}
        {% block nav %}
            <nav class="navbar navbar-expand-lg navbar-light bg-light">
                <div class="container">
                    <a class="navbar-brand" href="#">我的博客</a>
            
                    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                            <span class="navbar-toggler-icon"></span>
                        </button>
            
                    <div class="collapse navbar-collapse" id="navbarSupportedContent">
                        <ul class="navbar-nav mr-auto">
                            <li class="nav-item {% if request.endpoint == 'blog.index' %} active {% endif %}">
                                <a class="nav-link" href="{{ url_for('blog.index') }}">首页<span class="sr-only">(current)</span></a>
                            </li>
                        </ul>
            
                        <ul class="navbar-nav">
                            <li class="nav-item {% if request.endpoint == 'blog.index' %} active {% endif %}">
                                <a class="nav-link" href="{{ url_for('admin.login') }}">登录</a>
                            </li>
                        </ul>
                    </div>
                </div>
            </nav>
        {% endblock nav %}
    
        <div class="container">
            {% block content %}{% endblock%}
        </div>
    
        {% block scripts %}
            {{ bootstrap.load_js() }} 
        {% endblock %}
    
    </body>
    
    </html>
    

    3.页面展示

    登录页面:

    管理后台页面:

    新建博客页面:

  • 相关阅读:
    vue的工作机制
    koa中的执行顺序
    vue项目中的keep-alive缓存
    vue项目中组件的重新初始化
    常用的JS代码块收集
    每个程序员都必须遵守的编程原则--转了
    自己写操作系统 2
    自己写操作系统 1
    【转】Hadoop安装教程_单机/伪分布式配置_Hadoop2.6.0/Ubuntu14.04
    ubuntu14.04LTS openssh-server 手动安装配置步骤
  • 原文地址:https://www.cnblogs.com/qxcheng/p/13748811.html
Copyright © 2011-2022 走看看