Flask中的其他控件

Day04

1.分页器方法

分页器
	BaseQuery.paginate()
		page
		per_page
		False
	Pagination
		items
		pages
			获取总页数
		prev_num
			上一页的页码
		has_prev
			是否有上一页
		next_num
			下一个页码
		has_next
			是否有下一页
		iter_pages

李晶:

__init__.py
from flask import Flask
from App import settings
from App.ext import init_ext
def create_app(envname):
    app = Flask(__name__)

    app.config.from_object(settings.ENV_NAME.get(envname))

    init_ext(app)
    return app

ext.py
# flask-script
# flask-blueprint
# flask-session
# flask-sqlalchemy
# flask-migrate
from flask_bootstrap import Bootstrap
from flask_debugtoolbar import DebugToolbarExtension
from flask_migrate import Migrate
from flask_session import Session
from App.models import db


def init_ext(app):

    app.config['SECRET_KEY']='110'
    app.config['SESSION_TYPE']='redis'
    Session(app=app)

    db.init_app(app=app)

    migrate = Migrate()
    migrate.init_app(app=app,db=db)

    Bootstrap(app=app)

    app.debug = True
    # debugtoolbar
    debugtoolbar = DebugToolbarExtension()
    debugtoolbar.init_app(app=app)

models.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

class Emp(db.Model):
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    name = db.Column(db.String(32))
    age = db.Column(db.Integer,default=18)
    gender = db.Column(db.String(2))
    salary = db.Column(db.Float)


class Parent(db.Model):
    id=db.Column(db.Integer,primary_key=True,autoincrement=True)
    name=db.Column(db.String(30),unique=True)
    # Child对应的表  backref 子表外键描述需要
    children=db.relationship("Child",backref="parent",lazy=True)


class Child(db.Model):
    id = db.Column(db.Integer, primary_key=True,autoincrement=True)
    name = db.Column(db.String(30), unique=True)
    parent_id = db.Column(db.Integer, db.ForeignKey('parent.id'))


class User(db.Model):
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    name = db.Column(db.String(32))
    age = db.Column(db.Integer,default=18)

class Movie(db.Model):
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    name = db.Column(db.String(32))

class Collection(db.Model):
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    u_id = db.Column(db.Integer,db.ForeignKey(User.id))
    m_id = db.Column(db.Integer,db.ForeignKey(Movie.id))

setting.py

def get_database_uri(DATABASE):
    dialect = DATABASE.get('dialect')
    driver = DATABASE.get('driver')
    username = DATABASE.get('username')
    password = DATABASE.get('password')
    host = DATABASE.get('host')
    port = DATABASE.get('port')
    database = DATABASE.get('database')
    return '{}+{}://{}:{}@{}:{}/{}'.format(dialect,driver,username,password,host,port,database)


class Config():
    Test = False
    Debug = False
    SQLALCHEMY_TRACK_MODIFICATIONS = False

class DevelopConfig(Config):
    Debug = True

    DATABASE={
        'dialect':'mysql',
        'driver':'pymysql',
        'username':'root',
        'password':'1234',
        'host':'localhost',
        'port':'3306',
        'database':'flaskday04',
    }
    SQLALCHEMY_DATABASE_URI=get_database_uri(DATABASE)

ENV_NAME={
    'develop':DevelopConfig
}


views.py
from flask import Blueprint, render_template, request, redirect, url_for

from App.models import Emp, db, Parent, Child, Collection

blue = Blueprint('blue',__name__)


@blue.route('/')
def hello_world():
    return 'Hello World!'


@blue.route('/list/')
def list():
    emps = Emp.query.all()

    return render_template('userList.html',emps=emps)

@blue.route('/toadd/')
def toadd():
    return render_template('add.html')

@blue.route('/add/',methods=['get','post'])
def add():
    name = request.form.get('name')
    age = request.form.get('age')
    gender = request.form.get('gender')
    salary = request.form.get('salary')
    print(name,age,gender,salary)

    emp = Emp()
    emp.name = name
    emp.age = age
    emp.gender = gender
    emp.salary = salary
    db.session.add(emp)
    db.session.commit()
    return redirect(url_for('blue.list'))

@blue.route('/delete/')
def delete():
    id = request.args.get('id')
    emp = Emp.query.get(id)
    db.session.delete(emp)
    db.session.commit()

    return redirect(url_for('blue.list'))


@blue.route('/toupdate/')
def toupdate():
    id = request.args.get('id')
    emp = Emp.query.get(id)
    return render_template('update.html',emp=emp)


@blue.route('/update/',methods=['get','post'])
def update():
    id = request.args.get('id')
    emp = Emp.query.get(id)
    name = request.form.get('name')
    age = request.form.get('age')
    gender = request.form.get('gender')
    salary = request.form.get('salary')

    emp.name=name
    emp.age = age
    emp.gender = gender
    emp.salary = salary

    db.session.add(emp)
    db.session.commit()
    return redirect(url_for('blue.list'))

# 添加主键对象  会不会直接将外键添加
@blue.route('/saveparent/')
def saveparent():
    p = Parent()
    p.name = '张三'

    c = Child()
    c.name = '张四'

    c1 = Child()
    c1.name = '王五'

    p.children=[c,c1]

    db.session.add(p)
    db.session.commit()
    return 'add success'

# 从查主
# select * from parent where  id = (select pid from Child where id = 1)
# 主查从
# select * from Child where pid = (select id from Parent where id = 1)
# 查询

@blue.route('/getparent/')
def getparent():
    p = Parent.query.filter(Child.parent_id == 1).first()
    # print(p[0].name)
    print(p.name)
    return 'ok'

@blue.route('/getchild/')
def getchild():
    clist = Child.query.filter(Parent.id == 1)
    for c in clist:
        print(c.name)
    return 'ok'


# 多对多的添加
# 将用户id和电影id 获取      然后去数据库中查找 是否存在 如果存在那就告诉已经添加到购物车
# 否则 添加到购物车
@blue.route('/addcollection/')
def addcolletion():
    u_id = int(request.args.get('u_id'))
    m_id = int(request.args.get('m_id'))
    print(u_id,m_id)
    c = Collection.query.filter(Collection.u_id == u_id).filter(Collection.m_id==m_id)

    if c.count() > 0:
        return '已经添加到购物车'
    else:
        c1 = Collection()
        c1.u_id = u_id
        c1.m_id = m_id
        db.session.add(c1)
        db.session.commit()

        return 'ok'


@blue.route('/bootstrapDemo/')
def bootstrapDemo():
    # emps = Emp.query.all()
    page = int(request.args.get('page',1))
    per_page = int(request.args.get('per_page',2))

    pagination = Emp.query.paginate(page=page,per_page=per_page,error_out=False)

    return render_template('bootstrapDemo.html',pagination=pagination)

manager.py
from flask_migrate import MigrateCommand
from flask_script import Manager

from App import create_app
from App.views import blue

app = create_app('develop')

manager = Manager(app=app)

app.register_blueprint(blueprint=blue)

manager.add_command('db',MigrateCommand)


if __name__ == '__main__':
    manager.run()

templates:

add.html
<html>
	<head>
		<title>regist</title>
		<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
		<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
	</head>
	<body>
		<div id="wrap">
			<div id="top_content">
				<div id="header">
					<div id="rightheader">
						<p>
							2009/11/20
							<br />
						</p>
					</div>
					<div id="topheader">
						<h1 id="title">
							<a href="#">Main</a>
						</h1>
					</div>
					<div id="navigation">
					</div>
				</div>

				<div id="content">
					<p id="whereami">
					</p>
					<h1>
						注册
					</h1>
					<form action="{{ url_for('blue.add') }}" method="post">
						<table cellpadding="0" cellspacing="0" border="0"
							class="form_table">
							<tr>
								<td valign="middle" align="right">
									用户名:
								</td>
								<td valign="middle" align="left">
									<input type="text" class="inputgri" name="name" />
								</td>
							</tr>


							<tr>
								<td valign="middle" align="right">
									年龄:
								</td>
								<td valign="middle" align="left">
									<input type="text" class="inputgri" name="age" />
								</td>
							</tr>
							<tr>
								<td valign="middle" align="right">
									性别:
								</td>
								<td valign="middle" align="left">
									男
									<input type="radio" class="inputgri" name="gender" value="男"
										checked="checked" />
									女
									<input type="radio" class="inputgri" name="gender" value="女" />
								</td>
							</tr>
							<tr>
								<td valign="middle" align="right">
                                    薪水:
								</td>
								<td valign="middle" align="left">
									<input type="text" class="inputgri" name="salary" />
								</td>
							</tr>


						</table>
						<p>
							<input type="submit" class="button" value="添加" />
						</p>
					</form>
				</div>
			</div>
			<div id="footer">
				<div id="footer_bg">
					ABC@126.com
				</div>
			</div>
		</div>
	</body>
</html>

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


{% block navbar %}
    <nav class="navbar navbar-inverse">
        <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="#">企业文化</a></li>
                </ul>
                <form class="navbar-form navbar-left">
                    <div class="form-group">
                        <input type="text" class="form-control" placeholder="请输入员工姓名">
                    </div>
                    <button type="submit" class="btn btn-default">搜索</button>
                </form>
                <ul class="nav navbar-nav navbar-right">
                    <li><a href="#">注册</a></li>
                    <li><a href="#">登录</a></li>
                </ul>
            </div><!-- /.navbar-collapse -->
        </div><!-- /.container-fluid -->
    </nav>

{% endblock %}







{% block content %}
    <div class="container">
        <div class="jumbotron">
            <h1>welcome to red langman</h1>
            <p>...</p>
            <p><a class="btn btn-primary btn-lg" href="#" role="button">go</a></p>
        </div>
    </div>

    <div align="center">
        <table width="800" height="150" border="1" align="center">
            <tr>
                <th>id</th>
                <th>name</th>
                <th>age</th>
                <th>gender</th>
                <th>salary</th>
                <th>operate</th>
            </tr>
            {% for emp in pagination.items %}
                <tr>
                    <td>{{ emp.id }}</td>
                    <td>{{ emp.name }}</td>
                    <td>{{ emp.age }}</td>
                    <td>{{ emp.gender }}</td>
                    <td>{{ emp.salary }}</td>
                    <td>
                        <a>删除</a>
                        <a>修改</a>
                    </td>
                </tr>
            {% endfor %}

        </table>


    </div>

    <div align="center">
        <nav aria-label="Page navigation">
            <ul class="pagination">
                <li>
                    {% if pagination.has_prev %}
                        <a href="{{ url_for('blue.bootstrapDemo') }}?page={{ pagination.prev_num }}" aria-label="Previous">
                            <span aria-hidden="true">上一页</span>
                        </a>
                    {% else %}
                        <a href="#" aria-label="Previous">
                            <span aria-hidden="true">上一页</span>
                        </a>
                    {% endif %}

                </li>
                {% for p in pagination.iter_pages() %}
                    <li><a href="#">{{ p }}</a></li>
                {% endfor %}



                <li>
                    {% if pagination.has_next %}
                        <a href="{{ url_for('blue.bootstrapDemo') }}?page={{ pagination.next_num }}" aria-label="Next">
                            <span aria-hidden="true">下一页</span>
                        </a>
                    {% else %}
                        <a href="#" aria-label="Next">
                            <span aria-hidden="true">下一页</span>
                        </a>
                    {% endif %}
                </li>
            </ul>
        </nav>

    </div>

{% endblock %}

login.html
<html>
	<head>
		<title>login</title>
		<meta http-equiv="content-type" content="text/html;charset=utf-8" />
		<link rel="stylesheet" type="text/css" href="css/style.css" />
	</head>

	<body>
		<div id="wrap">
			<div id="top_content">
				<div id="header">
					<div id="rightheader">
						<p>
							2009/11/20
							<br />
						</p>
					</div>
					<div id="topheader">
						<h1 id="title">
							<a href="#">Main</a>
						</h1>
					</div>
					<div id="navigation">
					</div>
				</div>
				<div id="content">
					<p id="whereami">
					</p>
					<h1>
						login
					</h1>
					<form action="userList.html" method="post">
						<table cellpadding="0" cellspacing="0" border="0"
							class="form_table">
							<tr>
								<td valign="middle" align="right">
									username:
								</td>
								<td valign="middle" align="left">
									<input type="text" class="inputgri" name="username" />
								</td>
							</tr>
							<tr>
								<td valign="middle" align="right">
									password:
								</td>
								<td valign="middle" align="left">
									<input type="password" class="inputgri" name="pwd" />
								</td>
							</tr>
						</table>
						<p>
							<input type="submit" class="button" 
							value="&nbsp;确定&nbsp;" />
							<a href="regist.html">还没有帐户,请点击这儿注册</a>
						</p>
					</form>
				</div>
			</div>
			<div id="footer">
				<div id="footer_bg">
					ABC@126.com
				</div>
			</div>
		</div>
	</body>
</html>


regist.html
<html>
	<head>
		<title>regist</title>
		<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
		<link rel="stylesheet" type="text/css" href="css/style.css" />
	</head>
	<body>
		<div id="wrap">
			<div id="top_content">
				<div id="header">
					<div id="rightheader">
						<p>
							2009/11/20
							<br />
						</p>
					</div>
					<div id="topheader">
						<h1 id="title">
							<a href="#">Main</a>
						</h1>
					</div>
					<div id="navigation">
					</div>
				</div>

				<div id="content">
					<p id="whereami">
					</p>
					<h1>
						注册
					</h1>
					<form action="login.html" method="post">
						<table cellpadding="0" cellspacing="0" border="0"
							class="form_table">
							<tr>
								<td valign="middle" align="right">
									用户名:
								</td>
								<td valign="middle" align="left">
									<input type="text" class="inputgri" name="username" />
								</td>
							</tr>
							<tr>
								<td valign="middle" align="right">
									真实姓名:
								</td>
								<td valign="middle" align="left">
									<input type="text" class="inputgri" name="name" />
								</td>
							</tr>
							<tr>
								<td valign="middle" align="right">
									密码:
								</td>
								<td valign="middle" align="left">
									<input type="password" class="inputgri" name="pwd" />
								</td>
							</tr>
							<tr>
								<td valign="middle" align="right">
									年龄:
								</td>
								<td valign="middle" align="left">
									<input type="text" class="inputgri" name="age" />
								</td>
							</tr>
							<tr>
								<td valign="middle" align="right">
									性别:
								</td>
								<td valign="middle" align="left">
									男
									<input type="radio" class="inputgri" name="sex" value="m"
										checked="checked" />
									女
									<input type="radio" class="inputgri" name="sex" value="f" />
								</td>
							</tr>
							<tr>
								<td valign="middle" align="right">
									电话:
								</td>
								<td valign="middle" align="left">
									<input type="text" class="inputgri" name="phone" />
								</td>
							</tr>
							<tr>
								<td valign="middle" align="right">
									对方要求:
								</td>
								<td valign="middle" align="left">
									<textarea rows="5" cols="30" name="ask" style="resize:none;"></textarea>
								</td>
							</tr>
							<tr>
								<td valign="middle" align="right">
									验证码:
									<img id="num" src="checkCode" />
									<a href="javascript:;"
										onclick="document.getElementById('num').src = 'checkCode?'+(new Date()).getTime()">换一张</a>
								</td>
								<td valign="middle" align="left">
									<input type="text" class="inputgri" name="number" />
								</td>
							</tr>
						</table>
						<p>
							<input type="submit" class="button" value="Submit &raquo;" />
						</p>
					</form>
				</div>
			</div>
			<div id="footer">
				<div id="footer_bg">
					ABC@126.com
				</div>
			</div>
		</div>
	</body>
</html>


update.html
<html>
	<head>
		<title>regist</title>
		<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
		<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
	</head>
	<body>
		<div id="wrap">
			<div id="top_content">
				<div id="header">
					<div id="rightheader">
						<p>
							2009/11/20
							<br />
						</p>
					</div>
					<div id="topheader">
						<h1 id="title">
							<a href="#">Main</a>
						</h1>
					</div>
					<div id="navigation">
					</div>
				</div>

				<div id="content">
					<p id="whereami">
					</p>
					<h1>
						注册
					</h1>
					<form action="{{ url_for('blue.update') }}?id={{ emp.id }}" method="post">
						<table cellpadding="0" cellspacing="0" border="0"
							class="form_table">
                            <tr>
                                <td>id</td>
                                <td>
                                    <input type="text" class="inputgri" name="id" value="{{ emp.id }}" readonly="true">
                                </td>

                            </tr>


							<tr>
								<td valign="middle" align="right">
									用户名:
								</td>
								<td valign="middle" align="left">
									<input type="text" class="inputgri" name="name" value="{{ emp.name }}"/>
								</td>
							</tr>


							<tr>
								<td valign="middle" align="right">
									年龄:
								</td>
								<td valign="middle" align="left">
									<input type="text" class="inputgri" name="age" value="{{ emp.age }}" />
								</td>
							</tr>
							<tr>
								<td valign="middle" align="right">
									性别:
								</td>
								<td valign="middle" align="left">
                                    {% if emp.gender == '男' %}
                                        男
                                        <input type="radio" class="inputgri" name="gender" value="男"
                                            checked="checked" />
                                        女
                                        <input type="radio" class="inputgri" name="gender" value="女" />
                                    {% else %}
                                        男
                                        <input type="radio" class="inputgri" name="gender" value="男"
                                             />
                                        女
                                        <input type="radio" class="inputgri" name="gender" value="女"
                                        checked="checked" />
                                    {% endif %}

								</td>
							</tr>
							<tr>
								<td valign="middle" align="right">
                                    薪水:
								</td>
								<td valign="middle" align="left">
									<input type="text" class="inputgri" name="salary" value="{{ emp.salary }}"/>
								</td>
							</tr>


						</table>
						<p>
							<input type="submit" class="button" value="修改" />
						</p>
					</form>
				</div>
			</div>
			<div id="footer">
				<div id="footer_bg">
					ABC@126.com
				</div>
			</div>
		</div>
	</body>
</html>


userDetail.html
<html>
	<head>
		<title>update Emp</title>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<link rel="stylesheet" type="text/css" href="css/style.css" />
	</head>
	<body>
		<div id="wrap">
			<div id="top_content">
				<div id="header">
					<div id="rightheader">
						<p>
							2009/11/20
							<br />
						</p>
					</div>
					<div id="topheader">
						<h1 id="title">
							<a href="#">Main</a>
						</h1>
					</div>
					<div id="navigation">
					</div>
				</div>

				<div id="content">
					<p id="whereami">
					</p>
					<h1>
						User Detail:
					</h1>
					<table class="table">
						<tr>
							<td>
								姓名
							</td>
							<td>
								电话
							</td>
						</tr>
						<tr>
							<td>
								zhangshan
							</td>
							<td>
								010-12345678
							</td>
						</tr>
					</table>
					<h1>
						对方要求:
					</h1>
					<table>
						<tr>
							<td colspan="2">
								<textarea cols="80" style="border:0px;resize:none;"></textarea>
							</td>
						</tr>
					</table>
					<br/>
					<h1>
						Load Photo:
					</h1>
	
						<form action="userDetail.html" method="post"
							enctype="multipart/form-data">
							Upload File Name:
							<input type="file" name="file1" />
							<input type="submit" value="confirm" />
						</form>

					<h1>
						view photo:
					</h1>
					<table>
								<tr>
									<td>
										<img src="upload/t1.jpg" width="300"
											height="200" />
									</td>
								</tr>
					</table>
				</div>
				<input type="button" onclick="location='userList.html'" value="查看所有用户"/>
			</div>
			<div id="footer">
				<div id="footer_bg">
					ABC@126.com
				</div>
			</div>
		</div>
	</body>
</html>


userlist.html
<html>
	<head>
		<title>emplist</title>
		<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
		<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
        <script type="text/javascript">
            function toadd() {
            {#    企业级开发中不要直接的跳转到某一个页面  必须要通过请求来跳转#}
            {#    window.location.href = '/toadd/'#}
                window.open('/toadd/',target='_self')
            }

        </script>
	</head>
	<body>
		<div id="wrap">
			<div id="top_content">
				<div id="header">
					<div id="rightheader">
						<p>
							2009/11/20
							<br />
						</p>
					</div>
					<div id="topheader">
						<h1 id="title">
							<a href="#">主页面</a>
						</h1>
					</div>
					<div id="navigation">
					</div>
				</div>

				<div id="content">
					<p id="whereami">
					</p>
					<h1>
						Welcome!
					</h1>
					<table class="table">
						<tr class="table_header">
							<td>
								ID
							</td>
							<td>
                                姓名
							</td>
							<td>
								性别
							</td>
							<td>
								年龄
							</td>
							<td>
                                薪水
							</td>
                            <td>
                                操作
							</td>
						</tr>
                        {% for emp in emps %}
                            <tr class="row1">
							<td>
								{{ emp.id }}
							</td>
							<td>
								{{ emp.name }}
							</td>
							<td>
								{{ emp.gender }}
							</td>
							<td>
								{{ emp.age }}
							</td>
                            <td>
                                {{ emp.salary }}
                            </td>
							<td>
                                               {#  /delete/?id=1  #}
								<a href="{{ url_for('blue.delete') }}?id={{ emp.id }}">删除</a>
								<a href='{{ url_for('blue.toupdate') }}?id={{ emp.id }}'>修改</a>
							</td>
						</tr>
                        {% endfor %}

					</table>
					<p>
						<input type="button" class="button" value="添加员工"
							onclick="toadd();" />
					</p>
				</div>
			</div>
			<div id="footer">
				<div id="footer_bg">
					ABC@126.com
				</div>
			</div>
		</div>
	</body>
</html>

2.flask-bootstrap

插件安装
	pip install  flask-bootstrap
ext中初始化
	Bootstrap(app=app)
	
bootstrap案例--bootstrap模板   {% extends ‘bootstrap/base.html’%}

3.FLASK-DEBUGTOOLBAR

辅助调试插件
安装
	pip install flask-debugtoolbar
初始化  ext 
     app.debug = True (最新版本需要添加)
	debugtoolbar = DebugToolBarExtension()
	debugtoolbar.init_app(app=app)

4.缓存flask-cache

1 缓存目的:
          缓存优化加载,减少数据库的IO操作
2 实现方案
          数据库
          文件
          内存
          内存中的数据库 Redis
3 实现流程
	从路由函数进入程序
	路由函数到视图函数
	视图函数去缓存中查找
	缓存中找到,直接进行数据返回
	如果没找到,去数据库中查找
	查找到之后,添加到缓存中
	返回到页面上
4 使用
    安装 flask-cache
		pip  install flask-cache
	初始化
          指定使用的缓存方案
              cache = Cache(config={'CACHE_TYPE':默认是simple})
              cache.init_app(app=app)
          使用
              在路由的下面添加@cache.cached(timeout=30)
          要配置config
              TYPE
              还可以配置各种缓存的配置信息
                  cache=Cache(config={'CACHE_KEY_PREFIX':'python'})
    用法
          装饰器
              @cache.cached(timeout=xxx)
          原生
              get
              set

5.钩子

before_request

6.四大内置对象

四大内置对象
	request
		- 请求的所有信息
	session
		- 服务端会话技术的接口
	config
		当前项目的配置信息
		模板中可以直接使用
			config
		在python代码中
			current_app.config
			当前运行的app
			使用记得是在初始化完成之后
			用在函数中
	g
		global  全局
		可以帮助开发者实现跨函数传递数据

7.路径

	BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
	init中app = Flask(__name__,static_folder=static_folder)
		 static_folder=os.path.join(settings.BASE_DIR,'static')

8.Json

JSON
	json数据不可以直接返回
	json例子   $.getJson
		jquery  cdn

Day05

1.前后端分离

RESTful API

什么是REST

一种软件架构风格、设计风格、而不是标准,只是提供了一组设计原则和

约束条件。它主要用户客户端和服务器交互类的软件。

基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存机制等。

REST全称是Representational State Transfer,表征性状态转移。

首次在2000年Roy Thomas Fielding的博士论文中出现,Fielding是一个

非常重要的人,他是HTTP协议(1.0版和1.1版)的主要设计者,

Apache服务器软件的作者之一,Apache基金会的第一任主席。所以,

他的这篇论文一经发表,就引起了广泛的关注。

论文:

本文研究计算机科学两大前沿----软件和网络----的交叉点。长期以来,

软件研究主要关注软件设计的分类、设计方法的演化,很少客观地评估

不同的设计选择对系统行为的影响。而相反地,网络研究主要关注系统

之间通信行为的细节、如何改进特定通信机制的表现,常常忽视了一个事实,

那就是改变应用程序的互动风格比改变互动协议,对整体表现有更大的影响。

我这篇文章的写作目的,就是想在符合架构原理的前提下,

理解和评估以网络为基础的应用软件的架构设计,得到一个功能强、

性能好、适宜通信的架构。

REST爆发

其实在REST架构推出的十几年间,它并没有一路高歌的发展,

真正的大范围推广是在2013年之后,伴随着移动端的飞速发展,

越来越多人的开始意识到,网站即软件,而且是一种新型的软件。

这种"互联网软件采用"客户端/服务器"模式,也就是我们常说的C/S模式,

这一切建立在分布式体系上,通过互联网通信,具有高延时,高并发等特点。

网站开发,完全采用软件开发开发的模式。但传统上,软件和网络是两个

不同的领域,很少有交集,软件开发主要针对单机环境,网络则主要

研究系统之间的通信。我们需要考虑的是如何开发在互联网环境中使用软件。

理解RESTful

要理解RESTful架构,最好的就是去理解它的单词 Representational State

Transfer 到底是什么意思,它的每一个词到底要表达什么。

REST的释义,“表现层状态转化”,其实这省略了主语。“表现层”其实指的是

“资源(Resource)”的“表现层”。

资源(Resource)

所谓“资源”,就是网络上的一个实体,或者说是网络上的一个具体信息。

它可以是一段文本,一张图片,一首歌曲,一种服务,总之就是一个具体的实例

。你可以使用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI

。要获取这个资源,访问它的URI就可以了,因此URI就成了每一个资源

的地址或独一无二的识别符。所谓“上网”就是与互联网上一系列的“资源”互动

,调用它们的URI。

表现层(Representation)

“资源”是一种信息实体,它可以有多种外在表现形式。我们把“资源”

具体呈现出来的形式,叫做它的”表现层“(Representation)。

URI只代表资源的实体,不代表它的形式。严格地说,有些网站最后的”

.html“后缀名是不必要的,因为这个后缀表示格式,属于”表现层“范畴,

而URI应该只代表”资源“的位置。它的具体表现形式,应该在HTTP请求

头的信息中使用Accept和Content-Type字段指定。

状态转换(State Transfer)

访问一个网站,就代表客户端和服务端的一个互动过程。在这个过程中,

势必涉及到数据和状态的变化。

互联网通信协议HTTP协议,是一个无状态协议。这意味着,

所有的状态都保存在服务端。因此,如果客户端想要操作服务器,

就必须通过某种手段,让服务器端发生”状态转换(State Transfer)“。

而这种转换是建立在表现层之上的,所以就是”表现层状态转化“。

客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议中,

四个表示操作方式的动词:GET,POST,PUT,DELETE。

它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源

(也可用于更新资源),PUT用来更新资源,DELETE用来删除资源

到底什么是RESTful架构

每一个URI代表一种资源

客户端和服务器之间,传递这种资源的某种表现层

客户端通过四个HTTP动词,对服务端资源进行操作,实现”表现层状态转换“

RESTful API设计

协议

API与用户的通信协议,通常使用HTTP(S)协议。

域名

应该尽量将API部署在专用域名之下。

http://api.rock.com

如果确定API很简单,不会有大规模扩充,可以考虑放在主域名之下。

http://www.rock.com/api/

版本

应该将API的版本号放入URL。

http://api.rock.com/v1/

也有做法是将版本号放在HTTP的头信息中,但不如放在URL中方便和直观。

GITHUB是这么搞的。

路径(Endpoint)

路径又称”终点“(endpoint),表示API的具体网址。

在RESTful架构中,每个网址代表一种资源(Resource),

所以网址中不能有动词,只能有名词,而且所用的名词往往与

数据库的表格名对应。一般来说,数据库中的表都是同种记录的”集合“

(collection),所以API中的名词也应该使用复数。

HTTP动词

对于资源的具体操作类型,由HTTP动词表示。

HTTP常用动词

GET(SELECT):从服务器取出资源

POST(CREATE or UPDATE):在服务器创建资源或更新资源

PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)

PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)

DELETE(DELETE):从服务器删除资源

HEAD:获取资源的元数据

OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的、

示例

GET /students:获取所有学生

POST /students:新建学生

GET /students/id:获取某一个学生

PUT /students/id :更新某个学生的信息(需要提供学生的全部信息)

PATCH /students/id:更新某个学生的信息(需要提供学生变更部分信息)

DELETE /students/id:删除某个学生

过滤信息(Filtering)

如果记录数量过多,服务器不可能将它们返回给用户。API应该提供参数,

过滤返回结果。

?limit=10

?offset=10

?page=2&per_page=20

?sortby=name&order=desc

?student_id=id

参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复,

比如 GET /students/id 和 ?student_id=id

状态码

服务器向用户返回的状态码和提示信息,常见的有以下一些地方

200 OK - [GET]:服务器成功返回用户请求的数据

201 CREATED -[POST/PUT/PATCH]:用户新建或修改数据成功

202 Accepted - [*] :表示一个请求已经进入后台排队(异步任务)

204 NO CONTENT - [DELETE]:表示数据删除成功

400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误

401 Unauthorized - [*] :表示用户没有权限(令牌,用户名,密码错误)

403 Forbidden - [*]:表示用户得到授权,但是访问是被禁止的

404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录

406 Not Acceptable - [*]:用户请求格式不可得

410 Gone - [GET] :用户请求的资源被永久移除,且不会再得到的

422 Unprocesable entity -[POST/PUT/PATCH]:当创建一个对象时,

发生一个验证错误

500 INTERNAL SERVER EROR - [*] :服务器内部发生错误

错误处理

如果状态码是4xx,就应该向用户返回出错信息。一般来说,

返回的信息中将error做为键名

返回结果

针对不同操作,服务器想用户返回的结果应该符合以下规范

GET /collection:返回资源对象的列表(数组,集合)

GET /collection/id:返回单个资源对象

POST /collection:返回新生成的资源对象

PUT /collection/id:返回完整的资源对象

PATCH /collection/id:返回完整的资源对象

DELETE /collection/id:返回一个空文档

使用链接关联资源

RESTful API最好做到Hypermedia,即返回结果中提供链接,

连向其他API方法,使得用户不查文档,也知道下一步应该做什么。

{

"link": {

    "rel":   "collection https://www.rock.com/zoostudents",

    "href":  "https://api.rock.com/students",

    "title": "List of students",

    "type":  "application/vnd.yourformat+json"

  }

}

rel:表示这个API与当前网址的关系

href:表示API的路径

title:表示API的标题

type:表示返回的类型

其它

服务器返回的数据格式,应该尽量使用JSON

API的身份认证应该使用OAuth2.0框架

总之

  为什么会出现Restful

在Restful之前的操作:

saveUser

http://127.0.0.1/user/query/1 GET 根据用户id查询用户数据

http://127.0.0.1/user/save POST 新增用户

http://127.0.0.1/user/update POST 修改用户信息

http://127.0.0.1/user/delete GET/POST 删除用户信息

RESTful用法:根据请求提交方式的不同 然后执行对应的方法

http://127.0.0.1/user/1 GET 根据用户id查询用户数据

http://127.0.0.1/user POST 新增用户

http://127.0.0.1/user PUT 修改用户信息

http://127.0.0.1/user DELETE 删除用户信息

if request.method = ‘get’:

User.query.first()

else request.method = ‘post’:

之前的操作是没有问题的,大神认为是有问题的,有什么问题呢?

你每次请求的接口或者地址,都在做描述,例如查询的时候用了query,

新增的时候用了save,其实完全没有这个必要,我使用了get请求,就是查询.

使用post请求,就是新增的请求,我的意图很明显,完全没有必要做描述,

这就是为什么有了restful.

ajax其实质利用浏览器内置ajax对象(xmlhttprequest xhr)

异步的向服务器发送请求

提交的是部分数据

利用返回的数据更新当前页面

整个过程中

页面无刷新

不打断用户的操作

整合网络和软件的一种架构模式
理解
	Representtational
		表现层
	State Transfer
		状态转换
	表现层状态转换
		资源(Resource)
	每一个URI代表一类资源
		对整个数据的操作
		增删改查
RESTful中更推荐使用HTTP的请求谓词(动词)来作为动作标识
	GET
	POST
	PUT
	DELETE
	PATCH
推荐使用json数据传输

状态码
	200 ok
	201 created
	202 Accepted
	204 删除成功 
	400 
	401
		没有认证
	403 
		没有权限
	404
	405 
	406 验证错误
	422 
	500

设计原则
	http(s)协议
	应该有自己专属域名
		在应用上添加一个api前缀
	都是名词,复数形式
	可以将版本号设计进去
		增量操作
	/collection/id/? id=xxx

2.原生实现

概念:就是判断不同的请求方式,实现请求方法
高内聚,低耦合
	高内聚
	相同的数据操作封装在一起
	低耦合
MVC 没有模板--前后端分离
使用
	md5
	    eg:
	    def generate_password(password):
              hash = hashlib.md5()
              hash.update(password.encode("utf-8"))
              return hash.hexdigest()
	get
		坑---类型
		eg:
		@blue.route("/users/<int:id>/", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
        def users(id):
            if request.method == "GET":
                page = int(request.args.get("page", default=1))
                per_page = int(request.args.get("per_page", default=3))

                users = User.query.paginate(page=page, per_page=per_page, error_out=False).items
                users_dict = []
                for user in users:
                    users_dict.append(user.to_dict())

                data = {
                    "message": "ok",
                    "status": "200",
                    "data": users_dict
                }

                return jsonify(data)
	post
		eg:
            elif request.method == "POST":
                  # 更新或创建
                  username = request.form.get("username")
                  password = request.form.get("password")

                  data = {
                      "message": "ok",
                      "status": "422"
                  }

                  if not username or not password:
                      data["message"] = "参数不正确"
                      return jsonify(data), 422

                  user = User()
                  user.u_name = username
                  user.u_password = generate_password(password=password)

                  try:

                      db.session.add(user)
                      db.session.commit()
                      data["status"] = "201"
                  except Exception as e:
                      data["status"] = "901"
                      data["message"] = str(e)
                      return jsonify(data), 422

                  return jsonify(data), 201
	put
		eg:
			elif request.method == "PUT":
                      username = request.form.get("username")
                      password = request.form.get("password")
                      user = User.query.get(id)

                      user.u_name = username
                      user.u_password = generate_password(password)

                      db.session.add(user)
                      db.session.commit()

                      data = {
                          "message": "update success",
                      }

                      return jsonify(data), 201

	delete
		eg:
		    elif request.method == "DELETE":
                    user = User.query.get(id)

                    data = {
                        "message": "delete success"
                    }

                    if user:
                        db.session.delete(user)
                        db.session.commit()
                        return jsonify(data), 204
                    else:
                        data["message"] = "指定数据不存在"
                        return jsonify(data)

	patch
			eg:
			   elif request.method == "PATCH":
                        password = request.form.get("password")
                        user = User.query.get(id)
                        user.u_password = generate_password(password)

                        data = {
                            "messgage": "update success"
                        }

                        db.session.add(user)
                        db.session.commit()

                        return jsonify(data), 201

3.flask-restful

框架简化开发

使用

使用
	安装 pip install flask-restful
	初始化 
		urls---在init中调用init_urls
			api = Api()
			api.add_resource(Hello, "/hello/")
				Hello是一个类的名字  hello是路由
			def init_urls(app):
    		api.init_app(app=app)
    
	apis--基本用法
		继承自Resource
			class Hello(Resource):
		实现请求方法对应函数
			def get(self):
        		return {"msg": "ok"}

            def post(self):
                return {"msg": "create success"}

定制输入输出

定制输入输出
	输出
		fields中的类型约束
			String
			Integer
			Nested
			List
				Nested
		@marshal_with的基本使用
			类型括号中还允许添加约束
				attribute
					指定连接对应名字
						attribute=名字
				default
					设置默认值
						default=404
		marshal_with特性
			        - 默认返回的数据如果在预定义结构中不存在,数据会被自动过滤
        - 如果返回的数据在预定义的结构中存在,数据会正常返回
        - 如果返回的数据比预定义结构中的字段少,预定义的字段会呈现一个默认值
			如果类型是Integer  那么默认值是  0
        如果类型是String  那么默认值是null
                @marshal_with返回一个类对象
                @marshal_with返回一个列表
	输入
		使用了parser=reqparse.RequestParser()
		parser.add_argument("c_name", type=str)
        parser.add_argument("id", type=int, required=True, help="id 是必须的")
		parse = parser.parse_args()
		cat_name = parse.get("c_name")
        id = parse.get("id")
         print(id)
		在对象中添加字段
			对字段添加约束
			default
			required
				必须的参数
			help
				id是必须的
			action
				action=append
					c_name=tom&c_name=zs
		继承
			copy
			可以对已有字段进行删除和更新
			继承解析
    - 在整个项目中,通用字段可以创建一个基parser
    - 复用已有的部分参数转换数据结构
			parse_c parser.copy()   parse_c.remove_argument('')

李晶1:

__init__.py
import os

from flask import Flask

from App import settings
from App.ext import init_ext


def create_app(envname):
    # 获取项目路径
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    print(BASE_DIR)

    templates_folder = os.path.join(BASE_DIR,'templates')

    print(templates_folder)

    static_folder = os.path.join(BASE_DIR,'static')

    print(static_folder)

    app = Flask(__name__,template_folder=templates_folder,static_folder=static_folder)

    app.config.from_object(settings.ENV_NAME.get(envname))

    init_ext(app)
    return app

ext.py
# flask-script
# flask-blueprint
# flask-session
# flask-sqlalchemy
# flask-migrate
from flask_bootstrap import Bootstrap
from flask_cache import Cache
from flask_debugtoolbar import DebugToolbarExtension
from flask_migrate import Migrate
from flask_session import Session

from App.models import db

cache = Cache(config={'CACHE_TYPE': 'redis'})

def init_ext(app):
    # 有循环导入问题
    # app.register_blueprint(blueprint=blue)

    app.config['SECRET_KEY']='110'
    app.config['SESSION_TYPE']='redis'
    Session(app=app)

    db.init_app(app=app)

    migrate = Migrate()
    migrate.init_app(app=app,db=db)

    Bootstrap(app=app)

    app.debug = True
    # debugtoolbar
    debugtoolbar = DebugToolbarExtension()
    debugtoolbar.init_app(app=app)

#   cache
#     cache有底层源码错误
#     解决办法  鼠标防到Cache上  ctrl + B  点击jinja2ext.py
#     进入之后 观察倒包   有一个叫做 flask.ext.cache的修改为flask_cache
#     from flask.ext.cache import make_template_fragment_key===>
#     from flask_cache import make_template_fragment_key
#     cache = Cache(config={'CACHE_TYPE':'redis'})
    cache.init_app(app=app)
    
    

models.py
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()


setting.py
def get_database_uri(DATABASE):
    dialect = DATABASE.get('dialect')
    driver = DATABASE.get('driver')
    username = DATABASE.get('username')
    password = DATABASE.get('password')
    host = DATABASE.get('host')
    port = DATABASE.get('port')
    database = DATABASE.get('database')
    return '{}+{}://{}:{}@{}:{}/{}'.format(dialect,driver,username,password,host,port,database)


class Config():
    Test = False
    Debug = False
    SQLALCHEMY_TRACK_MODIFICATIONS = False

class DevelopConfig(Config):
    Debug = True

    DATABASE={
        'dialect':'mysql',
        'driver':'pymysql',
        'username':'root',
        'password':'1234',
        'host':'localhost',
        'port':'3306',
        'database':'flaskday05',
    }
    SQLALCHEMY_DATABASE_URI=get_database_uri(DATABASE)

ENV_NAME={
    'develop':DevelopConfig
}


views.py
from flask import Blueprint, request, render_template, current_app,g

from App.ext import cache

blue = Blueprint('blue',__name__)


@blue.route('/')
def hello_world():
    return 'Hello World!'


@blue.route('/index/')
# 不能导入---》 因为在init方法中
# 能导入-循环导入问题---》
# view -->ext  cache
# ext  --->view blue

@cache.cached(timeout=30)
def index():
    print('你们多少个人去看电影阿  千万不要剧透')
    return 'index'


# 第一次访问的时候 显示  欢迎光临  第二次访问的时候  显示小爬虫快走开

@blue.route('/index1/')
def index1():
    ip = request.remote_addr

#     缓存中如果有记录 那么就证明你来过
#     get获取的意思  set设置的意思
    result = cache.get('ip')

    if result:
        return '小爬虫快走开'
    else:
        cache.set('ip',ip,timeout=30)
        return '欢迎光临'


# AOP  flask中 钩子 和 django中的中间件
# AOP 面向切面编程, 面向方面编程
# 在执行某方法之前 或者之后  执行一些方法
# eg: pymysql
#      add   delete  update  select
#      coonection   cursor  execute  close
# 每执行一个都需要链接 和 关闭

@blue.route('/testaop/')
def testaop():
    print('i am testaop')

    return 'ok'


# 默认情况下before_request是带()的  如果我们使用aop  需要将()删除
# @blue.before_request
# def aop():
#     print('i am aop simida')


@blue.route('/add/')
def add():
    print('i am add')
    return 'add'


@blue.route('/delete/')
def delete():
    print('i am delete')
    return 'delete'


@blue.route('/testconfig/')
def testconfig():
    for c in current_app.config:
        print(c)
    return render_template('testconfig.html')


@blue.route('/g/')
def g():

    g.ip = request.remote_addr
    return 'ok'


@blue.route('/testg1/')
def testg1():
#     问:怎么获取ip (不能移动ip的位置)
    print(g.ip)
    return 'ok1'

testconfig.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<ul>
    {% for c in config %}
        <li>{{ c|lower }}</li>
    {% endfor %}
</ul>
</body>
</html>

李晶Day05FZFlask:

flask-restful实现步骤

  1 pip install flask-restful

  2 在ext中 创建api对象  并且初始化  指定资源

  api = Api()

  api.init_app(app=app)

  api.add_resource(资源的类,路由路径)  eg:api.add_resource(Hello,'/hello/')

  3 注册资源

    在apis模块中  创建一个类

    class Hello(Resource):

        def get(self):

            data={}

            return data

        def post(self):

            data={}

            return data

        def delete/put/patch(self):

            data={}

            return data

    restful最重要的就是返回值

作业:

1 整理本周内容 复习

2 登录页面添加验证码

3 注册页面当输入邮箱的时候 会往邮箱发送件 在邮箱激活之后 才会可以登录

__init__.py
from flask import Flask

from App import settings
from App.ext import init_ext


def create_app():
    app = Flask(__name__)

    # session
    # app.config['SECRET_KEY']='114'
    # app.config['SESSION_TYPE']='redis'
    # Session(app=app)


    # 建立与settings文件的关键
    # settings.ENV_NAME.get('develop')获取的是settings文件中的value值
    # app.config.from_object(DevelopConfig)将类加载过来
    app.config.from_object(settings.ENV_NAME.get('develop'))

    # sqlalchemy
    # db.init_app(app=app)

    init_ext(app)

    return app

apis.py
# apis和views是一样的
from flask_restful import Resource


class Hello(Resource):

    def get(self):
        data = {
            'msg':'get'
        }
        return data

    def post(self):
        data = {
            'msg': 'post'
        }
        return data


ext.py
# 用来存放第三方扩展库
from flask_restful import Api
from flask_session import Session

from App.apis import Hello
from App.models import db


def init_ext(app):
    app.config['SECRET_KEY']='114'
    app.config['SESSION_TYPE']='redis'
    Session(app=app)

    db.init_app(app=app)

    # restful
    api = Api()

    api.add_resource(Hello,'/hello/')

    api.init_app(app=app)

views.py
from flask import Blueprint


blue = Blueprint('blue',__name__)

@blue.route('/')
def index():
    return 'index'

FzFlask1:

__init__.py
from flask import Flask

from App import settings
from App.ext import init_ext


def create_app(envname):
    app = Flask(__name__)

    app.config.from_object(settings.ENV_NAME.get(envname))

    init_ext(app)
    return app


ext.py


'''
flask-script
flask-blueprint
flask-session
flask-sqlalchemy
'''
from flask_migrate import Migrate
from flask_session import Session

from App.models import db


def init_ext(app):
    # session
    app.config['SECRET_KEY']='10010'
    app.config['SESSION_TYPE']='redis'
    Session(app=app)

    # sqlalchemy
    db.init_app(app=app)

    # migrate
    migrate = Migrate()
    # 注意参数的个数
    migrate.init_app(app=app,db=db)
    

views.py


from flask import Blueprint, request
from flask.json import jsonify

from App.models import User, db

blue = Blueprint('blue',__name__)

@blue.route('/index/')
def index():
    return 'index'

@blue.route('/getjson/')
def getjson():
    data = {
        'resultCode':'200',
        'resultValue':'封神演义',
    }
    # 注意flask中视图函数 不允许直接返回json  因为视图函数返回的是应该是 字符传 元祖  response实例
    # flask.json是flask的子类
    return jsonify(data)



# 在后端 定义一个列表  注意列表中的数据是python中基础数据类型
@blue.route('/getscore/')
def getscore():
    score_list = [4,6,3,7,9,10]
    data = {
        'status':200,
        'score_list':score_list
    }
    return jsonify(data)


@blue.route('/adduser/',methods=['get','post'])
def adduser():
    name = request.form.get('name')
    age = request.form.get('age')
    user = User()

    user.name = name

    user.age = age

    db.session.add(user)
    db.session.commit()

    data = {'msg':'success'}


    return jsonify(data)



# 通过请求方式执行不同的代码  并且返回的是json数据
@blue.route('/user/',methods=['GET','POST','DELETE','PUT','PATCH'])
def user():
    data = {
        'msg':'ok'
    }
    if request.method == 'GET':

        print('111111111111111')

        data['msg'] = 'get'

        return jsonify(data)
    elif request.method == 'POST':

        data['msg'] = 'post'
        return jsonify(data)
    elif request.method == 'DELETE':
        data['msg'] = 'delete'
        return jsonify(data)
    elif request.method == 'PUT':
        data['msg'] = 'put'
        return jsonify(data)
    elif request.method == 'PATCH':
        data['msg'] = 'patch'
        return jsonify(data)

    return jsonify(data)



manager.py
from flask_migrate import MigrateCommand
from flask_script import Manager

from App import create_app
from App.views import blue

app = create_app('develop')

manager = Manager(app=app)

manager.add_command('db',MigrateCommand)

app.register_blueprint(blueprint=blue)


if __name__ == '__main__':
    manager.run()

json:一种轻量级的数据交换标准

物物交换
货币:贝壳  通过贝壳来买卖

人民币


python对象==》json《=== js对象



json/xml

xml可扩展的标记语言
<python1901></python1901>
常用于java语言


json解析速度快  存储文档小


html 超文本标记语言
文本标记语言  简单标签   超级文本标记语言(图片 视频  音频。。。)

浏览器小名   html解析器



http://127.0.0.1:5000/user/add
http://127.0.0.1:5000/user/delete
http://127.0.0.1:5000/user/update
http://127.0.0.1:5000/user/select


rest  通过请求的提交方式不同 然后去执行对象方法
http://127.0.0.1:5000/user

请求提交方式  get    查询
            post   添加
            delete 删除
            put    修改    全部数据修改
            patch  修改    部分数据修改




addUser.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="/static/js/jquery.js"></script>

    <script type="text/javascript">
        $(function(){
            $('button').click(function () {
                var name = $('#name').val();
                var age = $('#age').val();
                $.ajax(
                    {
                        url:'/adduser/',
                        type:'post',
                        data:{'name':name,'age':age},
                        dataType:'json',
                        success:function (data) {
                            console.log(data);
                        }
                    }
                )
                

            })
        })

    </script>
</head>
<body>
    name:<input type="text" id="name"><br>
    age:<input type="text" id="age"><br>
    <button>提交</button>
</body>
</html>

scoreList.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
    <script type="text/javascript">
        $(function () {
            $('#b').click(function () {
                $.getJSON('/getscore/',function (data) {
                    //{#不能通过data.get获取数据 并且注释还有问题 需要删除 #}
                    //{#score_list = data.get('score_list');#}
                    //score_list = data['score_list']
                    score_list = data.score_list;
                    $ul = $('ul');
                    for(var i=0; i<score_list.length;i++){
                        score = score_list[i];
                        $li = $('<li></li>');
                        $li.html(score);
                        $ul.append($li);
                    }
                })
            })

        })
    </script>

</head>
<body>
    <button id="b">点我</button>
    <ul>

    </ul>
</body>
</html>

Day06

1.验证码

def get_code(request):

    # 初始化画布,初始化画笔

    mode = "RGB"

    size = (200, 100)

    red = get_color()

    green = get_color()

    blue = get_color()

    color_bg = (red, green, blue)

    image = Image.new(mode=mode, size=size, color=color_bg)

    imagedraw = ImageDraw(image, mode=mode)

    imagefont = ImageFont.truetype(settings.FONT_PATH, 100)

    verify_code = generate_code()

    request.session['verify_code'] = verify_code

    for i in range(4):
        fill = (get_color(), get_color(), get_color())
        imagedraw.text(xy=(50*i, 0), text=verify_code[i], font=imagefont, fill=fill)

    for i in range(100):
        fill = (get_color(), get_color(), get_color())
        xy = (random.randrange(201), random.randrange(100))
        imagedraw.point(xy=xy, fill=fill)

    fp = BytesIO()

    image.save(fp, "png")

    return HttpResponse(fp.getvalue(), content_type="image/png")


import random

def get_color():
    return random.randrange(256)

def generate_code():
    source = "qwertyuiopasdfghjklzxcvbnm1234567890QWERTYUIOPASDFGHJKLZXCVBNM"

    code = ""

    for i in range(4):
        code += random.choice(source)

    return code

2.发送邮件

1 前后端分离 源码 restful

2 restful的结构化输出 2种输出

3 restful输入

4 注册 前端验证 js 验证

    后端验证 用户名字是否存在 鼠标失去焦点  ajax

    邮箱验证

           提交表单 向邮箱发送邮件  打开邮箱  点击激活链接  将状态变成激活状态

           邮件的生存时间

    画一个页面
            学生姓名   后台验证  前台验证
            学生性别
            学生年龄
            学生密码
            确认密码   前台密码确认验证
            邮箱地址   发送邮件
            激活状态   邮件的生存时间

    邮箱激活:
           flask-mail

           1 设置邮箱的授权码
                 点击设置 然后 选择pop3  设置授权码
           2 注意 授权码和密码不能一致

           3 pip install flask-mail

           4 mail = Mail()

           5 mail.init_app(app=app)

           6 在settings中写 MAIL_SERVER MAIL_USERNAME  MAIL_PASSWORD

           7 在apis中 msg = Message(subject sender recipients注意列表)

           8 msg.html = 字符串 render_templates

           9 mail.send(msg)

    作业:
           邮件的内容
           尊敬的zslsww5您好:

请点击链接进行激活激活

http://127.0.0.1:8000/axf/doactive/?name=zslsww5

            点击激活  修改active的状态

5 登录 验证码 先验证验证码 减少数据库io操作

6 celery

day06代码:

apis文件包

Cat1Apis.py
from flask_restful import Resource


class Cat1Resource(Resource):
    def get(self):
        return 'i am ok'
   
Cat2Apis.py
from flask_restful import Resource


class Cat2Resource(Resource):
    def get(self):
        return 'i am ok1'
    
Cat3Apis.py
from flask_restful import Resource, marshal_with, fields


class Cat3Resource(Resource):

    '''
    - 默认返回的数据如果在预定义结构中不存在,数据会被自动过滤
    - 如果返回的数据在预定义的结构中存在,数据会正常返回
    - 如果返回的数据比预定义结构中的字段少,预定义的字段会呈现一个默认值
			        如果类型是Integer  那么默认值是  0
                     如果类型是String  那么默认值是null
    '''
    r1fields={
        # fields后面的类型 可以加() 可以不加()
        'msg':fields.String(),
        # 'resultCode':fields.Integer,
        # 'resultValue':fields.String
        # 'status':fields.String

        'resultValue':fields.String(default='dddd'),
        'status':fields.String(attribute='xxx')
    }
    # 结构化输出:按照指定的格式输出数据
    @marshal_with(r1fields)
    def get(self):
        data = {
            'msg':'ok',
            'status':'200',
            'xxx':'xxx',

        }
        return data
    

Cat4Apis.py
from flask_restful import Resource, fields, marshal

r4fields = {
    'msg': fields.String(),
    'resultCode': fields.Integer,
}

class Cat4Resource(Resource):



    def get(self):
        data = {
            'msg':'ok',
            'status':'200'
        }
        return marshal(data=data,fields=r4fields)
    
    
Cat5Apis.py
from flask_restful import Resource, marshal_with, fields

from App.models import Cat


catfields = {
    'id':fields.Integer,
    'name':fields.String,
    'color':fields.String
}

r5fields = {
    'msg':fields.String,
    'cat':fields.Nested(catfields)
}


class Cat5Resource(Resource):


    @marshal_with(r5fields)
    def get(self):
        cat = Cat.query.first()

        data = {
            'msg':'ok',
            'cat':cat
        }
        return data

    
Cat6Apis.py
from flask_restful import Resource, marshal, fields

from App.models import Cat

catfields = {
    'id':fields.Integer,
    'name':fields.String,
    'color':fields.String,
}


r6fields = {
    'msg':fields.String,
    'cats':fields.List(fields.Nested(catfields))
}


class Cat6Resource(Resource):


    def get(self):
        cats = Cat.query.all()

        data = {
            'msg':'ok',
            'cats':cats
        }

        return marshal(data=data,fields=r6fields)
    
    
CatApis.py
from flask_restful import Resource


class CatResource(Resource):
    def get(self):
        return {'msg':'ok'}
    
    
DogApis.py
from flask_restful import Resource, reqparse

# 输入
# 1 获取parser对象  eg:parser = reqparser.RequestParser()
# 2 将参数绑定到parser上 eg:parser.add_argument(name,type,help,required)
#   name 参数的名字  type 参数的类型  help如果没有参数的提示  required必须书写
# 3 将parser里的参数进行解析 解析之后为parse对象 eg  parse = parser.parse_args()
# 4 可以通过parse对象的get方法获取参数值

parser = reqparse.RequestParser()

parser.add_argument(name='name',type=str,help='请输入用户名字',required=True)
parser.add_argument(name='age',type=int,help='请输入年龄',required=True)
parser.add_argument(name='color',type=str,help='请输入颜色',required=True)


class DogResource(Resource):
    # 获取 name   然后如果用户名字为空  那么提示 用户名字不可以为空
    # 获取年龄     然后如果年龄为空  那么提示 年龄不可以为空
    # 获取颜色     然后如果颜色为空  那么提示  颜色不可以为空

    def post(self):
        parse = parser.parse_args()

        name = parse.get('name')
        age = parse.get('age')
        color = parse.get('color')

        print(name,age,color)
        return 'i am ok'
    
    
    
StudentApis.py
from flask import request
from flask_mail import Message
from flask_restful import Resource

from App.ext import mail
from App.models import Student, db


class StudentResource(Resource):
    # 前端验证 如果 符合要求  那么显示绿色字体  如果不符合要求 那么显示红色字体
    def post(self):
        # name = request.form.get('name')
        #
        #
        #
        # students = Student.query.filter(Student.name == name)
        #
        # data = {
        #     'msg':'用户名字可以注册',
        #     'status':'200',
        # }
        #
        # if students.count() > 0:
        #     student = students.first()
        #     data['status'] = 422
        #     data['msg'] = '用户已经存在'
        #     return data
        # return data
        name = request.form.get('name')
        gender = request.form.get('gender')
        age = request.form.get('age')
        password = request.form.get('password')
        email = request.form.get('email')

        student = Student()
        student.name = name
        student.gender = gender
        student.age = age
        student.password = password
        student.email = email

        db.session.add(student)
        db.session.commit()

        # 参数有三个  subject 主题  sender 发送者  recipients接受者
        msg = Message(subject='激活',sender='yulin_ljing@163.com',
                      recipients=[email])



        msg.html = "<h1>testingxxxx</h1>"


        mail.send(msg)

        return {'msg':'ok'}

__init__.py
from flask_restful import Resource, Api

#
# api = Api()
#
#
# def init_urls(app):
#     api.init_app(app=app)





register.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="/static/js/jquery.js"></script>

    <script type="text/javascript">
        $(function () {
             /**
            $('#name').blur(function () {

                 * 前端验证
                var name = $(this).val();

                var reg = /^[a-z]{3,6}$/;
                //reg的test方法 是判断某字符串是否满足 某正则
                //如果满足返回true  没有满足返回的是false
                if(reg.test(name)){
                    $('#nameinfo').css('color','green');
                }else{
                    $('#nameinfo').css('color','red');
                }
                //后台验证
                var name = $(this).val();
                $.ajax({
                    url:'/student/',
                    type:'post',
                    data:{'name':name},
                    dataType:'json',
                    success:function (data) {
                        var status = data['status']
                        if(status === 422){
                            $('#nameinfo').html(data['msg']);
                        }else{
                            $('#nameinfo').html(data['msg']);
                        }
                    }
                })
            });
            */

            $('#sub').click(function () {
                var name = $('#name').val();
                var gender = $('#gender').val();
                var age = $('#age').val();
                var password = $('#password').val();
                var email = $('#email').val();
                $.ajax({
                    url:'/student/',
                    type:'post',
                    data:{
                        'name':name,
                        'gender':gender,
                        'age':age,
                        'password':password,
                        'email':email
                    },
                    dataType:'json',
                    success:function (data) {
                        console.log(data);
                    }
                })

            })
        })

    </script>
</head>
<body>
<!--{#    学生姓名   后台验证  前台验证
{#                学生性别
{#                学生年龄
{#                学生密码
{#                确认密码   前台密码确认验证
{#                邮箱地址   发送邮件
{#                激活状态   邮件的生存时间#}
-->

name&nbsp;&nbsp;:<input type="text" id="name">
<span id="nameinfo">请输入3到6个英文字母</span>
<br/>
gender:<input type="text" id="gender"><br/>
age&nbsp;&nbsp;&nbsp;:<input type="text" id="age"><br/>
passwd:<input type="password" id="password"><br/>
confirm:<input type="password" id="confirmpassword"><br/>
email:<input type="text" id="email"><br/>
<input type="button" value="提交" id="sub">

</body>
</html>

__init__.py
from flask import Flask

from App import settings
from App.ext import init_ext
from App.urls import init_urls


def create_app(envname):
    app = Flask(__name__)

    app.config['JSON_AS_ASCII'] = False

    app.config.from_object(settings.ENV_NAME.get(envname))

    init_ext(app)
    init_urls(app)

    return app

ext.py
# flask-script   flask-blueprint  flask-session  flask-sqlalchemy
# flask-migrate  flask-boostrap  flask-debugtoolbar  flask-cache
# flask-restful
from flask_bootstrap import Bootstrap
from flask_cache import Cache
from flask_debugtoolbar import DebugToolbarExtension
from flask_mail import Mail
from flask_migrate import Migrate
from flask_session import Session

from App.models import db
from App.views import blue

cache = Cache(config={'CACHE_TYPE':'redis'})
mail = Mail()

def init_ext(app):
    app.register_blueprint(blueprint=blue)

    # flask-session
    app.config['SECRET_KEY']='110'
    app.config['SESSION_TYPE']='redis'

    session = Session()
    session.init_app(app=app)

#     flasksqlalchemy
    db.init_app(app=app)

#   flask-migrate
#     python manager.py db init
#     python manager.py db migrate
#     python manager.py db upgrade
#     python manager.py db downgrade
    migrate = Migrate()
    migrate.init_app(db=db,app=app)
    # flask-bootstrap
    bootstrap = Bootstrap()
    bootstrap.init_app(app=app)

    # flask-debugtoolbar
    app.debug = True
    debugtoolbar = DebugToolbarExtension()
    debugtoolbar.init_app(app=app)

    # flask-cache
    # cache = Cache(config={'CACHE_TYPE': 'redis'})
    cache.init_app(app=app)


#     flask-mail

    mail.init_app(app=app)



models.py
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()


class User(db.Model):
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    name = db.Column(db.String(32))


    def to_dict(self):
        return {'id':self.id,'name':self.name}


class Cat(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(32))
    color = db.Column(db.String(16))



class Dog(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(32))
    age = db.Column(db.Integer)
    color = db.Column(db.String(16))
'''
学生姓名   后台验证  前台验证
                学生性别
                学生年龄
                学生密码
                确认密码   前台密码确认验证
                邮箱地址   发送邮件
                激活状态   邮件的生存时间'''

class Student(db.Model):
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    name = db.Column(db.String(32),unique=True)
    gender = db.Column(db.String(16),default='1')
    age = db.Column(db.Integer)
    password = db.Column(db.String(256))
    email = db.Column(db.String(64))
    active = db.Column(db.Boolean,default=False)

settings.py
def get_database_uri(DATABASE):
    dialect = DATABASE.get('dialect')
    driver = DATABASE.get('driver')
    username = DATABASE.get('username')
    password = DATABASE.get('password')
    host = DATABASE.get('host')
    port = DATABASE.get('port')
    database = DATABASE.get('database')
    return '{}+{}://{}:{}@{}:{}/{}'.format(dialect,driver,username,password,host,port,database)



class Config():
    Test = False
    Debug = False
    SQLALCHEMY_TRACK_MODIFICATIONS = False

    MAIL_SERVER = 'smtp.163.com'
    MAIL_USERNAME = 'yulin_ljing@163.com'
    MAIL_PASSWORD = 'lijing0501115'


class DevelopConfig(Config):
    Debug = True

    DATABASE = {
        'dialect':'mysql',
        'driver':'pymysql',
        'username':'root',
        'password':'1234',
        'host':'localhost',
        'port':'3306',
        'database':'finalflask'
    }
    SQLALCHEMY_DATABASE_URI = get_database_uri(DATABASE)


ENV_NAME = {
    'develop':DevelopConfig
}

urls.py
from flask_restful import Api

from App.apis.Cat1Apis import Cat1Resource
from App.apis.Cat2Apis import Cat2Resource
from App.apis.Cat3Apis import Cat3Resource
from App.apis.Cat4Apis import Cat4Resource
from App.apis.Cat5Apis import Cat5Resource
from App.apis.Cat6Api import Cat6Resource
from App.apis.CatApis import CatResource
from App.apis.DogApis import DogResource
from App.apis.StudentApis import StudentResource

api = Api()


def init_urls(app):
    api.init_app(app=app)


api.add_resource(CatResource,'/cat/')
api.add_resource(Cat1Resource,'/cat1/')
api.add_resource(Cat2Resource,'/cat2/')
api.add_resource(Cat3Resource,'/cat3/')
api.add_resource(Cat4Resource,'/cat4/')
api.add_resource(Cat5Resource,'/cat5/')
api.add_resource(Cat6Resource,'/cat6/')


api.add_resource(DogResource,'/dog/')

api.add_resource(StudentResource,'/student/')


views.py
from flask import Blueprint, jsonify

from App.models import User

blue = Blueprint('blue',__name__)


@blue.route('/index/')
def index():
    return 'index'


@blue.route('/getuser/')
def getuser():
    # 视图函数返回的是json数据 那么数据中 不可以直接返回自定义类型的对象的
    # 可以直接返回python自带的数据类型对象
    user = User.query.first()
    # user = [1,2,3]
    data = {
        'msg':'ok',
        'user':user.to_dict(),
    }
    return jsonify(data)

@blue.route('/getusers/')
def getusers():


    users = User.query.all()

    user_list = []

    for user in users:
        user_list.append(user.to_dict())
    data = {
        'msg':'ok',
        'users':user_list
    }
    return jsonify(data)



manager.py
from flask_migrate import MigrateCommand
from flask_script import Manager

from App import create_app

app = create_app('develop')


manager = Manager(app=app)

manager.add_command('db',MigrateCommand)

if __name__ == '__main__':
    manager.run()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值