个人学习笔记

DAY 11.02
1,之前总结 
	复习js操作获取标签,操作标签,和ajax等
	
2,了解flask 视图 MVT  model view t?
运行flask程序时, 提示端口被占用

				@报错
				socket.error: [Errno 48] Address already in use
				解决
				查看占用5000端口的进程
				lsof -i:500
				关闭进程
				kill <pid>
				


3,web原理 客户端发送响应,服务器返回响应.
	总结(浏览器在地址栏里写上百度回车的分析
	1,浏览器自动补全http或者https的协议命令,
	2,浏览器访问dns服务器解析baidu映射的ip地址,给浏览器.
	3,浏览器向指定的ip地址发送请求报文.报文包括请求头,请求行,空行,请求体,还有请求协议请求方法等.
	4,服务器接受请求,并处理请求,判断请求内容,若为静态资源则直接返回,若为动态资源,则查询数据库,然后返回数据.
	5,服务器生成响应报文给客户端.)
	
	
	![nil](https://img-blog.csdnimg.cn/20181123230316900.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L211emhlMTAyNA==,size_16,color_FFFFFF,t_70)
	3.1 客户端:浏览器,app,代码,测试工具等  http 80 https 443 
	3.2 dns 域名解析服务器 世界上13台根域名解析服务器,大部分在美国.子级域名解析服务器. 返回ip地址
	3.3 浏览器以特定格式向ip地址发送报文请求  请求方法 /post/delete/put/get 增删改查四种方法.
	3.4 服务器接收请求,处理请求.六字箴言(写接口,调接口) 也叫api 函数 类 请求处理类等
			写接口:接收参数--检查参数--业务请求--返回数据  业务请求里包含查询数据去数据库里.
			调接口:调别人的接口 或者自己的接口.
	3.5 服务器生成响应报文返回给浏览器.(包括默认处理方式:静态资源  html css 等
											和动态处理方式:有请求参数的请求 ;查询字符串:url中?后面的以=传值,以&分割的信息.
		 响应状态码:
		   返回的状态码和状态不一致的情况是有可能发生得 
			比如Web应用程序内部错误,但仍然返回 

			200 OK 
			请求正常处理完毕
			204 No Content 
			请求成功处理,没有实体的主体返回
			206 Partial Content 
			GET范围请求已成功处理
			301 Moved Permanently 
			永久重定向,资源已永久分配新URI
			302 Found 
			临时重定向,资源已临时分配新URI
			303 See Other 
			临时重定向,期望使用GET定向获取
			304 Not Modified 
			发送的附带条件请求未满足
			307 Temporary Redirect 
			临时重定向,POST不会变成GET
			400 Bad Request 
			请求报文语法错误或参数错误
			401 Unauthorized 
			需要通过HTTP认证,或认证失败
			403 Forbidden 
			请求资源被拒绝
			404 Not Found 
			无法找到请求资源(服务器无理由拒绝)
			405  method not allowed
			请求方法不允许
			500 Internal Server Error 
			服务器故障或Web应用故障
			503 Service Unavailable 
			服务器超负载或停机维护
4, 框架介绍
	flask特点:轻巧简洁扩展  核心 werkzeug 和 jinja2  ???
	常用扩展包:
	wsgi 协议  
	@常识  奇数版本是开发版  偶数版一般是稳定版
	
5,mk创建进入虚拟环境	
	pip freeze > requirement.txt
	
	
6, hello world
	三点:
	
	6.1 视图函数不能重名.
	6.2 url可以重复
		因为http不同的请求方法为了不同的操作.
		@一个函数只有一个返回值  布尔类型的!
		debug=True ???
		@返回数据只能是浏览器认识的类型
		@不使用装饰器函数能实现路由映射.
		
7, 返回不符合协议默认状态的状态码,可以实现数据交互.

@app.route('/abc',methods=['POST','GET'])
def hello2018():
    # return 可以返回状态码,也可以返回不符合http协议的状态码,用来实现前后端的数据交互
    """
    前端发送ajax:
    $.ajax({
        url:'/abc',
        data:。。。, 发送到后端的数据
        contentType:'', 发送到后端的数据类型
        dataType:'json' 后端返回的数据类型
        success:function(resp){
            if (resp == '666'){
                alert(errmsg)
            }else{

            }

        }
    })

    errno=666,errmsg='用户名已注册'
    return:()


8, 加载配置文件的三种形式:
	8.1 外链 从外部py中导入
	8.2 ini文件
	8.3 envvar('外部环境变量的设置文件')
	
	from flask import Flask
# 导入配置类
# from config import Config
from config import config_dict
app = Flask(__name__)
# 加载配置文件:三种实现形式
# 1、加载配置对象,config是flask内置的配置对象
# 重点掌握:因为扩展性更强
# app.config.from_object(Config)
# app.config.from_object(config_dict['pro'])
# 2、加载配置文件
# app.config.from_pyfile('config.ini')
# 3、加载环境变量
# app.config.from_envvar('SET')


@app.route('/')
def index():
    return 'hello world'

if __name__ == '__main__':
    app.run()
	
9, 9.1 重定向 redirect(url) 项目地址变化的需求  需要导入方法
	9.2 url_for  跟视图函数名  这样少该地址.  反向解析  和url_map相对.
	
	from flask import Flask,redirect,url_for

app = Flask(__name__)
# 重定向redirect 接受参数为location,具体的url地址
# 重新发送网络请求,跳转页面
#项目路径url或文件发生变化的情况下需要重定向
@app.route('/')
def index():
    url = 'https://www.baidu.com/'
    return redirect(url)

# @app.route('/for')
#
# # url_for 反向解析,接受参数endpoint 视图函数名
def re_url_for(jisis):
    return redirect(url_for('index'))

if __name__ == '__main__':
    print(app.url_map)
    app.run()
# 重定向如果是定向给新的地址,那原来的地址要不可用,吗
# 其实如果比如在不同页面点击链接都会跳转到制定网址也比较形象.
# 或者,比如原地址是127.0.0.1:5000, 因为不能用了 或者不想让展示,就直接加一个重定向,让
# 他定向到想展示的地址.那怎么实现好多方法都定向到同一地址?

                                                                                   

 今日总结;
1,浏览器工作流程
2,什么是框架
3,什么是重定向


DAY 11.05

1,昨日总结 after_request   如果没有抛出错误,在每次请求后执行  有异常不会执行 异常是指服务器内部异常.
	127.0.0.1 - - [05/Nov/2018 09:00:27] "GET / HTTP/1.1" 200 -
	before request run---
	after request run---
	teardown request run---

2,上下文  语义环境  比如:
	包含请求上下文:request 和 session
	和应用上下文:current_app  和g
	
3,get请求和post请求的区别
	3.1 get请求没有请求体,
	3.1 并且url地址栏参数有长度限制.不超过2kb(浏览器限制的)
	提交form文件
	    <form action="http://127.0.0.1:5000/form" method="POST" enctype="multipart/form-data">

     <!-- 写的代码在提交包含文件类型的提交时必须进行编码处理 因为图片和文字肯定不是一个类型,他会默认 接受
    文字,加的属性为 enctype = 'multipart/form-data' -->
    <label for="">name</label><input type="text" name="name" id="">
    <label for="">password</label><input type="password" name="password" id="" >
    <input type="file" name="image">
    <input type="submit" name="提交" value="提交">
    <!-- <input type="reset" name="重置" > -->
4,request.form.get()
	from flask import Flask,request,current_app,sessions,g


app = Flask(__name__)

"""
请求上下文,request和session
request是flask的内置的请求上下文
request`的常用属性是 args from method url headers cookie  file 等

args查询的是字符串 url地址栏中 ?后面的以= 传值 &分割 

"""

# request的资本用法 args
@app.route('/')
def index():
    """ 1 获取get查询的字符参数"""
    name = request.args.get('name')
    age = request.args.get('age')
    print (name,age)
    # "zhangshan" "12"
    # s输出url的地址
    # print(request.url)
    # http://127.0.0.1:5000/?name="zhangshan"&age="12"
    # 输出请求方法
    # print(request.method)
    # print("------1-------")
    # print(request.headers)
    # print("------2-------")
    #
    # print(request.cookies)
    #
    # print("-----3--------")
    # !!总结 request方法可以在后端查看前端访问携带的信息, 可以做什么?


    return 'hello world'


#form表单请求 默认post
# @app.route('/form/',methods=['GET','POST'])
# def demo_form():
# #     获取表单参数
#     abc = request.form.get('abc')
#     name = request.form.get('name')
#     print(abc)
#
#     print(name)
#
#     # 总结  get方法也可以 方式调试不成功
#
#     return "demo form"

@app.route('/form',methods=['POST'])
def rec_files():
    image = request.files.get('value')
    image.save('./shabi.jpg')
    return 'save success'
if __name__ == '__main__':
    app.run(debug=True)
    print(app.url_map)


5,postman 可以模拟前段页面里的请求,来测试后端的交互.  用来试一下提交form表单的文件.
	记得post形式在body里加参数
	get在header里加参数

6,from flask_script import Manager  脚本管理器.
	manager.run(ip端口) 方法启动程序.可以在终端启动项目时,手动制定ip和服务.
	具体方法为在terminal打开,python方法运行,然后-p然后改端口.
	感觉没几把用


7, 模板. 目前是一种包含响应文本---html格式的文件  是前后端分离的一种工作方式.
	为了拆分出来专门交互的那部分工作.分担了视图的渲染数据的部分功能.
	
	建立模板文件夹记得mark成template
	
	
	
8,给模板传参数是字典形式. 使用时{{ 变量参数 }}
	<hr> 分割线标签
	loop.index  输出索引 从1 开始
	loop.index0 输出索引从0开始输出索引   他们用来判断循环次数.
	loop.cycle 给输出添加前缀  ??可以重命名
	
	返回值中 对应变量名书写形式为
	return render_template('index.html',data=data,my_list=my_list,my_dict=my_dict,data_list=data_list)

	
9,过滤器 filter 
	{{ 字符串 | 过滤器 | 过滤器2}} 链式调用过滤输出
	reverse 翻转 
	upper 大写
	lower 小写
	safe 渲染输出  默认不渲染输出也可以记为原始输出
	capitalize  第一个大写
	tittle  每个单词大写
	
10,CSRF cross-site request forgery  请求伪造
	用户A用浏览器向网站b发起正当请求,网站b返回请求,并给A注入cookie信息,此时或者在cookie到期之前A浏览器打开了c网站,c网站得到了	A的信息后发起了新的向b
	的新请求,然后客户A点开了 b,b网站验证了cookie信息允许进入,就实现了c通过a访问b,
	


DAY 11.06
1, 昨日总结 
	模板语法必须调用template语法才能执行 
	{{ 变量 }}
	{% endfor %}
	{% endif %}
	
2, csrf 借刀杀人 僚机 
	为什么会准确实现csrf攻击,恶意网站伪造好请求后,在路口等用户访问正常网站.就是守株待兔.
	也可以钓鱼去广阔流量中播撒恶意代码. 
	
3,过滤器 filter 
	3.1 列表处理 
	@字符串翻转原理  遍历输出列表再用索引取值方式重新排序. c语言中的原理描述就是以中间为
	轴对称调换指针位置.
	
	3.2 自定义过滤器
	<!DOCUTYPE = HTML>
	<html lang = "en">
	<head>
		<meta charset="UTF-8">
		<title>Title</title>
	</head>
	<body>
	</body>
	</html>
	!!自定义过滤器的方法  1 添加自定义函数 app.add_template_filter(do_listreverse,'lireverse')
	`````	2 装饰器函数 
	@app.template_filter('lireverse')
def do_listreverse(li):
    # 通过原列表创建一个新列表
    temp_li = list(li)
    # 将新列表进行返转
    temp_li.reverse()
    return temp_li
    
    !!!!!!
    @app.template_filter("dic_sortBV")
# 强转list
def dict_val_sort(key):
    temp_dict = list(key)
    # temp_dictval = list(value)
    print(temp_dict)
    # print(temp_dictval)
    temp_dict.reverse()
    return temp_dict
# 封装一个函数可以对字典进行排序或者翻转  ,只能达到这样子['name', 'age', 'hob']
4,模板复用
	4.1 宏的应用  macro 相当于def
	@前段页面的value全是为了实现交互的
	placeholder 提示信息!!!!傻逼没教
	{% macro fun() %}
	{% endmacro %}
	#调用
	{{ fun() }}
	也可以传参复用
	
	也可以封装自定义宏 以在其他文件中导入.import
	
	{% import '模板页面名' as newfu%}
	调用 newfu.()
	@注 宏常封装的是动态可复用的代码块 也就是格式相同参数不同的块.


{#宏的使用相当于模板中的函数,类似与python中的def
宏的作用实现模板页面的复用,一般封装的是局部可变的页面代码块#}
{#比如登录代码块#}
<input type="text" name="user" placeholder="user"><br>
<input type="text" name="password" placeholder="password"><br>
<input type="submit" name="提交" id="#">

{#定义宏#}
<hr>

{% macro fun() %}

<input  type="text" name="user" placeholder="user"><br>
<input type="text" name="password" placeholder="password"><br>
<input type="submit" name="#" id="#">

{% endmacro %}
{{ fun() }}
{#定义带参数宏#}
<hr>
{#{{ fun(type='muzhe',name='shabi',placeholder='hhhahha') }}???#}
{#不能这么用吗??#}
<hr>
{% import 'temp_macro.html' as f%}
{{ f.fun(type="muzhe",size=100) }}
</body>
</html>
{#为什么不显示前面的名字?aria-label="shahah"#}


5,模板继承(也是为了复用)  关键字 block
	格式:
	继承:extends '父类.html'  如果想用自己的样式 直接覆盖 要声明类block
	继承之后的子页面只能写在block内.其他额不会显示
	总结:
		多个页面中具有相同的顶部,底部,或者部分中间内容,可以使用继承. 
		包含或者部分的才需要使用,多个页面中重复的内用可以不用封装,
		多个页面中特有的内容才需要封装,让之类复用.
		灵活应用.
	@@模板不支持多继承!!!
	@@extends语句任何位置都行,但是建议写在第一行,可读性.
	@@父类和自己都使用要super调用
	@@在extends语句上面的语句也会生效,但是不会继承父类的样式.
	from flask import Flask,render_template
app = Flask(__name__)

@app.route('/')
def index():
    return render_template('3block.html')
    # return render_template('temp_macro.html')

"""
模板的继承
要点 模板中具有向东的顶部底部或者中间部分 可以使用继承
    2 多个页面中的重复内容留下不动?????????????    
    3 多个页面中特有内用封装成block 让子类重写 
    4 灵活   
    备注  模板不支持多继承
    extends语句建议写在第一行
    如果有想要自己实现的内用可以写在extends语句前面
    也想要父类内容也想要自定义内容可以用用super调用
    
"""
if __name__ == '__main__':
    app.run(debug=True)
# 总结 代码块的信息 是任意html格式的信息,
# 问题 号线没啥用啊super?
# 还有为啥我的extends没啥用啊
	
	
6,包含 跟继承不一样就是把包含的完整复用 可以用来复用完整的代码文件.  通常是已有内容后
		的增加内容  一般会加ignore missing的参数防止不存在.
		
	
# 总结 include包含的?代码块需要是一个html的文件名 或者一个文件名的list
# list怎么用不太知道????????????但是我的用法是在包含的文件名中包含文件名列表.可能也是办法	
  return render_template('demo4_include.html')	
{% include 'demo1_filters.html'  %}
{% include 'demo1_filters.html'  %}
{% include 'demo1_filters.html'  %}
{% include 'demo1_filters.html'  %}


		
7,总结@@@@@ 使用复用的方法  四个字  灵活应用 

8,特有变量函数  就是在很多地方使用并且意义和使用方法一样  一般需要导入后才能用.
  get_flashed_messages()  失去焦点后提示信息. 如果有编码错误 重启浏览器
  
9,WTFfroms表单 
	字段
	验证函数 anyof 在可选值之内
			  noneof 在可选值之外
			  
10,表单类 用来验证提交信息

验证器 token  生效需要通过调用函数. 他不仅验证请求参数是否形同
	还会验证表单验证中是否有token
	ipython
	import os base64
	然后...
	....
	
@ @@@注册 和 登录按钮 按道理说都是提交功能.

获取数据 form.get.('name')
	另一种form.user.data 
	然后打印
	
11, sql 关系型数据库    和   非关系型数据库.
	例子  微博用户的相互关注   自关联的多对多
			省区号    自关联1对多.
			
	三范式 1 原子性  每个字段不能拆分
			2 满足之前 且满足有主键约束
			3 满足之前俩 且满足非主键字段相互不能关联.

12, Alchemy  炼金术  抽象  
	orm 对象 关系 映射 
	sqlAlchemy 是orm 的框架
	flask_sqlAlchemy shi sqlAlchemy的封装
	
	
13,
mapping 解释一下:

DAY 11.08
![在这里插入图片描述](https://img-blog.csdnimg.cn/2018112323043076.png)
1,secret key 不是token的值 是根据token调用的.

2,一个进程包含多个线程 就是一对多 
3,开关和灯泡 一对多 或者双控就是多对多.
4,自关联 要包含一张对应关系的抽象表 这个表能查出两边的关系.

5,URI

6,默认端口 3306数据库  mogoudb 27017 

7,关键字 echo 打印sql语句.

8,定义模型类 
	8.1 链接数据库 app.config[]=
	8.2 dengdeng
	@

9, 创建数据库..

10, 等值过滤器 赋值 过滤器 就是以个等号?????????? 就是指定必须是谁来过滤,能加多个条件吗.

11, update()  修改,但是要想生效,要提交.
DAY 11.10
1,今天结婚3年了.

2,昨日总结,在ipython中测试数据库操作,在当前文件夹打开terminal,运行ipython,再import
	导入文件中所有的东西,然后就能用测试语句查询.
3,url_prefix = '' 在url地址里设置前缀,用于可以通过url实现直观了解访问类的作用.

4,使用蓝图  --创建对象 --调用路由 --程序中注册
	拆分文件使用蓝图 注意就是将第二个文件中的路由拆分出去 并导回第二个文件中,注意导入到创建的蓝图之下.
5,单元测试独立的功能模块运行是否正常,代表 postman
	用代码测试代码. 比如判断函数是否是斐波那契数列  就是用一个递归函数来测试一个数符不符合规则.
	
6,@写项目过程  静态页面--需求--功能分析--MVT(模型:定义模型,视图:实现逻辑,模板:实现展示)--遇山开山,遇水架桥.
	@具体实现步骤:1,实现基本功能(测试)
					
					2,扩展功能(测试)
					
7,wtf 验证
	删除数据, 要先查出来,有数据再删
	
8,测试
	1,导包
	2,定义测试类 三个函数 setup
	 		teardown
	 		test_add_data
	
	代码:
	from flask import Flask, render_template, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired

"""
 案例分析 

 案例作者和图书
 MVT: 
 m_model:定义模型  实现数据库表 存储数据 存储作者和书籍 然后配置数据库链接
 v_views: 实现业务逻辑,实现增删改查,并且实现增删改查之后的重定向局部刷新.
 T_template :实现数据展示,使用模板语法,加载数据渲染数据


 步骤:
 1 实现简单功能  
 2 定义模型类 实现数据表
 3 使用模板渲染数据 视图函数的数据传给模板
 
 4基本功能实现 扩展
  --添加表单 实现数据的增删改查
  在视图函数中实现逻辑操作  这些东西是方法 def的东西 不是类类是用来渲染的
 
 
 异常处理
 1 调用第三方接口
 2 参数处理
"""
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@localhost/authorbook'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 设置秘钥
app.config['SECRET_KEY'] = 'SDA2983SADdsalsa239saiidasfdsIJI'
app.config['SQLALCHEMY_ECHO'] = True
# 实例化sqlalchemy对象
db = SQLAlchemy(app)


class Author(db.Model):
    __tablename__ = 'authors'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32), unique=True)

    def __repr__(self):
        return 'author:%s' % self.name


class Book(db.Model):
    __tablename__ = 'books'
    id = db.Column(db.Integer, primary_key=True)
    info = db.Column(db.String(32), unique=True)

    def __repr__(self):
        return 'book:%s' % self.info


class Form(FlaskForm):
    wtf_author = StringField(validators=[DataRequired()])
    wtf_book = StringField(validators=[DataRequired()])
    wtf_submit = SubmitField('添加')


@app.route('/', methods=['GET', 'POST'])
def index():
    # 渲染所有数据
    # authors = Author.query.all()
    # books = Book.query.all()

    # 这是处理异常
    # authors, books = None, None # (????)

    # 实例化表单对象
    form = Form()
    if form.validate_on_submit():
        wtf_au = form.wtf_author.data
        wtf_bk = form.wtf_book.data
        #     把作者和书籍添加到数据库 数据必须通过模型类对象添加
        #
        auth = Author(name=wtf_au)
        book = Book(info=wtf_bk)
        try:
            db.session.add_all([auth, book])
            db.session.commit()
        except Exception as E:
            print(E)
            # 如果真有异常 要回滚
            db.session.rollback()
            # 添加数据库后数据库更新但是模板不更新,需要刷新,同步刷新,可以再次查询.
            try:
                authors = Author.query.all()
                book = Book.query.all()
            except Exception as E:
                print(E)

    try:
        authors = Author.query.all()
        books = Book.query.all()
    except Exception as E:
        print(E)

    return render_template('author_book.html', authors=authors, books=books,
                           form=form)  # , form=form, authors=authors, books=books


# 实现删除书籍功能
@app.route('/del_auth<int:id>')
def del_author(id):
    auth = Author.query.get(id)
    try:
        db.session.delete(auth)
        db.session.commit()
    except Exception as E:
        print(E)
        db.session.rollback()
    return redirect(url_for('index'))


@app.route('/del_book<int:id>')
def del_book(id):
    book = Book.query.filter_by(id=id).first()
    db.session.delete(book)
    db.session.commit()
    return redirect(url_for('index'))


if __name__ == '__main__':
    db.drop_all()
    db.create_all()
    au_ka = Author(name='卡尔.荣格')
    au_so = Author(name='亨利·戴维·梭罗')
    au_jo = Author(name='乔治.马丁')
    # 提交会话
    db.session.add_all([au_ka, au_so, au_jo])
    db.session.commit()

    bk_ka = Book(info='荣格自传')
    bk_so = Book(info='凡尔登湖')
    bk_jo = Book(info='GOT')
    # 提交回话
    db.session.add_all([bk_ka, bk_so, bk_jo])
    # 没有外键约束的话 添加的顺序与添加方式都可以无序.若有id限制则不可以
    db.session.commit()
    app.run(debug=True)

	
	
	
	
9,	Redis 数据库.
	nosql 非关系型数据库 只有key 和 对应的value
	适用于关系不复杂的项目.
	开源的使用ansi c语言编写  基于内存存储 以keyvalue实现的 nosql数据库.
	
	应用体现 新浪微博  session共享????、购物车 需要并发量很大的数据需求

	丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。

	
10,redis 数据操作
	增删改查  字符串 哈希hash 列表list 集合set 有序集合zset
	list
	set
	zset
	string
	hash
	
11, 个人习惯 redis-server –help 查看帮助文旦
	ps aux | grep redis 查看redis的服务器进程
	sudo kill -9 pid 杀死进程
	sudo redis-server / etc /redis /redis.conf  制定加载的配置文件.
	Redis -cli 启动客户端
	数据库没有名称 默认16个 从0开始 切换用select 10















	






12.. 上图看出 redis的数据结构都是字典形式的.
Key 的类型是字符串
key不能重复.
值有5种  string 
hash 
list
set
zset 有序set集合
对应五中数据类型 的增删改查

例如string  

12 增

set key value   ----get key
@setex  key 99 value 中间加时间 表示过期时间

@单独设置过期事件 expire key1 999  设置key1 过期时间为999.

@查看有效期 ttl key 查看key的过期时间 默认不过期 返回值为-1  已经过期的返回-2 
 


设置多个key和valuemset  a 28 b 28 c 28  -----mget  a b c  获取多个值

追加值 append a 12 相当于向字符串后面添加字符 ‘2812’


13.  查  支持正则表达式
查找key
keys * 查找所有key

keys ‘a*’ 查找含有字母a的key

exists key1  查找值是否存在key1 不存在返回0

16  删除
del  key1  删除key1 对应的值



17 , hash 
增 
hset user name  muzhe  增加user的属性name为muzhe
查
hkeys key 由key获取key的属性名 1) "name   2) "age"
hget key field  由上面查到的key的属性名来获取属性值
	hget user name
"muzhe"

同样获取多个属性的值 
hmget key field1 field2 

一次获取多个属性的属性值
hvals key


 删
删除整个hash 用del 加key
删除局部属性 要删除对应的属性名 hdel key field 

![在这里插入图片描述](https://img-blog.csdnimg.cn/20181123230455249.png)


17list
增
由左侧添加list
lpush key value1 value2..
rpush key val1 val2
展示列表 lrange key  start stop 名字和第几个值开始第几个值结束,

例4:获取键为'a1'的列表所有元素
lrange a1 0 -1
根据索引设置元素value
lset key index value


18 set 
 增 sadd key menmber1 menber2
查  smembers key
删 srem key member1  
del key  删除整个key


19 zset 有序set集合
序列靠权重实现 没有索引 不能修改
增
zadd  t2 1 zhangsan 2 lisi  3 wanbu 添加权重和元素
查
zrange t2 0 -1  从第0个开始都最后一个

返回score值在min和max之间的成员
      zrangebyscore key min max
    • 例3:获取键'a4'的集合中权限值在5和6之间的成员
      zrangebyscore a4 5 6
获取成员的权重
zscore key member
删
 	删除成员 zrem key member1
	zremrangebyscore key min max  按权重删除多个元素


总结string
    • set
    • setex
    • mset
    • append
    • get
    • mget
    • key
keys
    • exists
    • type
    • delete
    • expire
    • getrange
    • ttl
hash
    • hset
    • hmset
    • hkeys
    • hget
    • hmget
    • hvals
    • hdel
list
    • lpush
    • rpush
    • linsert
    • lrange
    • lset
    • lrem
set
    • sadd
    • smembers
    • srem
zset
    • zadd
    • zrange
    • zrangebyscore
    • zscore
    • zrem
    • zremrangebyscore

20, 主从配置 
	1 主服务器配置文件  sudo vim redis.conf
						bind 192.168.131.20
	2 重启服务
	3 从服务器 复制主服务器的conf文件改名为slave.conf
	4 修改从服务器配置文件 sudo vi slave.conf
	5 修改内容为 bind ip        192.168.131.20 和主服务器一样的原因是只有一台电脑 多台电脑则不同.
6 关键 slaveof 192.168.131.20 6379
port 6378       
应用配置文件  sudo redis-server slave.conf

7 查看主从关系  redis-cli -h 192.168.131.20 info  Replication

8 进入主从的命令分别为 redis-cli -h 192.168.131.20 -p 端口号

21, 主从服务器的数据操作类似,但是一般在主服务器上写 在从服务器上读

@Redis被配置为保存数据库快照,但它目前不能持久化到硬盘。用来修改集合数据的命令不能用
原因:
    • 强制关闭Redis快照导致不能持久化。 解决方案:
    • 运行config set stop-writes-on-bgsave-error no 命令后,关闭配置项stop-writes-on-bgsave-error解决该问题。

22,配置集群.
多台电脑组成的redis服务群  
主要命令 
1,
sudo cp /usr/share/doc/redis-tools/examples/redis-trib.rb /usr/local/bin/
2,
sudo sudo apt-get install ruby
3,创建集群 每台电脑
redis-trib.rb create --replicas 1 172.16.179.130:7000 172.16.179.130:7001 172.16.179.130:7002 172.16.179.131:7003 172.16.179.131:7004 172.16.179.131:7005

4,如果更新不成功为防火墙原因
-- 先查看⾃⼰的 gem 源是什么地址
gem source -l -- 如果是https://rubygems.org/ 就需要更换
-- 更换指令为
gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/
-- 通过 gem 安装 redis 的相关依赖
sudo gem install redis
-- 然后重新执⾏指令
redis-trib.rb create --replicas 1 172.16.179.130:7000 172.16.179.130:7001 172.16.179.130:7002 172.16.179.131:7003 172.16.179.131:7004 172.16.179.131:7005

5,出了yes 说明成功
6 ,链接集群 redis-cli -h 172.16.179.131 -c -p 7002

7 注意 必须存在3个以上的主节点才能建立集群.
DAY 11.12
1,昨日总结 适应团队 合作开发
  @复习数据库迁移
2,GIT 分布式版本管理系统  
	理念 多人操作一个文件 怎么合并版本.按照对比谁的版本比较先进来解决以谁为准.
	
3,入职基本工作 熟悉业务

4, git init   999,初始化后的文件都是隐藏的需要现实的话??
	git status
	git add 
	git commit -am  连添加追踪带提交描述  
	git log   git reflog    版本历史
	git reset --hard HEAD^   git reset --hard 版本号   @游戏存档 只能回滚 回滚以后不能前滚
	git reset HEAD <文件> 取消暂存区的修改
	@git checkout <文件> 重置工作区代码   这个和ctrl + z 还是有区别的  试一试就知道ctrlz的撤销范围很小 checkout的范围是上一次提交版本以后的所有代码,可以理解为没有add追踪的所有代码.
	@ git checkout <文件>的另一种用法  就是在工作区修改代码后已经add了并未commit,
	可以先git reset HEAD	 文件名 将add撤回到缓存区,再撤销掉工作区的代码
	
	  # 删除文件
	  rm 文件名
	  # git确定删除文件,对比添加文件git add 
	  git rm 文件名
	  # 删除后记录删除操作版本
	  git commit -m '删除描述'
	  @由上可知,删除操作也分为在工作区操作还是在仓库操作.
	  
	git checkout -- 文件名 撤销误删/  总结 撤销删除在提交删除之前操作的 如果已经git确认 那也没办法回撤.
	
	4.2 网络交互远程操作仓库
	经理工作:
	克隆远程仓库信息,配置自己身份信息,立项,push到库.
	push需要密码记录密码命令:
	git config --global credential.helper cache 
	永久记住密码是 git config --global credentail.helper store
	git push  提交项目文件 有可能要配置提交者信息
	git pull  协作提交有可能代码冲突,会返回错误,需要自己拉下来对比一下.决定后再提交
	
5, push时机,也就是保存时机 是个习惯.  局部功能实现push一下.
	经常pull 经常push.
	
6, 标签记录版本号   git tag 标签名 -m '标签描述'
				提交命令 git push origin 标签名
	这个操作好像是tag 相当于打包一下或者提纲一下 然后直接推送到仓库 仓库就会将本标签的内容分类展示.
	
7,分支  也是撤回的一种形式吧.	
	分支就是 区分开发与生产环境的代码.  其实也是tag的一种 是一个分出来的一个记忆点.起源.
	git branch查看分支  (git checkout -b dev)
	合并分支 切换到主分支上 然后git merge 分支名   
	 mayun  在终端git init 初始化 
	 然后在vsc里打开
	 
8,gitee支持有点问题 回来看一下


DAY 11.13

1, 昨日总结 记得暂存区撤销
2,项目目标
	2.1 web应用开发基本流程 4步
	2.2 web应用常见更能实现步骤
	2.3 git 使用
	2.4 源代码阅读 bug调试 工具使用  !!!!重点
	2.5 Diango 项目基础
	
3,前后端不分离 数据直接给浏览器 叫分离  比如直接写网页不用flask的
	模板渲染的 使用框架的 是项目前后端不分离  就是需要后端支持的

4, 项目分析
	4.1 技术实现  分析框架基础 数据库支持 三方扩展 部署系统要求
	
5, 框架搭建   基本的在一个文件中写 再拆出去.
	5.1 项目管理器
	5.2 项目配置信息  之后抽取出去
		项目配置要分类 封装不同环境的配置信息 用字典重定向 然后给app注册.
	5.3 抽取info到info包 
		info下的init文件是个初始化文件方便导包的 抽取的文件放进去以后导包直接forminfo文件夹就能达到目的.
	5.4 封装工厂函数 生产不同环境的app 以达到不同环境的app能调用不同的配置信息.
	5.5 在info下新建modules模块文件夹,再分类创建各种模块文件夹(新闻模块,排名模块,等等)然后抽取视图函数,封装蓝图,记得蓝图中盗图view模块.
	5.6 浏览器返回静态文件 比如静态logo 但是如果不关联文件路径的话 之前加载的缓存如果有错误,就算文件路径修复也不会加载.
	5.7 前段文件中有的功能还没实现会给一些特殊标记 叫TODO标记,标记让我们实现.
6,分析需求
	6.1 创建表还是字段根据需求名词提取. 并判断是功能还是表
	6.2 各种列表中的关键字.
	@审核通过不通过有原因 这个审核可以用关键字筛选.
	@用户表 里面包含 是不是管理员 是不是用户 是不是作者 !
	@数据迁移 导入models才能生成迁移脚本,才能执行迁移命令.
	
7,目录说明 .txt 
	根目录 
	名称		说明
	xxx      xxxxxxxxxxxxxxx
	xxx	   xxxxxxxxxxxxxxx
	可以树型对应 跟目录结构一样比较好查询.


DAY14

1,昨日漏点  modles复制过来的 需要导入才能执行数据迁移.

2,日子等级 记录该等级以上的信息 一下的不记录

3, 执行  导入logging 复制代码 等级为关键字段 并且创建logs文件夹 日子文件的大小
	不是限定的,可以定期整理.
	 
DAY 11.02
1,之前总结 
	复习js操作获取标签,操作标签,和ajax等
	
2,了解flask 视图 MVT  model view t?
运行flask程序时, 提示端口被占用

				@报错
				socket.error: [Errno 48] Address already in use
				解决
				查看占用5000端口的进程
				lsof -i:500
				关闭进程
				kill <pid>
				


3,web原理 客户端发送响应,服务器返回响应.
	总结(浏览器在地址栏里写上百度回车的分析
	1,浏览器自动补全http或者https的协议命令,
	2,浏览器访问dns服务器解析baidu映射的ip地址,给浏览器.
	3,浏览器向指定的ip地址发送请求报文.报文包括请求头,请求行,空行,请求体,还有请求协议请求方法等.
	4,服务器接受请求,并处理请求,判断请求内容,若为静态资源则直接返回,若为动态资源,则查询数据库,然后返回数据.
	5,服务器生成响应报文给客户端.)
	
	
	![nil](https://img-blog.csdnimg.cn/20181123230316900.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L211emhlMTAyNA==,size_16,color_FFFFFF,t_70)
	3.1 客户端:浏览器,app,代码,测试工具等  http 80 https 443 
	3.2 dns 域名解析服务器 世界上13台根域名解析服务器,大部分在美国.子级域名解析服务器. 返回ip地址
	3.3 浏览器以特定格式向ip地址发送报文请求  请求方法 /post/delete/put/get 增删改查四种方法.
	3.4 服务器接收请求,处理请求.六字箴言(写接口,调接口) 也叫api 函数 类 请求处理类等
			写接口:接收参数--检查参数--业务请求--返回数据  业务请求里包含查询数据去数据库里.
			调接口:调别人的接口 或者自己的接口.
	3.5 服务器生成响应报文返回给浏览器.(包括默认处理方式:静态资源  html css 等
											和动态处理方式:有请求参数的请求 ;查询字符串:url中?后面的以=传值,以&分割的信息.
		 响应状态码:
		   返回的状态码和状态不一致的情况是有可能发生得 
			比如Web应用程序内部错误,但仍然返回 

			200 OK 
			请求正常处理完毕
			204 No Content 
			请求成功处理,没有实体的主体返回
			206 Partial Content 
			GET范围请求已成功处理
			301 Moved Permanently 
			永久重定向,资源已永久分配新URI
			302 Found 
			临时重定向,资源已临时分配新URI
			303 See Other 
			临时重定向,期望使用GET定向获取
			304 Not Modified 
			发送的附带条件请求未满足
			307 Temporary Redirect 
			临时重定向,POST不会变成GET
			400 Bad Request 
			请求报文语法错误或参数错误
			401 Unauthorized 
			需要通过HTTP认证,或认证失败
			403 Forbidden 
			请求资源被拒绝
			404 Not Found 
			无法找到请求资源(服务器无理由拒绝)
			405  method not allowed
			请求方法不允许
			500 Internal Server Error 
			服务器故障或Web应用故障
			503 Service Unavailable 
			服务器超负载或停机维护
4, 框架介绍
	flask特点:轻巧简洁扩展  核心 werkzeug 和 jinja2  ???
	常用扩展包:
	wsgi 协议  
	@常识  奇数版本是开发版  偶数版一般是稳定版
	
5,mk创建进入虚拟环境	
	pip freeze > requirement.txt
	
	
6, hello world
	三点:
	
	6.1 视图函数不能重名.
	6.2 url可以重复
		因为http不同的请求方法为了不同的操作.
		@一个函数只有一个返回值  布尔类型的!
		debug=True ???
		@返回数据只能是浏览器认识的类型
		@不使用装饰器函数能实现路由映射.
		
7, 返回不符合协议默认状态的状态码,可以实现数据交互.

@app.route('/abc',methods=['POST','GET'])
def hello2018():
    # return 可以返回状态码,也可以返回不符合http协议的状态码,用来实现前后端的数据交互
    """
    前端发送ajax:
    $.ajax({
        url:'/abc',
        data:。。。, 发送到后端的数据
        contentType:'', 发送到后端的数据类型
        dataType:'json' 后端返回的数据类型
        success:function(resp){
            if (resp == '666'){
                alert(errmsg)
            }else{

            }

        }
    })

    errno=666,errmsg='用户名已注册'
    return:()


8, 加载配置文件的三种形式:
	8.1 外链 从外部py中导入
	8.2 ini文件
	8.3 envvar('外部环境变量的设置文件')
	
	from flask import Flask
# 导入配置类
# from config import Config
from config import config_dict
app = Flask(__name__)
# 加载配置文件:三种实现形式
# 1、加载配置对象,config是flask内置的配置对象
# 重点掌握:因为扩展性更强
# app.config.from_object(Config)
# app.config.from_object(config_dict['pro'])
# 2、加载配置文件
# app.config.from_pyfile('config.ini')
# 3、加载环境变量
# app.config.from_envvar('SET')


@app.route('/')
def index():
    return 'hello world'

if __name__ == '__main__':
    app.run()
	
9, 9.1 重定向 redirect(url) 项目地址变化的需求  需要导入方法
	9.2 url_for  跟视图函数名  这样少该地址.  反向解析  和url_map相对.
	
	from flask import Flask,redirect,url_for

app = Flask(__name__)
# 重定向redirect 接受参数为location,具体的url地址
# 重新发送网络请求,跳转页面
#项目路径url或文件发生变化的情况下需要重定向
@app.route('/')
def index():
    url = 'https://www.baidu.com/'
    return redirect(url)

# @app.route('/for')
#
# # url_for 反向解析,接受参数endpoint 视图函数名
def re_url_for(jisis):
    return redirect(url_for('index'))

if __name__ == '__main__':
    print(app.url_map)
    app.run()
# 重定向如果是定向给新的地址,那原来的地址要不可用,吗
# 其实如果比如在不同页面点击链接都会跳转到制定网址也比较形象.
# 或者,比如原地址是127.0.0.1:5000, 因为不能用了 或者不想让展示,就直接加一个重定向,让
# 他定向到想展示的地址.那怎么实现好多方法都定向到同一地址?

                                                                                   

 今日总结;
1,浏览器工作流程
2,什么是框架
3,什么是重定向


DAY 11.05

1,昨日总结 after_request   如果没有抛出错误,在每次请求后执行  有异常不会执行 异常是指服务器内部异常.
	127.0.0.1 - - [05/Nov/2018 09:00:27] "GET / HTTP/1.1" 200 -
	before request run---
	after request run---
	teardown request run---

2,上下文  语义环境  比如:
	包含请求上下文:request 和 session
	和应用上下文:current_app  和g
	
3,get请求和post请求的区别
	3.1 get请求没有请求体,
	3.1 并且url地址栏参数有长度限制.不超过2kb(浏览器限制的)
	提交form文件
	    <form action="http://127.0.0.1:5000/form" method="POST" enctype="multipart/form-data">

     <!-- 写的代码在提交包含文件类型的提交时必须进行编码处理 因为图片和文字肯定不是一个类型,他会默认 接受
    文字,加的属性为 enctype = 'multipart/form-data' -->
    <label for="">name</label><input type="text" name="name" id="">
    <label for="">password</label><input type="password" name="password" id="" >
    <input type="file" name="image">
    <input type="submit" name="提交" value="提交">
    <!-- <input type="reset" name="重置" > -->
4,request.form.get()
	from flask import Flask,request,current_app,sessions,g


app = Flask(__name__)

"""
请求上下文,request和session
request是flask的内置的请求上下文
request`的常用属性是 args from method url headers cookie  file 等

args查询的是字符串 url地址栏中 ?后面的以= 传值 &分割 

"""

# request的资本用法 args
@app.route('/')
def index():
    """ 1 获取get查询的字符参数"""
    name = request.args.get('name')
    age = request.args.get('age')
    print (name,age)
    # "zhangshan" "12"
    # s输出url的地址
    # print(request.url)
    # http://127.0.0.1:5000/?name="zhangshan"&age="12"
    # 输出请求方法
    # print(request.method)
    # print("------1-------")
    # print(request.headers)
    # print("------2-------")
    #
    # print(request.cookies)
    #
    # print("-----3--------")
    # !!总结 request方法可以在后端查看前端访问携带的信息, 可以做什么?


    return 'hello world'


#form表单请求 默认post
# @app.route('/form/',methods=['GET','POST'])
# def demo_form():
# #     获取表单参数
#     abc = request.form.get('abc')
#     name = request.form.get('name')
#     print(abc)
#
#     print(name)
#
#     # 总结  get方法也可以 方式调试不成功
#
#     return "demo form"

@app.route('/form',methods=['POST'])
def rec_files():
    image = request.files.get('value')
    image.save('./shabi.jpg')
    return 'save success'
if __name__ == '__main__':
    app.run(debug=True)
    print(app.url_map)


5,postman 可以模拟前段页面里的请求,来测试后端的交互.  用来试一下提交form表单的文件.
	记得post形式在body里加参数
	get在header里加参数

6,from flask_script import Manager  脚本管理器.
	manager.run(ip端口) 方法启动程序.可以在终端启动项目时,手动制定ip和服务.
	具体方法为在terminal打开,python方法运行,然后-p然后改端口.
	感觉没几把用


7, 模板. 目前是一种包含响应文本---html格式的文件  是前后端分离的一种工作方式.
	为了拆分出来专门交互的那部分工作.分担了视图的渲染数据的部分功能.
	
	建立模板文件夹记得mark成template
	
	
	
8,给模板传参数是字典形式. 使用时{{ 变量参数 }}
	<hr> 分割线标签
	loop.index  输出索引 从1 开始
	loop.index0 输出索引从0开始输出索引   他们用来判断循环次数.
	loop.cycle 给输出添加前缀  ??可以重命名
	
	返回值中 对应变量名书写形式为
	return render_template('index.html',data=data,my_list=my_list,my_dict=my_dict,data_list=data_list)

	
9,过滤器 filter 
	{{ 字符串 | 过滤器 | 过滤器2}} 链式调用过滤输出
	reverse 翻转 
	upper 大写
	lower 小写
	safe 渲染输出  默认不渲染输出也可以记为原始输出
	capitalize  第一个大写
	tittle  每个单词大写
	
10,CSRF cross-site request forgery  请求伪造
	用户A用浏览器向网站b发起正当请求,网站b返回请求,并给A注入cookie信息,此时或者在cookie到期之前A浏览器打开了c网站,c网站得到了	A的信息后发起了新的向b
	的新请求,然后客户A点开了 b,b网站验证了cookie信息允许进入,就实现了c通过a访问b,
	


DAY 11.06
1, 昨日总结 
	模板语法必须调用template语法才能执行 
	{{ 变量 }}
	{% endfor %}
	{% endif %}
	
2, csrf 借刀杀人 僚机 
	为什么会准确实现csrf攻击,恶意网站伪造好请求后,在路口等用户访问正常网站.就是守株待兔.
	也可以钓鱼去广阔流量中播撒恶意代码. 
	
3,过滤器 filter 
	3.1 列表处理 
	@字符串翻转原理  遍历输出列表再用索引取值方式重新排序. c语言中的原理描述就是以中间为
	轴对称调换指针位置.
	
	3.2 自定义过滤器
	<!DOCUTYPE = HTML>
	<html lang = "en">
	<head>
		<meta charset="UTF-8">
		<title>Title</title>
	</head>
	<body>
	</body>
	</html>
	!!自定义过滤器的方法  1 添加自定义函数 app.add_template_filter(do_listreverse,'lireverse')
	`````	2 装饰器函数 
	@app.template_filter('lireverse')
def do_listreverse(li):
    # 通过原列表创建一个新列表
    temp_li = list(li)
    # 将新列表进行返转
    temp_li.reverse()
    return temp_li
    
    !!!!!!
    @app.template_filter("dic_sortBV")
# 强转list
def dict_val_sort(key):
    temp_dict = list(key)
    # temp_dictval = list(value)
    print(temp_dict)
    # print(temp_dictval)
    temp_dict.reverse()
    return temp_dict
# 封装一个函数可以对字典进行排序或者翻转  ,只能达到这样子['name', 'age', 'hob']
4,模板复用
	4.1 宏的应用  macro 相当于def
	@前段页面的value全是为了实现交互的
	placeholder 提示信息!!!!傻逼没教
	{% macro fun() %}
	{% endmacro %}
	#调用
	{{ fun() }}
	也可以传参复用
	
	也可以封装自定义宏 以在其他文件中导入.import
	
	{% import '模板页面名' as newfu%}
	调用 newfu.()
	@注 宏常封装的是动态可复用的代码块 也就是格式相同参数不同的块.


{#宏的使用相当于模板中的函数,类似与python中的def
宏的作用实现模板页面的复用,一般封装的是局部可变的页面代码块#}
{#比如登录代码块#}
<input type="text" name="user" placeholder="user"><br>
<input type="text" name="password" placeholder="password"><br>
<input type="submit" name="提交" id="#">

{#定义宏#}
<hr>

{% macro fun() %}

<input  type="text" name="user" placeholder="user"><br>
<input type="text" name="password" placeholder="password"><br>
<input type="submit" name="#" id="#">

{% endmacro %}
{{ fun() }}
{#定义带参数宏#}
<hr>
{#{{ fun(type='muzhe',name='shabi',placeholder='hhhahha') }}???#}
{#不能这么用吗??#}
<hr>
{% import 'temp_macro.html' as f%}
{{ f.fun(type="muzhe",size=100) }}
</body>
</html>
{#为什么不显示前面的名字?aria-label="shahah"#}


5,模板继承(也是为了复用)  关键字 block
	格式:
	继承:extends '父类.html'  如果想用自己的样式 直接覆盖 要声明类block
	继承之后的子页面只能写在block内.其他额不会显示
	总结:
		多个页面中具有相同的顶部,底部,或者部分中间内容,可以使用继承. 
		包含或者部分的才需要使用,多个页面中重复的内用可以不用封装,
		多个页面中特有的内容才需要封装,让之类复用.
		灵活应用.
	@@模板不支持多继承!!!
	@@extends语句任何位置都行,但是建议写在第一行,可读性.
	@@父类和自己都使用要super调用
	@@在extends语句上面的语句也会生效,但是不会继承父类的样式.
	from flask import Flask,render_template
app = Flask(__name__)

@app.route('/')
def index():
    return render_template('3block.html')
    # return render_template('temp_macro.html')

"""
模板的继承
要点 模板中具有向东的顶部底部或者中间部分 可以使用继承
    2 多个页面中的重复内容留下不动?????????????    
    3 多个页面中特有内用封装成block 让子类重写 
    4 灵活   
    备注  模板不支持多继承
    extends语句建议写在第一行
    如果有想要自己实现的内用可以写在extends语句前面
    也想要父类内容也想要自定义内容可以用用super调用
    
"""
if __name__ == '__main__':
    app.run(debug=True)
# 总结 代码块的信息 是任意html格式的信息,
# 问题 号线没啥用啊super?
# 还有为啥我的extends没啥用啊
	
	
6,包含 跟继承不一样就是把包含的完整复用 可以用来复用完整的代码文件.  通常是已有内容后
		的增加内容  一般会加ignore missing的参数防止不存在.
		
	
# 总结 include包含的?代码块需要是一个html的文件名 或者一个文件名的list
# list怎么用不太知道????????????但是我的用法是在包含的文件名中包含文件名列表.可能也是办法	
  return render_template('demo4_include.html')	
{% include 'demo1_filters.html'  %}
{% include 'demo1_filters.html'  %}
{% include 'demo1_filters.html'  %}
{% include 'demo1_filters.html'  %}


		
7,总结@@@@@ 使用复用的方法  四个字  灵活应用 

8,特有变量函数  就是在很多地方使用并且意义和使用方法一样  一般需要导入后才能用.
  get_flashed_messages()  失去焦点后提示信息. 如果有编码错误 重启浏览器
  
9,WTFfroms表单 
	字段
	验证函数 anyof 在可选值之内
			  noneof 在可选值之外
			  
10,表单类 用来验证提交信息

验证器 token  生效需要通过调用函数. 他不仅验证请求参数是否形同
	还会验证表单验证中是否有token
	ipython
	import os base64
	然后...
	....
	
@ @@@注册 和 登录按钮 按道理说都是提交功能.

获取数据 form.get.('name')
	另一种form.user.data 
	然后打印
	
11, sql 关系型数据库    和   非关系型数据库.
	例子  微博用户的相互关注   自关联的多对多
			省区号    自关联1对多.
			
	三范式 1 原子性  每个字段不能拆分
			2 满足之前 且满足有主键约束
			3 满足之前俩 且满足非主键字段相互不能关联.

12, Alchemy  炼金术  抽象  
	orm 对象 关系 映射 
	sqlAlchemy 是orm 的框架
	flask_sqlAlchemy shi sqlAlchemy的封装
	
	
13,
mapping 解释一下:

DAY 11.08
![在这里插入图片描述](https://img-blog.csdnimg.cn/2018112323043076.png)
1,secret key 不是token的值 是根据token调用的.

2,一个进程包含多个线程 就是一对多 
3,开关和灯泡 一对多 或者双控就是多对多.
4,自关联 要包含一张对应关系的抽象表 这个表能查出两边的关系.

5,URI

6,默认端口 3306数据库  mogoudb 27017 

7,关键字 echo 打印sql语句.

8,定义模型类 
	8.1 链接数据库 app.config[]=
	8.2 dengdeng
	@

9, 创建数据库..

10, 等值过滤器 赋值 过滤器 就是以个等号?????????? 就是指定必须是谁来过滤,能加多个条件吗.

11, update()  修改,但是要想生效,要提交.
DAY 11.10
1,今天结婚3年了.

2,昨日总结,在ipython中测试数据库操作,在当前文件夹打开terminal,运行ipython,再import
	导入文件中所有的东西,然后就能用测试语句查询.
3,url_prefix = '' 在url地址里设置前缀,用于可以通过url实现直观了解访问类的作用.

4,使用蓝图  --创建对象 --调用路由 --程序中注册
	拆分文件使用蓝图 注意就是将第二个文件中的路由拆分出去 并导回第二个文件中,注意导入到创建的蓝图之下.
5,单元测试独立的功能模块运行是否正常,代表 postman
	用代码测试代码. 比如判断函数是否是斐波那契数列  就是用一个递归函数来测试一个数符不符合规则.
	
6,@写项目过程  静态页面--需求--功能分析--MVT(模型:定义模型,视图:实现逻辑,模板:实现展示)--遇山开山,遇水架桥.
	@具体实现步骤:1,实现基本功能(测试)
					
					2,扩展功能(测试)
					
7,wtf 验证
	删除数据, 要先查出来,有数据再删
	
8,测试
	1,导包
	2,定义测试类 三个函数 setup
	 		teardown
	 		test_add_data
	
	代码:
	from flask import Flask, render_template, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired

"""
 案例分析 

 案例作者和图书
 MVT: 
 m_model:定义模型  实现数据库表 存储数据 存储作者和书籍 然后配置数据库链接
 v_views: 实现业务逻辑,实现增删改查,并且实现增删改查之后的重定向局部刷新.
 T_template :实现数据展示,使用模板语法,加载数据渲染数据


 步骤:
 1 实现简单功能  
 2 定义模型类 实现数据表
 3 使用模板渲染数据 视图函数的数据传给模板
 
 4基本功能实现 扩展
  --添加表单 实现数据的增删改查
  在视图函数中实现逻辑操作  这些东西是方法 def的东西 不是类类是用来渲染的
 
 
 异常处理
 1 调用第三方接口
 2 参数处理
"""
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@localhost/authorbook'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 设置秘钥
app.config['SECRET_KEY'] = 'SDA2983SADdsalsa239saiidasfdsIJI'
app.config['SQLALCHEMY_ECHO'] = True
# 实例化sqlalchemy对象
db = SQLAlchemy(app)


class Author(db.Model):
    __tablename__ = 'authors'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32), unique=True)

    def __repr__(self):
        return 'author:%s' % self.name


class Book(db.Model):
    __tablename__ = 'books'
    id = db.Column(db.Integer, primary_key=True)
    info = db.Column(db.String(32), unique=True)

    def __repr__(self):
        return 'book:%s' % self.info


class Form(FlaskForm):
    wtf_author = StringField(validators=[DataRequired()])
    wtf_book = StringField(validators=[DataRequired()])
    wtf_submit = SubmitField('添加')


@app.route('/', methods=['GET', 'POST'])
def index():
    # 渲染所有数据
    # authors = Author.query.all()
    # books = Book.query.all()

    # 这是处理异常
    # authors, books = None, None # (????)

    # 实例化表单对象
    form = Form()
    if form.validate_on_submit():
        wtf_au = form.wtf_author.data
        wtf_bk = form.wtf_book.data
        #     把作者和书籍添加到数据库 数据必须通过模型类对象添加
        #
        auth = Author(name=wtf_au)
        book = Book(info=wtf_bk)
        try:
            db.session.add_all([auth, book])
            db.session.commit()
        except Exception as E:
            print(E)
            # 如果真有异常 要回滚
            db.session.rollback()
            # 添加数据库后数据库更新但是模板不更新,需要刷新,同步刷新,可以再次查询.
            try:
                authors = Author.query.all()
                book = Book.query.all()
            except Exception as E:
                print(E)

    try:
        authors = Author.query.all()
        books = Book.query.all()
    except Exception as E:
        print(E)

    return render_template('author_book.html', authors=authors, books=books,
                           form=form)  # , form=form, authors=authors, books=books


# 实现删除书籍功能
@app.route('/del_auth<int:id>')
def del_author(id):
    auth = Author.query.get(id)
    try:
        db.session.delete(auth)
        db.session.commit()
    except Exception as E:
        print(E)
        db.session.rollback()
    return redirect(url_for('index'))


@app.route('/del_book<int:id>')
def del_book(id):
    book = Book.query.filter_by(id=id).first()
    db.session.delete(book)
    db.session.commit()
    return redirect(url_for('index'))


if __name__ == '__main__':
    db.drop_all()
    db.create_all()
    au_ka = Author(name='卡尔.荣格')
    au_so = Author(name='亨利·戴维·梭罗')
    au_jo = Author(name='乔治.马丁')
    # 提交会话
    db.session.add_all([au_ka, au_so, au_jo])
    db.session.commit()

    bk_ka = Book(info='荣格自传')
    bk_so = Book(info='凡尔登湖')
    bk_jo = Book(info='GOT')
    # 提交回话
    db.session.add_all([bk_ka, bk_so, bk_jo])
    # 没有外键约束的话 添加的顺序与添加方式都可以无序.若有id限制则不可以
    db.session.commit()
    app.run(debug=True)

	
	
	
	
9,	Redis 数据库.
	nosql 非关系型数据库 只有key 和 对应的value
	适用于关系不复杂的项目.
	开源的使用ansi c语言编写  基于内存存储 以keyvalue实现的 nosql数据库.
	
	应用体现 新浪微博  session共享????、购物车 需要并发量很大的数据需求

	丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。

	
10,redis 数据操作
	增删改查  字符串 哈希hash 列表list 集合set 有序集合zset
	list
	set
	zset
	string
	hash
	
11, 个人习惯 redis-server –help 查看帮助文旦
	ps aux | grep redis 查看redis的服务器进程
	sudo kill -9 pid 杀死进程
	sudo redis-server / etc /redis /redis.conf  制定加载的配置文件.
	Redis -cli 启动客户端
	数据库没有名称 默认16个 从0开始 切换用select 10















	






12.. 上图看出 redis的数据结构都是字典形式的.
Key 的类型是字符串
key不能重复.
值有5种  string 
hash 
list
set
zset 有序set集合
对应五中数据类型 的增删改查

例如string  

12 增

set key value   ----get key
@setex  key 99 value 中间加时间 表示过期时间

@单独设置过期事件 expire key1 999  设置key1 过期时间为999.

@查看有效期 ttl key 查看key的过期时间 默认不过期 返回值为-1  已经过期的返回-2 
 


设置多个key和valuemset  a 28 b 28 c 28  -----mget  a b c  获取多个值

追加值 append a 12 相当于向字符串后面添加字符 ‘2812’


13.  查  支持正则表达式
查找key
keys * 查找所有key

keys ‘a*’ 查找含有字母a的key

exists key1  查找值是否存在key1 不存在返回0

16  删除
del  key1  删除key1 对应的值



17 , hash 
增 
hset user name  muzhe  增加user的属性name为muzhe
查
hkeys key 由key获取key的属性名 1) "name   2) "age"
hget key field  由上面查到的key的属性名来获取属性值
	hget user name
"muzhe"

同样获取多个属性的值 
hmget key field1 field2 

一次获取多个属性的属性值
hvals key


 删
删除整个hash 用del 加key
删除局部属性 要删除对应的属性名 hdel key field 

![在这里插入图片描述](https://img-blog.csdnimg.cn/20181123230455249.png)


17list
增
由左侧添加list
lpush key value1 value2..
rpush key val1 val2
展示列表 lrange key  start stop 名字和第几个值开始第几个值结束,

例4:获取键为'a1'的列表所有元素
lrange a1 0 -1
根据索引设置元素value
lset key index value


18 set 
 增 sadd key menmber1 menber2
查  smembers key
删 srem key member1  
del key  删除整个key


19 zset 有序set集合
序列靠权重实现 没有索引 不能修改
增
zadd  t2 1 zhangsan 2 lisi  3 wanbu 添加权重和元素
查
zrange t2 0 -1  从第0个开始都最后一个

返回score值在min和max之间的成员
      zrangebyscore key min max
    • 例3:获取键'a4'的集合中权限值在5和6之间的成员
      zrangebyscore a4 5 6
获取成员的权重
zscore key member
删
 	删除成员 zrem key member1
	zremrangebyscore key min max  按权重删除多个元素


总结string
    • set
    • setex
    • mset
    • append
    • get
    • mget
    • key
keys
    • exists
    • type
    • delete
    • expire
    • getrange
    • ttl
hash
    • hset
    • hmset
    • hkeys
    • hget
    • hmget
    • hvals
    • hdel
list
    • lpush
    • rpush
    • linsert
    • lrange
    • lset
    • lrem
set
    • sadd
    • smembers
    • srem
zset
    • zadd
    • zrange
    • zrangebyscore
    • zscore
    • zrem
    • zremrangebyscore

20, 主从配置 
	1 主服务器配置文件  sudo vim redis.conf
						bind 192.168.131.20
	2 重启服务
	3 从服务器 复制主服务器的conf文件改名为slave.conf
	4 修改从服务器配置文件 sudo vi slave.conf
	5 修改内容为 bind ip        192.168.131.20 和主服务器一样的原因是只有一台电脑 多台电脑则不同.
6 关键 slaveof 192.168.131.20 6379
port 6378       
应用配置文件  sudo redis-server slave.conf

7 查看主从关系  redis-cli -h 192.168.131.20 info  Replication

8 进入主从的命令分别为 redis-cli -h 192.168.131.20 -p 端口号

21, 主从服务器的数据操作类似,但是一般在主服务器上写 在从服务器上读

@Redis被配置为保存数据库快照,但它目前不能持久化到硬盘。用来修改集合数据的命令不能用
原因:
    • 强制关闭Redis快照导致不能持久化。 解决方案:
    • 运行config set stop-writes-on-bgsave-error no 命令后,关闭配置项stop-writes-on-bgsave-error解决该问题。

22,配置集群.
多台电脑组成的redis服务群  
主要命令 
1,
sudo cp /usr/share/doc/redis-tools/examples/redis-trib.rb /usr/local/bin/
2,
sudo sudo apt-get install ruby
3,创建集群 每台电脑
redis-trib.rb create --replicas 1 172.16.179.130:7000 172.16.179.130:7001 172.16.179.130:7002 172.16.179.131:7003 172.16.179.131:7004 172.16.179.131:7005

4,如果更新不成功为防火墙原因
-- 先查看⾃⼰的 gem 源是什么地址
gem source -l -- 如果是https://rubygems.org/ 就需要更换
-- 更换指令为
gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/
-- 通过 gem 安装 redis 的相关依赖
sudo gem install redis
-- 然后重新执⾏指令
redis-trib.rb create --replicas 1 172.16.179.130:7000 172.16.179.130:7001 172.16.179.130:7002 172.16.179.131:7003 172.16.179.131:7004 172.16.179.131:7005

5,出了yes 说明成功
6 ,链接集群 redis-cli -h 172.16.179.131 -c -p 7002

7 注意 必须存在3个以上的主节点才能建立集群.
DAY 11.12
1,昨日总结 适应团队 合作开发
  @复习数据库迁移
2,GIT 分布式版本管理系统  
	理念 多人操作一个文件 怎么合并版本.按照对比谁的版本比较先进来解决以谁为准.
	
3,入职基本工作 熟悉业务

4, git init   999,初始化后的文件都是隐藏的需要现实的话??
	git status
	git add 
	git commit -am  连添加追踪带提交描述  
	git log   git reflog    版本历史
	git reset --hard HEAD^   git reset --hard 版本号   @游戏存档 只能回滚 回滚以后不能前滚
	git reset HEAD <文件> 取消暂存区的修改
	@git checkout <文件> 重置工作区代码   这个和ctrl + z 还是有区别的  试一试就知道ctrlz的撤销范围很小 checkout的范围是上一次提交版本以后的所有代码,可以理解为没有add追踪的所有代码.
	@ git checkout <文件>的另一种用法  就是在工作区修改代码后已经add了并未commit,
	可以先git reset HEAD	 文件名 将add撤回到缓存区,再撤销掉工作区的代码
	
	  # 删除文件
	  rm 文件名
	  # git确定删除文件,对比添加文件git add 
	  git rm 文件名
	  # 删除后记录删除操作版本
	  git commit -m '删除描述'
	  @由上可知,删除操作也分为在工作区操作还是在仓库操作.
	  
	git checkout -- 文件名 撤销误删/  总结 撤销删除在提交删除之前操作的 如果已经git确认 那也没办法回撤.
	
	4.2 网络交互远程操作仓库
	经理工作:
	克隆远程仓库信息,配置自己身份信息,立项,push到库.
	push需要密码记录密码命令:
	git config --global credential.helper cache 
	永久记住密码是 git config --global credentail.helper store
	git push  提交项目文件 有可能要配置提交者信息
	git pull  协作提交有可能代码冲突,会返回错误,需要自己拉下来对比一下.决定后再提交
	
5, push时机,也就是保存时机 是个习惯.  局部功能实现push一下.
	经常pull 经常push.
	
6, 标签记录版本号   git tag 标签名 -m '标签描述'
				提交命令 git push origin 标签名
	这个操作好像是tag 相当于打包一下或者提纲一下 然后直接推送到仓库 仓库就会将本标签的内容分类展示.
	
7,分支  也是撤回的一种形式吧.	
	分支就是 区分开发与生产环境的代码.  其实也是tag的一种 是一个分出来的一个记忆点.起源.
	git branch查看分支  (git checkout -b dev)
	合并分支 切换到主分支上 然后git merge 分支名   
	 mayun  在终端git init 初始化 
	 然后在vsc里打开
	 
8,gitee支持有点问题 回来看一下


DAY 11.13

1, 昨日总结 记得暂存区撤销
2,项目目标
	2.1 web应用开发基本流程 4步
	2.2 web应用常见更能实现步骤
	2.3 git 使用
	2.4 源代码阅读 bug调试 工具使用  !!!!重点
	2.5 Diango 项目基础
	
3,前后端不分离 数据直接给浏览器 叫分离  比如直接写网页不用flask的
	模板渲染的 使用框架的 是项目前后端不分离  就是需要后端支持的

4, 项目分析
	4.1 技术实现  分析框架基础 数据库支持 三方扩展 部署系统要求
	
5, 框架搭建   基本的在一个文件中写 再拆出去.
	5.1 项目管理器
	5.2 项目配置信息  之后抽取出去
		项目配置要分类 封装不同环境的配置信息 用字典重定向 然后给app注册.
	5.3 抽取info到info包 
		info下的init文件是个初始化文件方便导包的 抽取的文件放进去以后导包直接forminfo文件夹就能达到目的.
	5.4 封装工厂函数 生产不同环境的app 以达到不同环境的app能调用不同的配置信息.
	5.5 在info下新建modules模块文件夹,再分类创建各种模块文件夹(新闻模块,排名模块,等等)然后抽取视图函数,封装蓝图,记得蓝图中盗图view模块.
	5.6 浏览器返回静态文件 比如静态logo 但是如果不关联文件路径的话 之前加载的缓存如果有错误,就算文件路径修复也不会加载.
	5.7 前段文件中有的功能还没实现会给一些特殊标记 叫TODO标记,标记让我们实现.
6,分析需求
	6.1 创建表还是字段根据需求名词提取. 并判断是功能还是表
	6.2 各种列表中的关键字.
	@审核通过不通过有原因 这个审核可以用关键字筛选.
	@用户表 里面包含 是不是管理员 是不是用户 是不是作者 !
	@数据迁移 导入models才能生成迁移脚本,才能执行迁移命令.
	
7,目录说明 .txt 
	根目录 
	名称		说明
	xxx      xxxxxxxxxxxxxxx
	xxx	   xxxxxxxxxxxxxxx
	可以树型对应 跟目录结构一样比较好查询.


DAY14

1,昨日漏点  modles复制过来的 需要导入才能执行数据迁移.

2,日子等级 记录该等级以上的信息 一下的不记录

3, 执行  导入logging 复制代码 等级为关键字段 并且创建logs文件夹 日子文件的大小
	不是限定的,可以定期整理.
	 
4, 图片验证码  根据uuid也是就是图片验证码的id  需要前端生成 因为客户通过浏览器访问前端然后来访问服务器,直接在前端验证有没有uuid来对比是否生成验证码. 后端验证的是是否有uuid  

5,操作标签属性???

6,PIL 包  画图包

7, 图片验证码 两大类 图片测试  语义区分  (图灵测试)

8,返回图片  make_response 

9,有官方SDK的放在libs中

10,发送短信,检查参数时 每个参数都必须检查,并且 在比较获取的图片验证码时,必须删除,应为只能用一次.
11,接收参数 检查参数 业务处理 返回结果
12, 检查参数 if not all([mobile,image_code,image_code_id])
13,比较图片验证码是否正确.如果发送的验证码 不能与抽取的验证码匹配返回信息
注意忽略大小写,都大写 或者都小写.
14,随机6位数验证码  '%06d' % random.randint(0,999999)

15,添加项目依赖环境文件.  在黑窗口pip freeze>requirement.txt

16,解决问题 4开头看前端
			5 开头 看后端
			没问题看下浏览器	87一天2


DAY 16
11.16
1,昨日露点 
2,@理解 视图函数 是def下绑定的哪个函数,app后面的'/'就是视图.route是把函数绑定给视图.
3,  @给视图传参/<参数>就是让函数调用视图的参数参数,以达到让浏览器返回用户自己的参数并让服务器接受用户参数的效果.  但是传递的参数会被编译 ,所以要过滤.
4,  @内置过滤器有6种,默认是字符串string,还有两种数值型的:int ,float,另外三种叫any,path,uuid.

-----------------------------------------

5,今日笔记
	接口文档 接口设计 
	.URL:/接口 路由
	.methods: post
	.dataType:json
	
	参数名 类型 是否必须 参数说明 
	如果前后端交互不了,看接口文档,谁写的有问题,谁负责.
	如果接口文档有问题,改接口文档.
	接口文档是按照项目需求文档设计的.
	
	
6,检查参数 的一般思想   写入日志的信息
	6.1 uuid或者手机号
	6.2 检查uuid或者手机号格式
	6.3 格式错误终止  终止前保存日志
	@	是否注册 保存是否注册 返回终止信息.
	6.4 格式正确 读取数据库对比带来的参数
	6.5 一次性的的数据信息删除 写入日志
	6.6 返回或者存储  
	6.7 前端返回提示.
	@	是否注册过手机号 这里提示会泄露信息.
	
	曾经有个人告诫我,你怎样走能少走弯路,我没有在意,直到我现在在弯路上才后悔莫及,如果老天再给我一个机会让我重来一次的话,我一定会洗耳恭听.如果能给从来指定一个日期的话,我希望是有记忆的那一天.
	
7,前端实现思路  
	7.1 var得参数
	7.2 ajax发送请求
		{()}
8, 缓存用户昵称等可变信息到redis中的话, 有可能出现问题是在农业面中信息是过期信息类似于修改后的真正信息在页面中不显示,好像就是改不了的昵称. 也就是 要保证redis数据库和mysql数据库中的数据保持一致.
	@缓存数据和mysql数据库 的作用要分清
	@问题,缓存数据和数据库数据不一致的解决方法.  以什么为准,要以数据库为准.缓存信息的字段要以为数据库为准.
	@问题,为了避免缓存过期,怎么办  业务逻辑改成缓存显示后就过期.然后以mysql为准.
	
9,检查用户登录状态:显示是否登录
	9.1 思路接收参数--检查参数--业务逻辑--返回参数
	9.2 使用会话 也就是状态保持.
	@user = none??????
	
10,退出实现. 清除缓存
11, 三元表达式 
	a?c : b 判断是不是a 是就执行c 不是就执行b
	报黄  ????????????
12, 完善csrfPortect 设置csrf_token,让after_request(response)带走,因为每次请求都会执行after_request.  
	return response
	
	在ajax值里面添加请求头信息,header:{
		x-csrftoken:get(cookie),
	},


DAY 11.18
「print(''牧哲: Wpy℡15035135008''):唯一知道的事情就是自己一无所知。

1,昨日总结 
递归调用有可能造成栈溢出 ,可以在需要递归的地方单独调用,比如昨天的溢出,不让全部调用,每行单独调用。
2,点击排行实现
查询点击量 按点击量排行。
@实现不同的样式 用过滤器 写在工具文件中 是个过滤工具
在初始化文件中导入过滤器。
@这里可以写三行样式代码然后再写循环。
3,新闻分类展示
首页展示 查询数据库 查询新闻分类然后遍历结果,
最新新闻实现方法
过滤器查询所有的新闻中按时间排序
然后分页
@分页 paginate
@代码示例 给别人看懂的代码块 
@注意转换数据类型要进行异常处理。
  另外两种需要处理异常的情况:
@找错误 print()
   alert()
   return的地方插入断点。
.each  前端遍历命令

@页面加载原理 默认是不加载 等加载完一页再加载新的一页  可以防止暴力刷新。

4,新闻详情展示实现
转换器返回用户请求的数据。
@登陆 和首页展示的部分 不是固定的盒子吗,为什么切换其他的新闻详情页面还要手动展示?不是局部刷新吗?
@g对象。
@函数名.__name__ 就是函数的的名字
fun.__name__ 返回的就是fun  实现这个效果的标准模块  functools

5,实现收藏列表
默认收藏 判断用户是否取消

6,模板继承」
—————————
urlfor查询的是?后面的数据
proxy代理

DAY 11.19
1,基本资料实现
2,接口怎么写。
@new_blue.rout()
 获取参数  就是有没有参数值
检查参数就是对比参数是否存在
根据参数的值查询对应的新闻是否存在
将评论信息保存在数据库
提交数据
返回结果
@判断用户是否登陆
获取  就是查询
检查就是 ifnotall
转换类型 news-id = int(news-id)
判断手否有父评论id
vue
评论是模板渲染的  需要周四新闻详情中留评论信息才能实现静态展示。
@如果有评论显示评论 没有评论 不展示
实现方式 遍历评论内容
 
3 登陆界面
iframe  前端页面嵌套
iframe是个标签
判断是否登陆 登陆了进个人中心 没登陆重定向到登陆页面
中心显示的是数据  通过查询展示
@快速导入如果不是包有可能自动创建bug
@对比数据去重 编码后对比数据 节省原二进制对比。
4,图片上传
@,后端获取文件 request.files
4.1判断用户登陆 如果登陆判断请求方法,使用模板渲染数据
4.2如果不是get请求,获取参数,获取文件对象,文件对象是要有读写方法的对象
4.3  读取图片
4.4 用云存储数据
4.5 在mysql中存储图片截连接
4.6 返回给前端。
4.7  本地数据库存储文件应该存行对地址,应为引用的常量已经保存了常量的绝对的地址,绝对地址是空间地址,有可能会改变,这个常量如果改变,可以维护,存贮绝对的地址的话就不好维护。(????)
@难道云返回的图片名称是地址吗,也就hi说可以在青牛里直接搜名称就出来了吗?
@一个浏览器一般不允许多、开!!???

5. 发布新闻
发布新闻接口。。

这部分是表单提交 表单不是和后台已经连接了吗,怎么写怎么提交,还用判断吗?
5.1 新闻发布获取参数
title = requst.form.get(titlie)
@存储新闻图片存储一个绝对路径,因为新闻图片一般来说对新闻很重要,如果不存在新闻图片就不展示新闻,?????答 看情况,不一定
5.2 提交数据 db存储在数据库 


6,管理员页面
在manage文件中添加代码完成管理员添加。
函数不是必须返回数据吗?

7,后台客户统计
@模拟用户添加。
timedelta  时间随机数
@手动开启上下文,才能和manager关联。
@添加密码固定数据,。iambic一样的。
8,项目部署
硬件 和 软件 
电脑系统 
操作系统,flask自带的服务器用来调试。不能用于生产。
@epoll linux操作系统的内核。
@项目的并发量,几百上千最多。
@nginx 反向代理服务器。转发用户服务请求,对不同服务器进行分配。
达到请求转发和负载均衡的目的。
@反向代理就是客户端不知道具体访问服务器是哪台。
@正向代理,就是通过代理不让服务器知道客户是谁。
@所以,有可能一次请求有可能同时存在正向代理 和 反向代理。」
—————————
4, 图片验证码  根据uuid也是就是图片验证码的id  需要前端生成 因为客户通过浏览器访问前端然后来访问服务器,直接在前端验证有没有uuid来对比是否生成验证码. 后端验证的是是否有uuid  

5,操作标签属性???

6,PIL 包  画图包

7, 图片验证码 两大类 图片测试  语义区分  (图灵测试)

8,返回图片  make_response 

9,有官方SDK的放在libs中

10,发送短信,检查参数时 每个参数都必须检查,并且 在比较获取的图片验证码时,必须删除,应为只能用一次.
11,接收参数 检查参数 业务处理 返回结果
12, 检查参数 if not all([mobile,image_code,image_code_id])
13,比较图片验证码是否正确.如果发送的验证码 不能与抽取的验证码匹配返回信息
注意忽略大小写,都大写 或者都小写.
14,随机6位数验证码  '%06d' % random.randint(0,999999)

15,添加项目依赖环境文件.  在黑窗口pip freeze>requirement.txt

16,解决问题 4开头看前端
			5 开头 看后端
			没问题看下浏览器	87一天2


DAY 16
11.16
1,昨日露点 
2,@理解 视图函数 是def下绑定的哪个函数,app后面的'/'就是视图.route是把函数绑定给视图.
3,  @给视图传参/<参数>就是让函数调用视图的参数参数,以达到让浏览器返回用户自己的参数并让服务器接受用户参数的效果.  但是传递的参数会被编译 ,所以要过滤.
4,  @内置过滤器有6种,默认是字符串string,还有两种数值型的:int ,float,另外三种叫any,path,uuid.

-----------------------------------------

5,今日笔记
	接口文档 接口设计 
	.URL:/接口 路由
	.methods: post
	.dataType:json
	
	参数名 类型 是否必须 参数说明 
	如果前后端交互不了,看接口文档,谁写的有问题,谁负责.
	如果接口文档有问题,改接口文档.
	接口文档是按照项目需求文档设计的.
	
	
6,检查参数 的一般思想   写入日志的信息
	6.1 uuid或者手机号
	6.2 检查uuid或者手机号格式
	6.3 格式错误终止  终止前保存日志
	@	是否注册 保存是否注册 返回终止信息.
	6.4 格式正确 读取数据库对比带来的参数
	6.5 一次性的的数据信息删除 写入日志
	6.6 返回或者存储  
	6.7 前端返回提示.
	@	是否注册过手机号 这里提示会泄露信息.
	
	曾经有个人告诫我,你怎样走能少走弯路,我没有在意,直到我现在在弯路上才后悔莫及,如果老天再给我一个机会让我重来一次的话,我一定会洗耳恭听.如果能给从来指定一个日期的话,我希望是有记忆的那一天.
	
7,前端实现思路  
	7.1 var得参数
	7.2 ajax发送请求
		{()}
8, 缓存用户昵称等可变信息到redis中的话, 有可能出现问题是在农业面中信息是过期信息类似于修改后的真正信息在页面中不显示,好像就是改不了的昵称. 也就是 要保证redis数据库和mysql数据库中的数据保持一致.
	@缓存数据和mysql数据库 的作用要分清
	@问题,缓存数据和数据库数据不一致的解决方法.  以什么为准,要以数据库为准.缓存信息的字段要以为数据库为准.
	@问题,为了避免缓存过期,怎么办  业务逻辑改成缓存显示后就过期.然后以mysql为准.
	
9,检查用户登录状态:显示是否登录
	9.1 思路接收参数--检查参数--业务逻辑--返回参数
	9.2 使用会话 也就是状态保持.
	@user = none??????
	
10,退出实现. 清除缓存
11, 三元表达式 
	a?c : b 判断是不是a 是就执行c 不是就执行b
	报黄  ????????????
12, 完善csrfPortect 设置csrf_token,让after_request(response)带走,因为每次请求都会执行after_request.  
	return response
	
	在ajax值里面添加请求头信息,header:{
		x-csrftoken:get(cookie),
	},


DAY 11.18
「print(''牧哲: Wpy℡15035135008''):唯一知道的事情就是自己一无所知。

1,昨日总结 
递归调用有可能造成栈溢出 ,可以在需要递归的地方单独调用,比如昨天的溢出,不让全部调用,每行单独调用。
2,点击排行实现
查询点击量 按点击量排行。
@实现不同的样式 用过滤器 写在工具文件中 是个过滤工具
在初始化文件中导入过滤器。
@这里可以写三行样式代码然后再写循环。
3,新闻分类展示
首页展示 查询数据库 查询新闻分类然后遍历结果,
最新新闻实现方法
过滤器查询所有的新闻中按时间排序
然后分页
@分页 paginate
@代码示例 给别人看懂的代码块 
@注意转换数据类型要进行异常处理。
  另外两种需要处理异常的情况:
@找错误 print()
   alert()
   return的地方插入断点。
.each  前端遍历命令

@页面加载原理 默认是不加载 等加载完一页再加载新的一页  可以防止暴力刷新。

4,新闻详情展示实现
转换器返回用户请求的数据。
@登陆 和首页展示的部分 不是固定的盒子吗,为什么切换其他的新闻详情页面还要手动展示?不是局部刷新吗?
@g对象。
@函数名.__name__ 就是函数的的名字
fun.__name__ 返回的就是fun  实现这个效果的标准模块  functools

5,实现收藏列表
默认收藏 判断用户是否取消

6,模板继承」
—————————
urlfor查询的是?后面的数据
proxy代理

DAY 11.19
1,基本资料实现
2,接口怎么写。
@new_blue.rout()
 获取参数  就是有没有参数值
检查参数就是对比参数是否存在
根据参数的值查询对应的新闻是否存在
将评论信息保存在数据库
提交数据
返回结果
@判断用户是否登陆
获取  就是查询
检查就是 ifnotall
转换类型 news-id = int(news-id)
判断手否有父评论id
vue
评论是模板渲染的  需要周四新闻详情中留评论信息才能实现静态展示。
@如果有评论显示评论 没有评论 不展示
实现方式 遍历评论内容
 
3 登陆界面
iframe  前端页面嵌套
iframe是个标签
判断是否登陆 登陆了进个人中心 没登陆重定向到登陆页面
中心显示的是数据  通过查询展示
@快速导入如果不是包有可能自动创建bug
@对比数据去重 编码后对比数据 节省原二进制对比。
4,图片上传
@,后端获取文件 request.files
4.1判断用户登陆 如果登陆判断请求方法,使用模板渲染数据
4.2如果不是get请求,获取参数,获取文件对象,文件对象是要有读写方法的对象
4.3  读取图片
4.4 用云存储数据
4.5 在mysql中存储图片截连接
4.6 返回给前端。
4.7  本地数据库存储文件应该存行对地址,应为引用的常量已经保存了常量的绝对的地址,绝对地址是空间地址,有可能会改变,这个常量如果改变,可以维护,存贮绝对的地址的话就不好维护。(????)
@难道云返回的图片名称是地址吗,也就hi说可以在青牛里直接搜名称就出来了吗?
@一个浏览器一般不允许多、开!!???

5. 发布新闻
发布新闻接口。。

这部分是表单提交 表单不是和后台已经连接了吗,怎么写怎么提交,还用判断吗?
5.1 新闻发布获取参数
title = requst.form.get(titlie)
@存储新闻图片存储一个绝对路径,因为新闻图片一般来说对新闻很重要,如果不存在新闻图片就不展示新闻,?????答 看情况,不一定
5.2 提交数据 db存储在数据库 


6,管理员页面
在manage文件中添加代码完成管理员添加。
函数不是必须返回数据吗?

7,后台客户统计
@模拟用户添加。
timedelta  时间随机数
@手动开启上下文,才能和manager关联。
@添加密码固定数据,。iambic一样的。
8,项目部署
硬件 和 软件 
电脑系统 
操作系统,flask自带的服务器用来调试。不能用于生产。
@epoll linux操作系统的内核。
@项目的并发量,几百上千最多。
@nginx 反向代理服务器。转发用户服务请求,对不同服务器进行分配。
达到请求转发和负载均衡的目的。
@反向代理就是客户端不知道具体访问服务器是哪台。
@正向代理,就是通过代理不让服务器知道客户是谁。
@所以,有可能一次请求有可能同时存在正向代理 和 反向代理。」
—————————
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值