day78——基础知识复习2

一、后续课程安排

1 drf框架
2 git
3 redis使用
4 路飞项目(celery异步)
5 爬虫(mongodb)
6 linux
7 cmdb项目(资产收集)
8 代码发布系统
9 flask框架(给你一到两个项目)
10 数据结构和算法
11 docker,dockercompose(用docker部署项目,nginx负载均衡,横向扩展),k8s(看情况)
12 就业辅导(redis高级,Elasticsearch,如何提高项目并发量,分布式锁,分布式id,远程连接docker开发,git冲突如何解决)

二、作业讲解

作业一:

前后端传数据三种编码格式,传json格式,原生django不能从POST中取出字典,用中间件或者装饰器前端不管传json还是其他格式,requests对象中有个data属性

form django.utils.deprecaton import MiddlewareMixin

import json 
class JsonMiddel(MiddlewareMixin)
	def process_request(self,request):
        try:
            request.data = json.loads(request.body)
        except Exception as e:
            request.data = request.POST
                        

前端用ajax提交数据:

<body>
<form method="post">
    用户名:<input type="text" name="name" id="name">
    密码:<input type="text" name="pwd" id="pwd">
    <input type="submit" value="提交1">
    <input type="button" value="提交" id="submit">

</form>

</body>
<script>
    $('#submit').click(function () {
        $.ajax({
            url:'/index/',
            type:'post',
            contentType:'application/json',
            data:JSON.stringify({'name':$('#name').val(),'pwd':$('#pwd').val()}),
            //data:{'name':$('#name').val(),'pwd':$('#pwd').val()},
            success:function (data) {
                console.log(data)

            }
        })

    })
</script>

易错点:

  1. form表单和ajax重复提交请求:

    form表单中input的submit类型和button按钮都会触发提交数据的动作,如果有ajax的话,点一次按钮就会提交两次,如果只需要用ajax提交数据那么就绑定input的button类型,或者将button按钮放在form表单外进行绑定。

  2. form django.http.request import QueryDict

    本质是一个字典,但是比字典的功能强大,并且不能修改值,一改就会报错,只能用copy复制一份进行修改。

ps:CommonMiddleware中间件控制了是否重定向到带/的地址

"""
当在浏览器中输入的url没有以/结尾,请求到django中间件中会自动拼接上/,然后在匹配一次路由
这是django的CommonMiddleware帮我们实现的"""

# django.middleware.common.CommonMiddleware 中间件源码
class CommonMiddleware(MiddlewareMixin):
    ...
    def should_redirect_with_slash(self, request):
        """
        Return True if settings.APPEND_SLASH is True and appending a slash to
        the request path turns an invalid path into a valid one.
        """
        if settings.APPEND_SLASH and not request.path_info.endswith('/'):
            urlconf = getattr(request, 'urlconf', None)
            return (
                not is_valid_path(request.path_info, urlconf) and
                is_valid_path('%s/' % request.path_info, urlconf)
            )
        return False

三、python 中的魔法方法(双下滑方法)

常用的魔法方法:

  • __init__:类实例化对象会触发

  • __stry__:打印对象会触发

  • __call__:对象加()调用会触发,类也是对象,元类(),类的实例化过程调用元类的__call__

  • __new__:在类实例化会触发,它比 __init__早,(造一个空的对象)

  • __del__:del对象或者在对象被回收的时候触发

  • __setattr__/__getattr__:(.拦截方法),当对象.属性的时——》赋值的时候调用__setattr__

    取值的时候调用__getattr__

  • __getitem__/__setitem__:([]拦截),字典添加键值对或者[]取值的时候会触发

  • __enter__/__exit__:上下文管理器,进入with管理的时候触发、with代码块运行结束后触发

3.1 setattr、getattr、settiem、getitem演示

# 1 __setattr__与__getattr__
class MyClass:
    def __init__(self, name):
        self.name = name

    def __setattr__(self, name, value):
        if type(value) != str:
            print('名字必须是字符串')
        else:
            # setattr(self,key,value) 内部还是用.赋值,又会触发__setattr__,形成递归报错。
            self.__dict__[name] = value # 不要加引号


obj1 = MyClass('zts')
obj1.name = 123
print(obj1.name)


# 2 __getitem__与__setitem__

class MyClass1:
    def __init__(self, name):
        self.name = name

    def __setitem__(self,key,value):
        setattr(self,key,value)

    def __getitem__(self, key):
        return getattr(self,key)


obj2 = MyClass1('tom')
obj2['age'] = 18
print(obj2['age'])

3.1 with上下文管理器

class Person:
    def __enter__(self):
    	print('我在with管理的时候,会触发')
        return 'xx'  # 进入with语句块执行此方法,此方法如果有返回值就会赋值给as声明的变量
    
    def __exit__(self, exc_type,exc_val,exc_tb):
        print('在退出with代码块,也就是with代码块运行完后会执行此方法')
        print('1',exc_type)
        print('2',exc_val)
        print('3',exc_tb)
        
      
with Person() as p:  # 这句代码执行,会触发类的__enter__方法
    print(p)  # 打印之后with代码块运行结束,会触发类的__exit__方法
    

四、cookie/session/token

HTTP协议四大特性:

  1. 无状态
  2. 无连接
  3. 基于请求相应
  4. 基于tcp/ip,应用层协议
  • mysql:c/s架构,底层基于socket,自己封装的协议,mysql的服务端:navicate(c++图形化界面,实现了请求和相应协议)/pymsql(用python语言实现了请求和响应协议)
  • redis:c/s架构,底层基于socket,自己封装的协议
  • docker:c/s架构,基于http协议,使用restfull规范

是存在浏览器上的键值对,向服务端发送请求,携带它过去(不安全)

session:

存在与服务端的键值对,可以放在文件中或者数据库中(mysql/rediex)

django中session的底层原理:

# 在中间件中,请求走的时候,process_response,取出request.session的modify属性,判断是否是true,如果是true,表示在视图函数中修改过session,数据库同步修改,如果是false,就不修改,返回给前端sessionid:随机字符串
# 请求来了,通过sessionid,取出随机字符串--》去数据库中查--》把表的数据转成字典,赋值给request.session,后面视图函数中就可以操作它了

缺点:如果用户量大,存储需要耗费服务端资源

token:

token现在应用非常广泛,契合了前后端分离

JWT:json web token

五、异常处理

try:
    print("xxx")
    # print(1/0)
except Exception as e:
    print(e)
else:  # 基本上不会用到
    print("正常执行,没有出异常,会走")
finally:
    print("我是finally")   # 用于会走,无论是否有异常

六、pymsql的使用

# 1 连接数据库
conn = pymsql.connect(host='127.0.0.1',
                      user='root',
                      passwrod='1111',
                      database='test',
                      port=3306)
# 2 获取游标
cursor = conn.cursor(cursor = pymysql.cursors.DictCursor) # 字典格式
# 查
sql_1  = 'select id,name from book'
cursor.execute(sql_1)
ret = cursor.fetchall()
print(ret)

# 插入数据
sql_2 = 'insert into book(id,name) values(%s,%s)'
cursor.execute(slq_2,[3,'tom'])
conn.commit()  # 提交到数据库

# 删除
sql_3 = 'delete from book where name=%s'
cursor.execute(sql,['tom'])
conn.commit()

# 更新
sql_4 = 'update book set name=%s where id=%s'
cursor.execute(sql_4,['xxx',1])
conn.commit()

作业:

1 写一个类,有个name属性,如果name赋值为非字符串,就不让放

class MyClass:
    def __init__(self, name):
        self.name = name

    def __setattr__(self, name, value):
        if type(value) != str:
            print('名字必须是字符串')
        else:
            self.__dict__[name] = value


obj1 = MyClass('zts')
obj1.name = 123
print(obj1.name)
obj1.name = 'tom'

"""
名字必须是字符串
zts
tom"""

2 通过上下文管理器写一个mysql的连接,通过with管理

class MySQL:
    conn = None
    cursor = None

    def __init__(self, host, port, user, password, database):
        self.host = host
        self.port = port
        self.user = user
        self.password = password
        self.database = database

    def __enter__(self):
        import pymysql
        self.conn = pymysql.connect(host=self.host,
                                    port=self.port,
                                    user=self.user,
                                    database=self.database,
                                    password=self.password)
        self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)  # 将查询出来的数据由元祖的形式改成字典
        return self.conn

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.conn.close()


with MySQL('127.0.0.1', 3306, 'root', '123123', 'db_py') as conn:
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
# 1 查
sql_1 = 'select name,age from student'
cursor.execute(sql_1)
ret = cursor.fetchall()
print(ret)

# 2 增
sql_2 = 'insert into student(name,age) values(%s,%s)'
cursor.execute(sql_2, ['tank', 20])
conn.commit()

# 3 删
sql_3 = 'delete from student where name=%s'
cursor.execute(sql_3, ['tom'])
conn.commit()

# 4 改
sql_4 = 'update student set name=%s where id>0'
cursor.execute(sql_4, ['xxx'])
conn.commit()

3 使用django实现token功能

# 1 视图函数
def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        user_obj = auth.authenticate(request,username=username,password=password)
        if user_obj:
            request.user_id = username
            return HttpResponse('登陆成功')
        else:
            request.user_id = None
            return HttpResponse('登陆失败')
    return render(request,'login.html')


# 2 自定义中间件
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
import hashlib


class MyMiddleware(MiddlewareMixin):
    def process_request(self, request):
        res = request.COOKIES.get('token')
        if res:
            user_id, user_hash = res.split('|')
            m = hashlib.md5()
            m.update(user_id.encode())
            m.update('世界那么大我想去看看'.encode('utf-8'))
            user_hash_1 = str(m.hexdigest())
            if user_hash_1 == user_hash:
                print(f'token校验成功,这是{user_id}的信息')
            else:
                obj = HttpResponse(f'token已被修改,校验失败,无法获取{user_id}的信息')
                obj.delete_cookie('token')
                return obj
        else:
            print('没有登陆,无法获取用户信息')

    def process_response(self, request, response):
        try:
            user_id = request.user_id
            if user_id:
                m = hashlib.md5()
                m.update(user_id.encode())
                m.update('世界那么大我想去看看'.encode('utf-8'))
                user_hash = str(m.hexdigest())
                token_list = [user_id, user_hash]
                token = '|'.join(token_list)
                obj = HttpResponse('token设置成功')
                obj.set_cookie('token', token)
                return obj
        except Exception:
            return response

posted @ 2020-07-02 21:33  风起千寻  阅读(111)  评论(0编辑  收藏  举报