Flask入门二(Flask的CBV、模版语法、请求和响应、session执行流程分析、Flask闪现、请求拓展、g对象、蓝图、导出Flask项目依赖)

一、Flask的CBV

1.CBV的写法

from flask import Flask
app = Flask(__name__)
app.debug = True

# FBV的写法
@app.route('/')
def index():
    return 'hello'


# CBV的写法
from flask.views import MethodView
class TestView(MethodView):
    def get(self):
        return '我是get'

    def post(self):
        return '我是post'

# 注册路由
# as_view必须加一个字符串---》是路由的别名
# endpoint 和 as_view(name= 路由别名),以谁为准?
# 读源码后,知道了,以 endpoint 为准
# 如果endpoint 没传--》endpoint是 view_func.__name__ 视图函数的名字 ,别名就是函数名
# 如果endpoint 没传,as_view(name= 路由别名)也没传---》去视图函数名字-->视图函数都是:view
# as_view(name= 路由别名) 有什么用? 把view的名字改为了,你传入的字符串名
app.add_url_rule('/test', 'test', TestView.as_view('test'))


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

在这里插入图片描述

2.CBV的执行流程

	'从上面CBV的写法来查看执行流程'
	1.app.add_url_rule('/test', 'test', TestView.as_view('test'))
		-这个注册路由的第三个参数,放视图函数的内存地址,也就是TestView.as_view('test') 是函数内存地址
		
	2.所以我们需要在TestView中找类的方法as_view
		-已知我们自己写的TestView中没有写这个方法,所以得去继承的MethodView中寻找,最后在MethodView继承的View中找到了
		
		@classmethod  '把源码精简一下'
	    def as_view(cls, name,*class_args, **class_kwargs):
	        def view(**kwargs):
	        	'这里是把它放到异步函数中操作,本质就是return了self.dispatch_request(**kwargs)'
	            return current_app.ensure_sync(self.dispatch_request)(**kwargs)
	        return view
	        
	3.app.add_url_rule的第三个位置,也就是as_view,放的就是View的内层函数

	4.当请求来了的时候,路由匹配成功,就会执行view(参数),本质上就是执行self.dispatch_request(**kwargs)

	5.所以我们要去找dispatch_request方法,我们视图类中没有,那么去父类MethodView中寻找,结果找到了
	'这个就跟我们Django中的CBV一样了'
		'然后看到self.dispatch_request中方法 ,在当前视图类中反射,请求方式的小写字符串(get,post),如果我们写了这些方法 就会去执行。'
	    def dispatch_request(self, **kwargs: t.Any) -> ft.ResponseReturnValue:
	        # request.method.lower() 请求方式变小写
	        # self是视图类的对象
	        # 去视图类的对象中反射跟请求方式同名的方法 假设是get方法
	        meth = getattr(self, request.method.lower(), None)
	        if meth is None and request.method == "HEAD":
	            meth = getattr(self, "get", None)
	        assert meth is not None, f"Unimplemented method {request.method!r}"
	        # get(传入参数)
	        return meth(**kwargs)  

3.endpoint 的使用

	1.如果写了endpoint,别名以它为准,如果不写以as_view的参数为准
	app.add_url_rule('/test', endpoint='xxx',view_func=TestView.as_view('test'))
	
	'逻辑:'
	1 app.add_url_rule('/test',endpoint='xxx', view_func=TestView.as_view('test'))
	
	2 endpoint = _endpoint_from_view_func(view_func)
		如果endpoint没传也就是None,就会走这句 view_func是TestView.as_view('test')  它就是函数名
		if endpoint is None:
            endpoint = _endpoint_from_view_func(view_func)	# view_func.__name__
        options["endpoint"] = endpoint		# 如果都是endpoint就会冲突
        
	3 _endpoint_from_view_func(view_func)---》返回了传入的函数的名字
		return view_func.__name__
		# 如果没有其他更改--->所有cbv的函数内存地址都是view
	
	4 如果上面传入了TestView.as_view('test'),它的函数名就是view---》endpoint就是view
		-view.__name__ = name
	    -view的名字 是咱么  TestView.as_view('名字') 传入的名字,不再是view了
	
	'总结:'
	endpoint如果不传,会以视图函数的函数名作为endpoint
    	-fbv:如果不写endpoint,会以函数名作为endpoint,但是如果多个视图函数加了同一个装饰器,又没有指定endpoint,就会出错了
        -cbv:调用as_view一定要传入一个字符串---》如果endpoint没写,endpoint就是传入的这个字符串,如果写了,这个字符串没用
        
    如果传了,直接以endpoint传入的作为endpoint


	TestView.as_view(name='index'),name到底有啥用
		app.add_url_rule('/test', view_func=TestView.as_view('test'))
	   	没有传endpoint,Login.as_view('login')是view函数的内存地址
	       endpoint会以函数名作为endpoint的值,现在所有函数都是view,必须传入name,来修改调view函数的名字
	       如果传了endpoint,别名以endpoint为主,如果不传endpoint,别名以name为主
	       app.add_url_rule('/test', view_func=TestView.as_view(name='test'),endpoint='xxx')

4.CBV中得methods作用

	视图类中有个属性就是methods = ['GET', 'POST']
	用来控制允许的请求方式 写了什么方法 就允许什么请求 若没有写则不能使用该方法

5.CBV加装饰器

	1 使用步骤:在类中加入类属性:
	class UserView(MethodView):
	    decorators = [装饰器1,装饰器2] # 先写的装饰器放在最内部(最左边),是最后执行的装饰器
	    def get(self):
            return 'get'
	
	    def post(self):
	        return 'post'
	
	2.我们在as_view源码中可以看到
    if cls.decorators:
        view.__name__ = name
        view.__module__ = cls.__module__
         # 这就是装饰器的本质原理
        '循环拿出,然后使用装饰器来执行被装饰函数,然后在把执行的赋值给被装饰函数'
        for decorator in cls.decorators:
            view = decorator(view)

二、模版语法

1.渲染变量

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>用户列表</h1>
    <table>
        {% for k,v in user_dict.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>

2.变量的循环

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>用户列表</h1>
    <table>
        {% for k,v in user_dict.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>

3.逻辑判断

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>用户列表</h1>
    <table>
        {% if name %}
          <h1>Hello {{ name }}!</h1>
        {% else %}
          <h1>Hello World!</h1>
        {% endif %}
    </table>
</body>
</html>

比django中多可以加括号,执行函数,传参数

	from flask import Flask,render_template,jsonify,make_response
	from markupsafe import Markup
	app = Flask(__name__, template_folder='temp')
	
	def func1(arg):
	    return Markup("<input type='text' value='%s' />" %(arg,))
	@app.route('/')
	def index():
	    return render_template('index.html',ff = func1)
	
	if __name__ == '__main__':
	    app.run()

	index.html
	<!DOCTYPE html>
	<html lang="en">
	<head>
	    <meta charset="UTF-8">
	    <title>Title</title>
	</head>
	<body>
	
	    {{ff('六五')}}
		{{ff('六五')|safe}}
	
	</body>
	</html>

	注意:
	1.Markup等价django的mark_safe ,
	2.extends,include一模一样

三、请求和响应

	from flask import Flask
    from flask import request
    from flask import render_template
    from flask import redirect
    from flask import make_response

    app = Flask(__name__)


    @app.route('/login.html', methods=['GET', "POST"])
    def login():
    	'请求(request,http请求中的东西,都能从request中取出来)'
        1.请求相关信息
        # request.method  提交的方法
        # request.args  get请求提及的数据
        # request.form   post请求提交的数据
        # request.values  post和get提交的数据总和
        # request.cookies  客户端所带的cookie
        # request.headers  请求头
        # request.path     不带域名,请求路径
        # request.full_path  不带域名,带参数的请求路径
        # request.script_root  
        # request.url           带域名带参数的请求路径
        # request.base_url		带域名请求路径
        # request.url_root      域名
        # request.host_url		域名
        # request.host			127.0.0.1:500
        # request.files
        # obj = request.files['the_file_name']
        # obj.save('/var/www/uploads/' + secure_filename(f.filename))
        
		'响应'
        2.响应相关信息
        # return "字符串"
        # return render_template('html模板路径',**{})
        # return redirect('/index.html')
        #return jsonify({'k1':'v1'})

        # response = make_response(render_template('index.html'))
        # response是flask.wrappers.Response类型
        # response.delete_cookie('key')
        # response.set_cookie('key', 'value')
        # response.headers['X-Something'] = 'A value'
        # 向响应头中添加
        res = make_response('hello')
        res.headers['xx'] = 'll'
        # return response
        retrun res

        return "内容"

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

四、session执行流程分析

1.基本使用

	'cookie 是客户端浏览器的键值对,session是存在于服务端的键值对'
	flask的session存在哪了?它加密后存放到了cookie中
	
	from flask import Flask, request,session
	from flask.views import MethodView
	
	app = Flask(__name__)
	app.debug = True
	app.secret_key='xuoikjfdlsakjfs'
	
	
	@app.route('/login', methods=['GET'])
	def login():
	    name = request.args.get('name')  # 获取路径后面的?name=xxx
	    '存入全局的Session,session需要匹配secret_key才能使用'
	    session['name'] = name
	    return 'Hello World!,%s' % name
	
	
	class UserView(MethodView):
	    def get(self):
	    	取值全局Session
	        name = session.get('name')
	        if name:
	            return '欢迎你:%s' % name
	        else:
	            return '没有登录无法查看'
	
	    def post(self):
	        return 'post'
	
	app.add_url_rule('/user', 'user', UserView.as_view('user'))
	
	if __name__ == '__main__':
	    app.run(debug=True)

2.执行流程

	'flask中通过SecureCookieSessionInterface对象来控制整个session的使用流程'
		app.session_interface=SecureCookieSessionInterface()
		
	1.登录成功后,会放到session中数据,最终它把session中的数据取出来,并且加密(dumps),放到cookie中,
	然后返回给前端-->save_session
	
	2.请求来了,请求中携带了cookie,然后falsk框架会取出cookie,然后会进行解密(loads)得到数据,
	把数据放到session中,然后进入到视图函数,这样在后续的视图函数中直接使用session.get()
	就能取出当时放入的值-->open_session

	'注意:不同浏览器,放的不一样,取出来也不一样'

	'SecureCookieSessionInterface 俩方法来支撑上面的流程'
	1.open_session: 请求来的时候--》解析出cookie,放到session中
	def open_session(self, app: Flask, request: Request) -> SecureCookieSession | None:
		# 拿到解密或加密的对象
	    s = self.get_signing_serializer(app) # 获取签名的序列化
	    if s is None:
	        return None
	    
	    # request.cookie 取出客户端携带的cookie
	    # self.get_cookie_name(app) ---》 app.config["SESSION_COOKIE_NAME"]--》session
	    # eyJuYW1lIjoieHh4In0.ZeVMAw.2iCEYHAW7rDaH6Z5ntmKonErTbw
	    # val 就是取出的三段 头 荷载 签名
	    val = request.cookies.get(self.get_cookie_name(app))
	    if not val:
	        # 如果是空,就会走这里,这里做成空session后,返回了
	        return self.session_class()
	    # 如果不为空,继续执行下面代码,cookie在过期时间内
	    max_age = int(app.permanent_session_lifetime.total_seconds())
	    try:
	        # 解密--》把eyJuYW1lIjoieHh4In0.ZeVMAw.2iCEYHAW7rDaH6Z5ntmKonErTbw解成字典
	        data = s.loads(val, max_age=max_age)
	        # 组装成有 数据的session
	        return self.session_class(data)
	    except BadSignature:
	        return self.session_class()

	2.save_session:请求走的时候---》放到cookie中
	def save_session(self, app: Flask, session: SessionMixin, response: Response) -> None:
		 # 拿到  session 字符串  拿到配置文件中对应的配置
        name = self.get_cookie_name(app)
        domain = self.get_cookie_domain(app)
        path = self.get_cookie_path(app)
        secure = self.get_cookie_secure(app)
        samesite = self.get_cookie_samesite(app)
        httponly = self.get_cookie_httponly(app)
        if session.accessed:
            response.vary.add("Cookie")
            
        # 如果session不为空,就继续往下走---》视图函数中放入了值  session[name]=jack
        if not session:
            # 判断session是否被修改过
            if session.modified:
                # 如果session被修改过,删除cookie
                response.delete_cookie(
                    name,
                    domain=domain,
                    path=path,
                    secure=secure,
                    samesite=samesite,
                    httponly=httponly,
                )
                response.vary.add("Cookie")

            return

        if not self.should_set_cookie(app, session):
            return

       	# 获取过期时间
        expires = self.get_expiration_time(app, session)
        # 获得加密对象,使用dumps对session进行加密---》asdfas.asdfas.asdfasd
        val = self.get_signing_serializer(app).dumps(dict(session))  # type: ignore
        # 放到cookie中
        response.set_cookie(
            name,
            val,  # type: ignore
            expires=expires,
            httponly=httponly,
            domain=domain,
            path=path,
            secure=secure,
            samesite=samesite,
        )
        response.vary.add("Cookie")

3.Django中session的执行流程

	# django 在中间件中做的
	session不是直接加密放在cookie 中得, 加密放在 django-session表中--》有个随机字符串对应
	
	1 app中要注册 session ---》生成django-session表
		'django.contrib.sessions',
	    
	2 中间件要注册--》真正支撑session流程的
	'django.contrib.sessions.middleware.SessionMiddleware',
	
	3 支撑session流程的
	请求走了---》把session--》写入到cookie中
		-def process_response(self, request, response):---》等价于---》save_session
	请求来了---》从cookie中取出来--》查数据库--》放到session中
		-def process_request(self, request)---》等价于---》open_session

	def process_request(self, request):
		# 取出 前端在cookie中携带的  随机字符串
	    session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
	    # SessionStore 实例化得到对象---》session_key是随机字符串
	    # 内部 根据随机字符串去django-session表中--》查出 session_data--》解密--》包装成对象
	    # 赋值给request.session -->后续所有视图函数中,都能使用request.session 放值或取值
	    request.session = self.SessionStore(session_key)
	
	def process_response(self, request, response):
	    try:
	        accessed = request.session.accessed
	        modified = request.session.modified
	        empty = request.session.is_empty()
	    except AttributeError:
	        return response
	    if settings.SESSION_COOKIE_NAME in request.COOKIES and empty:
	        response.delete_cookie(
	            settings.SESSION_COOKIE_NAME,
	            path=settings.SESSION_COOKIE_PATH,
	            domain=settings.SESSION_COOKIE_DOMAIN,
	            samesite=settings.SESSION_COOKIE_SAMESITE,
	        )
	        patch_vary_headers(response, ('Cookie',))
	    else:
	        if accessed:
	            patch_vary_headers(response, ('Cookie',))
	        if (modified or settings.SESSION_SAVE_EVERY_REQUEST) and not empty:
	            if request.session.get_expire_at_browser_close():
	                max_age = None
	                expires = None
	            else:
	                max_age = request.session.get_expiry_age()
	                expires_time = time.time() + max_age
	                expires = http_date(expires_time)
	            # Save the session data and refresh the client cookie.
	            # Skip session save for 500 responses, refs #3881.
	            if response.status_code != 500:
	                try:
	                    request.session.save()
	                except UpdateError:
	                    raise SessionInterrupted(
	                        "The request's session was deleted before the "
	                        "request completed. The user may have logged "
	                        "out in a concurrent request, for example."
	                    )
	                # 往cookie中放入 key是:session  value值是随机字符串: request.session.session_key
	                response.set_cookie(
	                    settings.SESSION_COOKIE_NAME,
	                    request.session.session_key, max_age=max_age,
	                    expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
	                    path=settings.SESSION_COOKIE_PATH,
	                    secure=settings.SESSION_COOKIE_SECURE or None,
	                    httponly=settings.SESSION_COOKIE_HTTPONLY or None,
	                    samesite=settings.SESSION_COOKIE_SAMESITE,
	                )
	    return response

五、Flask闪现

1.作用

	'访问A页面出现错误 重定向到B页面,要在B页面上展示A页面报错的信息'
	-在某个请求中放入值,另一个请求中取出,取出来后就没了(只能使用一次)
	-谁(浏览器)放入的,谁(浏览器)才能取出来
	-所以它实际上是放在session中了,但是flask中session是通过加密放在cookie中
	-所以闪现必须配合session(secret_key)使用
	

	使用方式1:
		设置值:
		    flash('用户名或密码错误')	# 可以用多次  
		取值:
		    get_flashed_messages()		# 取出列表

	使用方式2(高级使用,设置flash时,设置category分类):
		设置值:
			flash('用户名或密码错误',category='login')
	        flash('register的错误',category='register')	# 可以使用多次
		取值:
			res = get_flashed_messages(category_filter=['login'])  # 可迭代对象
			res = res[0][1]  # 取出来的格式为,列表套元组
			

2.案例

	from flask import Flask,request,session,render_template,redirect,flash,get_flashed_messages
	
	app=Flask(__name__)
	app.secret_key='kjfldaoiuozflka'
	app.debug=True
	
	@app.route('/login', methods=['GET', 'POST'])
	def login():
	    if request.method=='GET':
	        return render_template('login.html')
	    else:
	        username = request.form.get('username')
	        password = request.form.get('password')
	        if username == 'jack' and password == '123':
	            # 存入session
	            session['name'] = username
	
	            return redirect('/')
	        else:
	            # 往flash中放入值
	            # flash('用户名或密码错误')
	            # 高级使用,设置分类
	            flash('用户名或密码错误',category='login')
	            flash('register的错误',category='register')
	            return redirect('/errors')
	            # return '用户名或密码错误!'
	
	
	@app.route('/',methods=['GET'])
	def index():
	    name = session.get('name')
	    if name:
	        return '欢迎您:%s'%name
	    else:
	        return '您还没有登录,请登录后尝试'
	
	
	@app.route('/errors')
	def errors():
	    # 从flash中取出值
	    # res = get_flashed_messages()[0]  # 是一个列表
	    # 高级使用,通过分类取出
	    res = get_flashed_messages(True,category_filter=['login'])  # 只拿登录相关的
	    res = res[0][1]  # 取出来的格式是列表套元组
	    # flash闪现,主要取出来就没有了
	    return '请求出错!,错误是:%s' % res
	
	
	if __name__ == '__main__':
	    app.run()

3.Django中的闪现(消息框架)

	1 注册app
	  'django.contrib.messages',

	2 注册中间件
	'django.contrib.sessions.middleware.SessionMiddleware',
	'django.contrib.messages.middleware.MessageMiddleware',

	3 配置 templates
	TEMPLATES = [
	    {
	        'BACKEND': 'django.template.backends.django.DjangoTemplates',
	        'DIRS': [os.path.join(BASE_DIR,'templates')],
	        'APP_DIRS': True,
	        'OPTIONS': {
	            'context_processors': [
									...
	                'django.contrib.messages.context_processors.messages',
	            ],
	        },
	    },
	]
	
	4 以后再视图函数中 放入
		from django.contrib import messages
		messages.debug
		messages.info
		messages.success
		messages.warning
		messages.error
		messages.warning(request,'登陆失败,用户名或密码无效')
	
	5 在 视图函数中取
		get_messages(request)
		# 4 在模板中
		{% if messages %}
		    {% for message in messages %}
		        <div class="alert alert-{{ message.tags }} fade in">
		            {{ message }}
		        </div>
		    {% endfor %}
		{% endif %}

六、请求扩展

在请求进入视图函数之前执行一些代码,请求出了视图函数以后执行一些代码,类似于django的中间件完成的功能6个装饰器(原来有7个,新版本去掉一个)

	1. before_request:在请求进视图函数之前执行
		多个的话会从上往下依次执行 django:process_request,如果返回四件套之一就直接返回了,在这里面正常使用request对象
		
	2. after_request:在请求从视图函数走之后执行
		多个的话会从下往上依次执行 django:process_response一样,要有参数和返回值参数就是response对象 返回值也必须是resposne对象
		session、request照常使用
		
	3. before_first_request:(这个新版本去掉了)项目启动后第一次访问会执行以后再也不执行了
		可以做一些初始化的操作
		
	4. teardown_request:每一个请求之后绑定一个函数即使遇到了异常,每个请求走都会执行记录错误日志
		@app.teardown_request
		def tear_down(e):
			print(e)  # 如果有异常,这是异常对象
			print('我执行了')
			
	5. errorhandler路径不存在时404,服务器内部错误500
		@app.errorhandler(404)
		def error_404(arg):
			print('404会执行我')
			return "404错误了"
			return render_template('404.html')
		
		@app.errorhandler(500)  # debug为False请情况下才能看到
		def error_500(arg):
		    print('500会执行我')
		    return "服务器内部错误"
		    
	6. template_global 标签 在模板中用  {{sb(1,2)}}
		@app.template_global()
			def sb(a1, a2):
			    return a1 + a2
			    
	7. template_filter过滤器  在模板中用  {{10|db(1,2)}}
		@app.template_filter()
			def db(a1, a2, a3):
			    return a1 + a2 + a3

展示案例

	from flask import Flask,request,session,render_template,redirect,flash,get_flashed_messages
	app=Flask(__name__)
	app.secret_key='kjfldaoiuozflka'
	app.debug=True
	
	@app.before_request  # 任意一次请求来的都会执行,被装饰函数
	def before_request():
	    # 判断如果没有登录,重定向到登录
	    if session.get('name') or 'login' in request.path:
	        print('请求来了')
	    else:
	        return redirect('/login')
	
	
	@app.route('/login', methods=['GET', 'POST'])
	def login():
	    if request.method=='GET':
	        return render_template('login.html')
	    else:
	        username = request.form.get('username')
	        password = request.form.get('password')
	        if username == 'jack' and password == '123':
	            session['name'] = username
	
	            return redirect('/')
	        else:
	            flash('用户名或密码错误',category='login')
	            return redirect('/errors')
	
	
	@app.route('/',methods=['GET'])
	def index():
	    name = session.get('name')
	    if name:
	        return '欢迎您:%s'%name
	    else:
	        return '您还没有登录,请登录后尝试'
	
	
	@app.route('/errors')
	def errors():
	    res = get_flashed_messages(True,category_filter=['login'])
	    res = res[0][1]  # 取出来的格式是列表套元组
	    return '请求出错!,错误是:%s' % res
	
	
	@app.teardown_request  # 每一个请求之后绑定一个函数,即使遇到了异常
	def teardown_request(error):
	    # 可以在这里记录错误日志
	    print(error)
	
	
	@app.errorhandler(404)  # 监听http响应码:只要响应码对应,就会执行对应的函数
	def errorhandler(args):  # 会和debug模式冲突,因为debug模式是要在页面展示错误,会冲突
	    # 也可以写一个页面来展示404页面
	    return '路径不存在,404'
	
	
	@app.after_request  # 任意一次请求走了的都会执行,被装饰函数
	def after_reqeust(response):
	    print('请求走了')
	    # 在响应头中加入一些数据
	    response.headers['hello'] = 'world'
	    return response
	
	
	# 标签
	@app.template_global()  # {{sb(1,2)}}
	def sb(a1, a2):
	    return a1 + a2
	
	
	# 过滤器
	@app.template_filter()  # {{10|db(1,2)}}
	def db(a1, a2, a3):
	    return a1 + a2 + a3
	
	
	if __name__ == '__main__':
	    app.run()

七、g对象

专门用来存储用户信息的g对象,g的全称的为global
g对象在一次请求中的所有的代码的地方,都是可以使用的

from flask import Flask,request,session,g
# g global 全局的意思,每次请求,这个g一直存在,可以设置值和取值
app = Flask(__name__)
app.secret_key = 'kjfldaoiuozflka'
app.debug = True


@app.before_request
def before():
    # 在g中设置值
    g.name = 'jack'  # 放入g中


def ShowName():
    print('ShowName',g.name)

@app.route('/', methods=['GET'])
def index():
    # 取出g中得值
    print('index',g.name)
    ShowName()
    return 'hello world'


@app.after_request
def after(response):
    print(g.name)
    return response


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

八、BluePrint蓝图

blueprint:对目录进行划分,因为之前所有代码都写在一个py文件中,后期肯定要分到多个文件中

1.不用蓝图

	flask_no_blueprint
	core
		-views   # 视图函数的py文件
			-user.py  # 用户相关视图,可以在views里面写任意你想的视图,不过写完需要再__init中导入注册
		-__init__.py  # 里面定义了Flask的app对象
		-models.py
		-settings.py  # 配置文件,使用的是类的那种
	static   # 静态文件存放位置
	templates  # 模板存放位置
	main.py  # 启动文件

	# 小配置演示
	'settings.py'
		class DevelopmentConfig(Config):  # 例如开发配置
	    	DEBUG = True
   	
   	'views/user.py'
	   	from core import app  # 导入appp
		@app.route('/')
		def index():
		    return 'from index'
		    
		from flask import render_template
		@app.route('/register')
		def register():
		    return render_template('register.html')  # 读取模版文件

	'core/__init__.py'
		from flask import Flask
		app = Flask(__name__,template_folder='../templates')  # 加载模版文件位置
		app.config.from_object('core.settings.DevelopmentConfig')  # 导入配置
		from .views import user  # 导入注册视图
	
	'main.py'
		from core import app
		if __name__ == '__main__':
		    app.run()

2.蓝图小项目目录划分(只有一个app)

	flask_blueprint_little  # 项目名
		-views  # 视图文件
				-order.py  # 订单视图
				-user.py  # 用户视图
		-__init__.py  # app对象创建的地方
		-models.py  # 表模型相关
		-settings.py   # 配置文件
	-static  # 静态文件
	-templates  # 模版文件
		-register.html
	-manage.py  # 启动文件
	
	# 小配置演示
	'settings.py'
		class DevelopmentConfig(Config):  # 例如开发配置
		    DEBUG = True
	'flask_blueprint_little/__init__.py'
		from flask import Flask
		# 实例化flask对象,加载模版文件位置及静态文件位置
		app = Flask(__name__,template_folder='../templates',static_folder='../static')
		# 导入配置文件
		app.config.from_object('flask_blueprint_little.settings.DevelopmentConfig')
		
		# 注册蓝图
		from flask_blueprint_little.views.user import user
		app.register_blueprint(user)

	'views/user.py'
		from flask import render_template
		'''
		蓝图使用步骤
		1.蓝图类实例化得到一个对象
		2.在视图函数上,使用蓝图注册路由
		3.在app中注册蓝图
		'''
		from flask import Blueprint
		# 第一个参数叫蓝图名
		user=Blueprint('user',__name__)
		
		# 使用蓝图注册路由
		@user.route('/')
		def index():
		    return 'index'
		
		@user.route('/register')
		def register():
		    return render_template('register.html',name='jack')

	'manage.py'
	from flask_blueprint_little import app
	if __name__ == '__main__':  # 启动文件
	    app.run()

3.大型项目目录划分(多个app)

	flask_blueprint_big  # 项目名字
		-apps  # 应用
			-order # order app相关
			-user  # user app相关
				-static  # user的静态文件
				-templates  # user的模版文件
				-__init__.py  # user的蓝图初始化
				-models.py  # user的表模型
				-views.py  # user的视图
		-__init__.py  # app注册位置
		-settings.py  # 配置文件
	-manage.py  # 启动文件

	# 小配置演示
	'settings.py'
		class DevelopmentConfig(Config):  # 例如开发配置
		    DEBUG = True

	'apps/user/__init__.py'
		# 蓝图初始化
		from flask import Blueprint
		# user,app的蓝图实例化,并加载user app的模版文件及静态文件位置
		user_blue = Blueprint('user',__name__,template_folder='./templates',static_folder='./static')

	'user/views.py'
		# user app的视图文件
		from . import user_blue
		from flask import render_template
		# 在视图函数上,使用蓝图注册路由
		@user_blue.route('/')
		def index():
		    return 'index'
		
		@user_blue.route('/register')
		def register():
		    return render_template('register.html')
	
	'flask_blueprint_big/__init__.py'
		from flask import Flask
		app = Flask(__name__)
		# 实例化得到flask对象,导入配置文件
		app.config.from_object('flask_blueprint_big.settings.DevelopmentConfig')
		
		# 在app中注册蓝图
		from .apps.user.views import user_blue
		app.register_blueprint(user_blue)

	'manage.py'
		# 启动文件
		from flask_blueprint_big import app
		if __name__ == '__main__':
		    app.run()

九、导出Flask项目依赖

	虚拟环境:只装了该项目的模块
	pip freeze > requirements.txt
	
	真实环境导出依赖会把所有都导出,可能会有问题导出太多
	- 项目依赖 pip3 install pipreqs
	- 生成依赖文件:pipreqs ./ --encoding=utf8
	- 安装依赖文件:pip3 install -r requirements.txt 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值