flask-(1)

内容概览

  • flask展示用户信息案例
  • 配置文件写法
  • 路由系统
  • 路由本质
  • cbv写法
  • 模板语法

flask展示用户信息案例

from flask import Flask, request, render_template, session, redirect

app = Flask(__name__)

# 如果要使用session,必须加秘钥
app.secret_key = 'asdfasfd35435634**&#)#)$)$%$'
# 用户信息数据,做成全局,后面写项目,尽量不要写全局变量
USERS = {
    1: {'name': '张三', 'age': 18, 'gender': '男', 'text': "道路千万条"},
    2: {'name': '李四', 'age': 28, 'gender': '男', 'text': "安全第一条"},
    3: {'name': '王五', 'age': 18, 'gender': '女', 'text': "行车不规范"},
}


# 登录页面(get请求返回登录页面,post请求提交数据登录)
@app.route('/login', methods=['GET', 'POST'])
def login():
    # 判断是否为get请求,如果是get请求,显示登录页面
    if request.method == 'GET':  # request虽然导入是全局的,如果用在这个局部,就是当次login请求自己的request
        # 返回首页
        return render_template('login.html')
    else:  # post请求,取出前端传入的用户名,密码,判断是否正确,如果正确,返回给前端cookie,前端跳转到index页面
        # request.form:前端post请求传入的数据,字典格式
        username = request.form.get('username')
        password = request.form.get('password')
        if username == 'xxx' and password == '123':
            # 写入cookie
            session['is_login'] = True
            return redirect('/index')
        else:  # 用户名或密码错误,把错误信息渲染到login的页面上
            return render_template('login.html', errors='用户名或密码错误')  # 参数直接写在后边,与django有点区别


# 首页,显示一条条显示用户信息
@app.route('/index')
def index():
    # 需要登录后才能访问,取出用户携带的cookie判断
    if session.get('is_login'):
        # 如果有值说明登录了,返回首页页面
        return render_template('index.html', users=USERS)
    else:
        # 没有登录,重定向到登录页面
        return redirect('/login')


# 用户详情,点击首页某条数据,显示用户详情
@app.route('/detail/<int:id>')  # 转换器
def detail(id):
    # 也要登录才能够访问
    if session.get('is_login'):
        user = USERS.get(id)
        return render_template('detail.html', user=user)
    else:
        return redirect('/login')


if __name__ == '__main__':
    app.run(host='127.0.0.1', port=8000)

  • login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<form method="post">
    <p>用户名:<input type="text" name="username"></p>
    <p>密码:<input type="password" name="password"></p>
    <input type="submit" value="提交"> <span>{{ errors }}</span>
</form>
</body>
</html>
  • index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<h1>用户信息--模板语言</h1>
<table>
    {% for k,v in users.items() %}
        <tr>
            <td>{{ k }}</td>
            <td>{{ v.name }}</td>
            <td>{{ v['name'] }}</td>
            <td>{{ v.get('name') }}</td>
            <td><a href="/detail/{{ k }}">查看详细</a></td>
        </tr>
    {% endfor %}
</table>
</body>
</html>
  • detail.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h2>用户名字:{{ user.name }}</h2>
<h2>用户年龄:{{ user.age }}</h2>
<h2>用户性别:{{ user.gender }}</h2>
<h2>用户介绍:{{ user.text }}</h2>
</body>
</html>

配置文件写法

# 项目的配置文件:如果不配,有默认的
# 几个重要的
# DEBUG:是否是调试模式
# SECRET_KEY:项目的秘钥
# print(app.config)
"""1 使用配置文件之一:(写小脚本测试阶段用)直接通过app对象,配置上,只能配置几个,本质都要放到app.config中"""
app.debug=True
app.secret_key='asdfasf4555'
app.session_cookie_name='sss'
print(app.config)

"""2 直接通过app.config 配置"""
app.config['DEBUG'] = True
app.config['SECRET_KEY'] = 'asfasdf'
print(app.config)

"""3 通过配置文件(很像djagno),不常用"""
# 先写一个settings.py的文件
DEBUG=True
SECRET_KEY='aaaaa'
# 导入配置文件
app.config.from_pyfile('settings.py')
print(app.config)

"""4 通过类配置(用的多,可以有多套配置)"""
# settings.py文件
class Config(object):
    DEBUG = False
    TESTING = False
    DATABASE_URI = 'sqlite://:memory:'  # 自定义的配置

class ProductionConfig(Config):
    DEBUG = False
    DATABASE_URI = 'mysql://192.168.11.11/foo'  # 上线数据库地址

class DevelopmentConfig(Config):
    DEBUG = True
    DATABASE_URI = 'mysql://127.0.0.1/foo'  # 开发阶段本地数据库地址

# 导入配置
app.config.from_object('setting.DevelopmentConfig')  # 开发阶段配置
app.config.from_object('setting.ProductionConfig')  # 上线阶段配置
print(app.config)

"""5 以下,做了解"""
app.config.from_envvar("环境变量名称")  # 在环境变量中导入配置
app.config.from_json("json文件名称")

# 使用分布式配置中心
import requests
res = request.get('获取配置数据').json()
app.config.from_mapping(res)

路由系统

"""djagno中,路由是单独的urls.py;flask中是装饰的形式"""

# 使用方式
@app.route(参数)
	重要的参数:
		-rule: 字符串的路径,使用转换器  <string:name>  <name>
	    	'default':          UnicodeConverter,
	        'string':           UnicodeConverter,
	        'any':              AnyConverter,
	        'path':             PathConverter,    # /xx/sss/
	        'int':              IntegerConverter, # 数字
	        'float':            FloatConverter,   #小数
	        'uuid':             UUIDConverter,    #asdfas-asdfas-asdf
	        #记住:string,int,path
	    -methods: 列表,规定请求的方式,如果列表中没有,该请求方式不被支持
	    -endpoint:路由别名,如果不写,会以被装饰的函数名作为别名,django中叫name

路由本质

"""
flask中路由是使用装饰器的,但是它的本质其实是app对象(Flask)的方法self.add_url_rule(rule, endpoint, f, **options)

如果在视图函数上加了装饰器,其实本质是在调用self.add_url_rule
	-我们可以不加装饰器,自己调用这个方法,也能完成路由的注册
"""

# 路由本质:
# 1 @app.route('/') 先执行完成,结果是decorator内层函数
    @decorator
    def index():
# 2 index=decorator(index)
    def decorator(f):
        # @app.route('/',endpoint='index') 如果没有传endpoint,这个地方就是None
        endpoint = options.pop("endpoint", None)
        # self是Flask的对象,app :rule路由, endpoint:别名,是None,其他的打散了传入了(methods..)
        self.add_url_rule(rule, endpoint, f, **options)
        return f
# 3 加了装饰器最终,返回的还是index,只不过执行了 self.add_url_rule(rule, endpoint, f, **options)

# 4 Flask类中得add_url_rule方法
    -rule:就是装饰器传入的路径,路由
    -endpoint:别名
    -view_func:视图函数不加括号
    
# 5 得到的结论,现在不需要使用装饰器来注册路由了,自己写
    
    app.add_url_rule('/home', view_func=home, endpoint='home')


# 其实跟djagno没有大的差距,只是使用装饰器来配置
add_url_rule的参数
@app.route和app.add_url_rule参数:
# rule, URL规则
# view_func, 视图函数名称
# defaults = None, 默认值, 当URL中无参数,函数需要参数时,使用defaults = {'k': 'v'}
为函数提供参数,就是djagno中得kwargs

# endpoint = None, 名称,用于反向生成URL,即: url_for('名称'),等同于django的reverse
# methods = None, 允许的请求方式,如:["GET", "POST"]

# strict_slashes 对URL最后的 / 符号是否严格要求
strict_slashes = None
    '''
        @app.route('/index', strict_slashes=False)
        #访问http://www.xx.com/index/ 或http://www.xx.com/index均可
        @app.route('/index', strict_slashes=True)
        #仅访问http://www.xx.com/index
    '''
# redirect_to 重定向到指定地址
redirect_to = None, 
    '''
        @app.route('/index/<int:nid>', redirect_to='/home/<nid>')
    '''

cbv写法

flask的cbv写法
# 第一步:写一个类,继承MethodView
    class Login(MethodView):
        def get(self):
            return '我是get'
        def post(self):
            return '我是psot'
        
# 第二步:注册路由 name 是别名,本质就是endpoint
	app.add_url_rule('/login', view_func=Login.as_view(name='index'))
    
# 第三步:只要向 /login 发送get请求,就会执行Login 的get方法
cbv加装饰器
# 研究第1个问题:cbv加装饰器,如何做?
	类属性中加入,加入decorators = [auth, ],属性是一个列表,按照列表顺序,依次给每个方法加装饰器
    
     def as_view(cls, name, *class_args, **class_kwargs ) :
       ....
       if cls.decorators:
          for decorator in cls.decorators:
            '''
            # 装饰器原理:
             @auth
             def view():
             本质是  view=auth(view)  
            '''
            # 给view加装饰器----》给视图类中得方法加装饰器
             view = decorator(view) 
        return view
as_view的执行流程
# 研究第2个问题,as_view的执行流程
    def as_view(cls, name, *class_args, **class_kwargs):
        def view(**kwargs):
            return self.dispatch_request(**kwargs)
        return view
 
    -请求来了,路由匹配成功,会执行as_view内的view()----》self.dispatch_request---》MethodView的dispatch_request
    -MethodView的dispatch_request
      def dispatch_request(self, **kwargs):
        # 在当前视图类中反射,请求方式的小写字符串(get),我们写了get方法
        meth = getattr(self, request.method.lower(), None)
        # 执行get()
        return meth(**kwargs) 
as_view中的name参数
# 研究第3个问题:Login.as_view(name='index')  name到底有什么用,还必须传
	-先研究 endpoint 有什么用,正常的fbv,如果不写endpoint,会以函数名作为别名,endpoint如何设置的
    -如果endpoint为None,它把函数名作为了endpoint
      if endpoint is None:
            endpoint = _endpoint_from_view_func(view_func)# view_func.__name__
        options["endpoint"] = endpoint
        
   -Login.as_view(name='index'),name到底有啥用
		-app.add_url_rule('/login', view_func=Login.as_view('login'))
    	-没有传endpoint,Login.as_view('login')是 view函数的内存地址,
        -endpoint会以函数名作为endpoint的值,现在所有函数都是view,必须传入name,来修改调view函数的名字
        -如果传了endpoint,别名以endpoint为主,如果不传endpoint,别名以name为主
        app.add_url_rule('/login', view_func=Login.as_view(name='login'),endpoint='xxx')
继承view写cbv
# 继承View写视图类(CBV)
	-1 继承 View 的视图类,执行流程都是一样的
    -2 请求来了,路由匹配成功,执行self.dispatch_request
	-3 self.dispatch_request 没有实现,直接抛异常NotImplementedError()
    -4 必须重写 dispatch_request,自己写匹配规则,执行不同的方法
cbv中methods作用
# 视图类中还有个类属性 methods = ['POST']
	-用来控制允许的请求方式
    -如果不写,写了什么方法,就允许什么请求

模板语法

"""dtl中得所有语法,它都支持,并且能够使用   函数()  可以传参数"""

from flask import Flask, render_template,Markup
app = Flask(__name__)
@app.route('/')
def index():
    # return render_template('test.html', name='lqz', age=19)
    # return render_template('test.html',
    #                        user={
    #                            1: {'name': 'lqz', 'age': 19, 'hobby': '篮球'},
    #                            2: {'name': 'lqz1', 'age': 20, 'hobby': '橄榄球'},
    #                            3: {'name': 'lqz2', 'age': 21, 'hobby': '乒乓球'},
    #                        })

    a='<a href="http://www.baidu.com">点我</a>'
    # a=Markup(a)
    return render_template('test.html',a=a)
if __name__ == '__main__':
    app.run()
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{#{{ name }}---{{ age }}#}


{#<table>#}
{#    {% for k,v in user.items() %}#}
{#        <tr>#}
{#            <td>{{ k }}</td>#}
{#            <td>{{ v.name }}</td>#}
{#            <td>{{ v['name'] }}</td>#}
{#            <td>{{ v.get('name') }}</td>#}
{#            <td><a href="/detail/{{ k }}">查看详细</a></td>#}
{#        </tr>#}
{#    {% endfor %}#}
{#</table>#}


{#<table>#}
{#    {% if name %}#}
{#        <h1>Hello {{ name }}!</h1>#}
{#    {% else %}#}
{#        <h1>Hello World!</h1>#}
{#    {% endif %}#}
{#</table>#}


{#{{ a|safe }}#}
{{ a}}


</body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值