一. Form&Auth

Form的验证思路--使用django内部的用户表单验证
前端:form表单
后台:创建form类,当请求到来时,先匹配,匹配出正确和错误信息。'''*******************
# templates/register.html
注意:
{% csrf_token %}
{{ errors.username }}
*******************'''  <form action="" method="post">{% csrf_token %}<p>用户名: <input type="text" name="username"><span>{{ errors.username }}</span></p><p>密码: <input type="password" name="password"><span>{{ errors.password }}</span></p><p>确认密码: <input type="password" name="password2"><span>{{ errors.password2 }}</span></p><input type="submit" value="注册">
</form>'''*******************
# App/forms.py
注意:在app目录下新建的文件forms.py
可以创建不同的表单验证类,对表单的字段进行验证
from django import forms
*******************'''  # Form的使用
class RegisterForm(forms.Form):# 使用表单做校验# 表示username字段必须填写,且最大不超过16字符,最小不低于6字符username = forms.CharField(required=True,max_length=16,min_length=6,error_messages={'required': "注册用户名必须填写",'max_length': '注册账号最长不超过16','min_length': '注册账号最小不少于6',})password = forms.CharField(required=True,max_length=18,min_length=6,error_messages={'required': '密码不能为空','max_length': '长度不能超过18','min_length': '长度不能小于6',})password2 = forms.CharField(required=True,max_length=18,min_length=6,error_messages={'required': '密码不能为空','max_length': '长度不能超过18','min_length': '长度不能小于6',})age = forms.IntegerField(required= True,max_value=100,min_value=18,error_messages={'required': '年龄不能为空','max_value': '超过最大年龄','min_value': '小于最小年龄',}# 重写clean方法def clean(self):# 获取清洗过之后的数据username = self.cleaned_data.get('username')password = self.cleaned_data.get('password')password2 = self.cleaned_data.get('password2')if password != password2:# 两次密码不一致raise forms.ValidationError({'password2': "两次密码不一致!"})# 检测用户名是否已存在if User.objects.filter(username=username).exists():raise forms.ValidationError({'username': "用户名已存在!"})return self.cleaned_data   '''*******************
# App/views.py
注意:
from django.contrib.auth.models import User
使用的是django内置模型来创建用户,而且密码是加密的
登录验证密码时要用auth.authenticate()
*******************'''
# 视图函数
def register(request):if request.method == 'GET':return render(request, 'register.html')elif request.method == 'POST':# 使用formform = RegisterForm(request.POST)if form.is_valid():# 如果所有输入都验证成功username = form.cleaned_data.get('username')password = form.cleaned_data.get('password')# 注册User.objects.create_user(username=username, password=password)return redirect(reverse('login'))else:# 验证失败print("form.errors: ", form.errors, type(form.errors))return render(request, 'register.html', {"errors": form.errors})'''*******************
登录验证
*******************'''
class LoginForm(forms.Form):# 对单个输入框验证username = forms.CharField(required=True,max_length=20,min_length=6,error_messages={'required': '用户名不能为空','max_length': '长度不能超过20','min_length': '长度不能小于6',})password = forms.CharField(required=True,max_length=18,min_length=6,error_messages={'required': '密码不能为空','max_length': '长度不能超过18','min_length': '长度不能小于6',})# 重写clean方法def clean(self):# 获取清洗过之后的数据username = self.cleaned_data.get('username')password = self.cleaned_data.get('password')# 检测用户名是否已存在if not User.objects.filter(username=username).exists():raise forms.ValidationError({'username': "不存在该用户名!"})# 检测密码if not auth.authenticate(username=username, password=password):raise forms.ValidationError({'password': "密码错误!"})return self.cleaned_data'''*******************
登录验证views.py
*******************'''  # 登录
def login(request):if request.method == 'GET':return render(request, 'login.html')elif request.method == 'POST':# username = request.POST.get('username')# password = request.POST.get('password')# 使用formform = LoginForm(request.POST)if form.is_valid():username = form.cleaned_data.get('username')password = form.cleaned_data.get('password')# 登录验证,设置sessionuser = auth.authenticate(username=username, password=password) # 多余验证,可以在formauth.login(request, user)  # 设置sessionreturn redirect(reverse('index'))else:return render(request, 'login.html', {'errors': form.errors})Auth
Django内置了强大的用户认证系统auth,它默认使用 auth_user 表来存储用户数据。
在INSTALLED_APPS中添加'django.contrib.auth'使用该APP, auth模块默认启用。auth 模块
创建超级用户:python manage.py createsuperuserauth.authenticate():验证用户名和密码是否正确,一般需要username、password,认证成功返回一个User对象。
auth.login():将认证通过后的User对象注入request.user属性,会在后端为该用户生成相关session数据。
auth.logout():调用该函数时,当前请求的session信息会全部清除。该用户即使没有登录,使用该函数也不会报错。
# 注销
def logout(request):    auth.logout(request)  # 删除sessionreturn redirect(reverse('index'))is_authenticated():判断是否认证。login_requierd():auth给我们提供的一个装饰器工具,用来快捷的给某个视图添加登录校验。- 若用户没有登录,则会跳转到django默认的登录URL '/accounts/login/' 并传递当前访问url的绝对路径 (登陆成功后,会重定向到该路径)。- 如果需要自定义登录的URL,则需要在settings.py文件中通过LOGIN_URL进行修改。- LOGIN_URL = '/login/'  # 这里配置成你项目登录页面的路由# 购物车
@login_required
def cart(request):return render(request, 'cart.html')    create_user():创建一个新用户,需要username、password等。
create_superuser():创建一个超级用户。* check_password():检查密码是否正确。* set_password():修改密码,设置完一定要调用用户对象的save方法。

二.验证码

在用户登录,注册以及一些敏感操作的时候,我们为了防止服务器被暴力请求,或爬虫爬取,我们可以使用验证码进行过滤,减轻服务器的压力。验证码需要使用绘图 Pillowpip install Pillow核心Image,ImageDraw,ImageFont绘制流程backgroundcolor = (10,20,30)   RGB颜色初始化画布 image = Image.new('RGB',(100,50),backgroundcolor)获取画布中画笔对象draw = ImageDraw.Draw(image)绘制验证码,随机四个font = ImageFont.truetype('path',size)fontcolor = (20,40,60)draw.text((x,y),'R',font,fontcolor)最后扫尾del draw import iobuf = io.BytesIO()Image.save(buf, 'png')return HttpResponse(buf.getvalue(),'image/png')'''*******************
# templates/index.html
注意:
{% csrf_token %}
{{ errors.username }}
*******************'''
<form action="" method="post">{% csrf_token %}<p> 用户名: <input type="text" name="username"> </p><p> 验证码: <input type="text" name="vcode"><img id="vcode" src="/genvcode/" /></p><input type="submit" value="登录">
</form><script>vcode.onclick = function () {// 由于浏览器会自动缓存图片,相同的图片url不会重新从服务器获取,所以需要更换随机urlthis.src = '/genvcode/?rd=' + Math.random()}
</script>   '''*******************
# App/views.py
注意:
# 随机验证码(4位数字字母)
# 随机颜色
*******************'''
# 验证码
def gen_vcode(request):# 1. 创建画布# 第一个参数: RGB颜色# 第二个参数: 画布大小# 第三个参数: 画布背景颜色image = Image.new('RGB', (100, 50), (200, 200, 100))# 2. 创建画笔draw = ImageDraw.Draw(image, 'RGB')# 3. 创建字体样式font_path = os.path.join(BASE_DIR, 'App/static/fonts/ADOBEARABIC-BOLD.OTF')font = ImageFont.truetype(font_path, 30)# 4. 画# 后台生成的验证码, 保存在session中vcode = random_code()request.session['vcode'] = vcode# 5、设置每位验证码的左右上下位置,并画在画布上for i in range(len(vcode)):xy = (15 + i*20, 10 + random.randint(-5, 5))draw.text(xy, vcode[i], font=font, fill=random_color())# 6. 转换成图片buff = io.BytesIO()  # 创建一个二进制的内存缓冲区image.save(buff, 'png')  # 将画布转成成png格式的图片,保存到buff缓冲区中return HttpResponse(buff.getvalue(), 'image/png')# 将图片二进制从缓冲区中取出,并以指定图片格式显示# 随机验证码(4位数字字母)
def random_code():s = "0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"code = ''for i in range(4):code += random.choice(s)return code# 随机颜色
def random_color():return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)# index
def index(request):if request.method == 'POST':username = request.POST.get('username')# 用户输入的验证码verify_code = request.POST.get('vcode')# 获取session中的vcodevcode = request.session.get('vcode')# 检测验证码是否匹配(忽略大小写)if verify_code.upper() == vcode.upper():return HttpResponse('验证码输入正确!')else:return HttpResponse('验证码输入不正确!')else:return render(request, 'index.html')

三.富文本

富文本:Rich Text Format(RTF),是由微软开发的跨平台文档格式,大多数的文字处理软件都能读取和保存RTF文档,其实就是可以添加样式的文档,和HTML有很多相似的地方tinymce 插件django的插件pip install django-tinymce用处大约有两种1. 在后台管理中使用2. 在页面中使用,通常用来作博客1.后台中使用:配置settings.py文件INSTALLED_APPS 添加  tinymce 应用添加默认配置TINYMCE_DEFAULT_CONFIG = {'theme':'advanced','width':600,'height':400,}创建模型类from tinymce.models import HTMLFieldclass Blog(models.Model):sBlog = HTMLField()配置站点admin.site.register2.在视图中使用:使用文本域盛放内容<form><textarea></textarea></form>在head中添加script<script src='/static/tiny_mce/tiny_mce.js'></script><script>tinyMCE.init({'mode':'textareas', 'theme':'advanced','width':800,'height':600,})</script>

四. Cache

缓存

django内置了缓存框架,并提供了几种常用的缓存,
django使用统一的api操作各类的缓存系统,类似于orm- 基于Memcached缓存
- 使用数据库进行缓存
- 使用文件系统进行缓存
- 使用本地内存进行缓存
- 提供缓存扩展接口

1、基于数据库缓存配置

(1)创建缓存表
python manage.py createcachetable [table_name]
例如: python manage.py createcachetable cache_db
(2)缓存配置(settings)
# 在工程目录下的settings加入下面选项CACHES = {'default': {'BACKEND': 'django.core.cache.backends.db.DatabaseCache',  # 缓存引擎'LOCATION': 'cache_table',  # 缓存表'TIMEOUT': '60', 'OPTIONS': {'MAX_ENTRIES': '300',},'KEY_PREFIX': 'jack',  # 缓存记录的前缀'VERSION': '1',}
}
(3)缓存使用(两种使用方式)
'''*******************
# 1.在视图中使用(使用最多的场景)
注意:缓存整个视图
@cache_page(time)
缓存整个视图,当浏览器第一次请求该视图时,会等待5s返回;
然后30秒内浏览器再访问,则从缓存中返回给浏览器,不需等待5s
*******************'''
- @cache_page()
参数:- time 秒  60*5 缓存五分钟- cache 缓存配置, 默认default,- key_prefix 前置字符串@cache_page(30)
def user_list(request):users = User.objects.all()template = loader.get_template('userlist.html')user_list = template.render({'users': users})time.sleep(5)return HttpResponse(user_list)    '''*******************
# 2.在视图中使用(使用最多的场景)
注意:缓存模板
获取cache
from django.core.cache import cache
cache = cache['cache_name'] 或 cache = cache.get('cache_name')设置cache
from django.core.cache import cache
cache.set(key, value, timeout)
*******************'''    def user_list(request):data = cache.get('user_list')if data:return HttpResponse(data)else:users = User.objects.all()template = loader.get_template('userlist.html')print(template, type(template))  # <class 'django.template.backends.django.Template'>user_list = template.render({'users': users})print(user_list, type(user_list))  # <class 'django.utils.safestring.SafeText'>cache.set('user_list', user_list, 30)time.sleep(5)return HttpResponse(user_list)    
(4)缓存底层

使用原生缓存来实现

def get_user_list(request):# 每次从缓存中获取user_cache = cache.get('user_cache')# 如果有缓存,则从缓存中直接取if user_cache:result = user_cache# 如果没有缓存,则从数据库中获取else:# 模拟长时间的数据操作user_list = User.objects.all()time.sleep(5)data = {'users': user_list,}# 使用模板渲染,得到result文本template = loader.get_template('App/stu_list.html')result = template.render(data)# 设置缓存cache.set('user_cache', result, 10)return HttpResponse(result)

2、基于redis数据库缓存配置

# 在工程目录下的settings下面修改选项# 缓存cache配置
CACHES = {# 使用数据库表缓存#   1. 创建缓存表: createcachetable cache_table#   2. 在settings中配置# 'default': {#     'BACKEND': 'django.core.cache.backends.db.DatabaseCache',#     'LOCATION': 'cache_table',#     'TIMEOUT': '60',#     'OPTIONS': {#         'MAX_ENTRIES': '300',#     },#     'KEY_PREFIX': 'QF',#     'VERSION': '1',# },# 使用redis缓存# 1. 安装插件:pip install django_redis# 2. 在settings中配置# 3. 启动redis服务: redis-server# 4. 启动redis客户端: redis-cli , 查看数据库1中的缓存内容."default": {"BACKEND": "django_redis.cache.RedisCache","LOCATION": "redis://127.0.0.1:6379/1","OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient",# "PASSWORD": "密码"},'KEY_PREFIX': 'HWM',}}

3、缓存可能造成的问题

1、缓存穿透
缓存穿透,是指查询一个数据库一定不存在的数据。正常的使用缓存流程大致是,数据查询先进行缓存查询,如果key不存在或者key已经过期,再对数据库进行查询,并把查询到的对象,放进缓存。如果数据库查询对象为空,则不放进缓存。想象一下这个情况,如果传入的参数key,查询不到数据,就是一定不存在的对象。就会每次都去查询数据库,而每次查询都是空,每次又都不会进行缓存。假如有恶意攻击,就可以利用这个漏洞,对数据库造成压力,甚至压垮数据库。即便是采用UUID,也是很容易找到一个不存在的KEY,进行攻击
解决方案: 如果从数据库查询的对象为空,也放入缓存,只是设定的缓存过期时间较短,比如设置为60秒。2、缓存雪崩
缓存雪崩,是指在某一个时间段,缓存集中过期失效。产生雪崩的原因之一,马上就要到双十二零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。在做电商项目的时候,一般是采取不同分类商品,缓存不同周期。在同一分类中的商品,加上一个随机因子。这样能尽可能分散缓存过期时间,而且,热门类目的商品缓存时间长一些,冷门类目的商品缓存时间短一些,也能节省缓存服务的资源。其实集中过期,倒不是非常致命,比较致命的缓存雪崩,是缓存服务器某个节点宕机或断网。因为自然形成的缓存雪崩,一定是在某个时间段集中创建缓存,那么那个时候数据库能顶住压力,这个时候,数据库也是可以顶住压力的。无非就是对数据库产生周期性的压力而已。而缓存服务节点的宕机,对数据库服务器造成的压力是不可预知的,很有可能瞬间就把数据库压垮。3、缓存击穿
缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。
其实,大多数情况下这种爆款很难对数据库服务器造成压垮性的压力。达到这个级别的公司没有几家的。所以对主打商品都是早早的做好了准备,让缓存永不过期。即便某些商品自己发酵成了爆款,也是直接设为永不过期就好了

五、cors跨域

1.什么是跨域

跨域(跨源)是指浏览器从一个源的网页去请求另一个源,源指的是域名、端口、协议以下都属于跨域问题
域名: 主域名不同: http://www.baidu.com/index.html –> http://www.sina.com/test.js 子域名不同: http://www.666.baidu.com/index.html –> http://www.555.baidu.com/test.js 域名和域名ip: http://www.baidu.com/index.html –>http://180.149.132.47/test.js
端口: http://www.baidu.com:8080/index.html–> http://www.baidu.com:8081/test.js
协议: http://www.baidu.com:8080/index.html–> https://www.baidu.com:8080/test.js 

2.为什么要考虑跨域问题

因为Ajax不能跨域, 一旦客户端和服务端的不在一台服务器, 则需要考虑跨域访问的问题

3.同源策略

同源策略是浏览器的一项最为基本同时也是必须遵守的安全策略。
同源策略的存在,限制了“源”自A的脚本只能操作“同源”页面的DOM,“跨源”操作来源于B的页面将会被拒绝。
所谓的“同源”,必须要求相应的URI的域名、端口、协议均是相同的。

4.使用Ajax发送请求的方式

//js
xhr = new XMLHttpRequest();
xhr.open('get', 'http://127.0.0.1:8000/app/getdata/', true);
xhr.send();
xhr.onreadystatechange = function () {if (xhr.readyState==4 && xhr.status==200){console.log(JSON.parse(xhr.responseText))}
}//jq
$.ajax({type: "get",url: 'http://127.0.0.1:8000/app/getdata/',data: {},async: true,success: function (data) {console.log(data);},error: function (e) {console.log(e);}
})// get请求
$.get("http://127.0.0.1:8000/app/getdata/", function (data) {console.log(data);
});// post请求 【csrf验证】
$.ajaxSetup({data:{csrfmiddlewaretoken:'{{ csrf_token }}'}
});$.post("http://127.0.0.1:8000/app/getdata/", function (data) {console.log(data);
})

5.解决跨域问题

方式一: 使用 JSONP (一种非Ajax技术,需要前后端同时支持)
'''*******************
# 1.login.html
注意:js写法
*******************'''
<script>//jq//使用jsonp: 只能用于get$.ajax({url:'http://127.0.0.1:8000/getdata/',dataType: 'JSONP',  //# 回调函数参数的名称 相当于http://127.0.0.1:8000/getdata/?callback=fnjsonp: 'callback',                   jsonpCallback: 'fn',  # 回调函数名称});# fn('情人节快乐!')  服务器返回, 浏览器自动调用function fn(data) {console.log("----fn--",data)}
</script>'''*******************
# view.py
注意:jsonp后端写法
*******************'''
def get_data(request):# return JsonResponse({'name': '成龙'})# jsonp后端写法callback = request.GET.get('callback')print(callback)return HttpResponse('%s("情人节快乐!")' % callback)  # fn('情人节快乐!')
方式二: 让服务器支持跨域(推荐)
Django支持跨域
安装django-cors-headerspip install django-cors-headers
配置settings.py文件INSTALLED_APPS = ['corsheaders',]MIDDLEWARE = ('corsheaders.middleware.CorsMiddleware','django.middleware.common.CommonMiddleware', )# 跨域增加忽略CORS_ALLOW_CREDENTIALS = TrueCORS_ORIGIN_ALLOW_ALL = True# 跨域允许的请求方式(可选)CORS_ALLOW_METHODS = ('DELETE','GET','OPTIONS','PATCH','POST','PUT',)# 跨域允许的头部参数(可选)CORS_ALLOW_HEADERS = ('XMLHttpRequest','X_FILENAME','accept-encoding','authorization','content-type','dnt','origin','user-agent','x-csrftoken','x-requested-with','Pragma',)

六、Celery分布式任务队列

1.celery介绍与简单使用
1.celery介绍:
Celery - 分布式任务队列. Celery 是一个简单、灵活且可靠的, 基于python开发的分布式异步消息任务队列,通过它可以轻松的实现任务的异步处理, 如果你的业务场景中需要用到异步任务,就可以考虑使用celery.
使用场景:(1).你想执行一个操作,可能会花很长时间,但你不想让你的程序一直等着结果返回,而是想有创建一个任务,这个任务会在其他地方执行,执行完毕后会你拿到结果, 在任务执行过程,你可以继续做其它的事情。 (2).你想做一个定时任务,比如每个星期五发送一条会议通知.Celery它是一个专注于实时处理的任务队列,同时也支持任务调度.Celery是基于Python开发的一个分布式任务队列框架,支持使用任务队列的方式在分布的机器/进程/线程上执行任务调度.2.Celery 主要包含以下几个模块:
(1).任务模块 Task包含异步任务和定时任务。其中,异步任务通常在业务逻辑中被触发并发往任务队列,而定时任务由 Celery Beat 进程周期性地将任务发往任务队列。(2).消息中间件 BrokerBroker,即为任务调度队列,接收任务生产者发来的消息(即任务),将任务存入队列。Celery 本身不提供队列服务,官方推荐使用 RabbitMQ 和 Redis 等。(3).任务执行单元 WorkerWorker 是执行任务的处理单元,它实时监控消息队列,获取队列中调度的任务,并执行它。(4).任务结果存储 BackendBackend 用于存储任务的执行结果,以供查询。同消息中间件一样,存储也可使用 RabbitMQ, redis 和 MongoDB 等。3.安装celery
创建虚拟环境mkvirtualenv celeryenv
使用pip安装pip install celery4.简单使用celery创建python工程, 然后新建tasks.py文件, 写入以下代码from celery import Celery# 创建celery对象,设置任务队列使用redisapp = Celery('tasks', broker='redis://localhost:6379')# 创建任务@app.taskdef add(a, b):    time.sleep(5)     ## 模拟等待超时n = a + b    print(n)    return nif __name__ == '__main__':# add(10, 5)    # 调用任务add.delay(10, 5)print('程序执行结束')   5.启动celery服务
linux:celery -A tasks worker --loglevel=info
windows:pip install eventletcelery -A tasks worker --loglevel=info -P eventlet6.运行tasks.py文件,结果是:先打印--程序执行结束,过5s之后再打印n的值
2、django中使用celery(配合redis与cache)
1、安装相关库
pip install celery
pip install redis
pip install sqlalchemy'''*******************
# 2.templates/login.html
注意:
*******************''' <form action="" method="post">{% csrf_token %}<p>手机号:<input type="text" name="phone" class="phe"></p><p>验证码:<input type="number" name="vcode"><span id="send">发送短信</span></p><input type="submit" value="登录"></form>'''*******************
# 3、msgpro/celery.py
注意:新增文件celery.py
msgpro为项目名称,要根据具体更改
*******************'''
from __future__ import absolute_import, unicode_literals
import os
from celery import Celeryos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'msgpro.settings')
app = Celery('msgpro')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()@app.task(bind=True)
def debug_task(self):print('Request: {0!r}'.format(self.request))    '''*******************
# 4、msgpro/__init__.py
注意:
*******************'''       from __future__ import absolute_import, unicode_literals# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app__all__ = ('celery_app',)'''*******************
# 5、msgpro/settings.py
注意:celery 配置,缓存cache配置
*******************'''
# 静态文件
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'),
]# 媒体文件
MEDIA_ROOT = os.path.join(BASE_DIR, 'static/upload')# celery 配置
CELERY_BROKER_URL = 'redis://127.0.0.1:6379/0'
CELERY_RESULT_BACKEND = 'db+sqlite:///result.db'
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'# 缓存cache配置
CACHES = {# 使用数据库表缓存#   1. 创建缓存表: createcachetable cache_table#   2. 在settings中配置# 'default': {#     'BACKEND': 'django.core.cache.backends.db.DatabaseCache',#     'LOCATION': 'cache_table',#     'TIMEOUT': '60',#     'OPTIONS': {#         'MAX_ENTRIES': '300',#     },#     'KEY_PREFIX': 'QF',#     'VERSION': '1',# },# 使用redis缓存# 1. 安装插件:pip install django_redis# 2. 在settings中配置# 3. 启动redis服务: redis-server# 4. 启动redis客户端: redis-cli , 查看数据库1中的缓存内容."default": {"BACKEND": "django_redis.cache.RedisCache","LOCATION": "redis://127.0.0.1:6379/1","OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient",# "PASSWORD": "密码"},'KEY_PREFIX': 'HWM',}}    '''*******************
# 6、app/tasks.py
注意:在app里新增tasks.py
*******************'''   # Create your tasks herefrom __future__ import absolute_import, unicode_literalsimport randomimport requestsfrom celery import shared_taskfrom django.core.cache import cache@shared_taskdef send_sms(phone):url = "http://106.ihuyi.com/webservice/sms.php?method=Submit"account = "C89751406"  # APIIDpassword = "10f309b164c51af798ad77f794598292"  # APIkeyvcode = get_vcode()content = "您的验证码是:" + vcode + "。请不要把验证码泄露给其他人。"# 定义请求的头部headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "text/plain"}# 定义请求的数据data = {"account": account,"password": password,"mobile": phone,"content": content,}# 发起数据response = requests.post(url, headers=headers, data=data)# url 请求的地址# headers 请求头部# data 请求的数据# 设置缓存cache.set(phone, vcode, 300)print(response.content.decode())print(response.text)return response.text  # 响应数据# 随机验证码def get_vcode():vcode = ""for i in range(4):vcode += str(random.randint(0, 9))return vcode'''*******************
# 7、app/views.py
注意:在视图中验证
*******************'''
def login(request):if request.method == 'GET':return render(request, 'login.html')elif request.method == 'POST':phone = request.POST.get('phone')vcode = request.POST.get('vcode')print(phone, vcode)vcode2 = cache.get(phone)if vcode == vcode2:return HttpResponse('登录成功')else:return HttpResponse('验证码错误或已过期')def send_msg(request):phone = request.GET.get('phone')send_sms.delay(phone)print(phone)return HttpResponse('ok') 8、启动服务(django应用服务、celery服务与redis服务):django应用服务: python manage.py runservercelery服务 : celery -A proj worker -l info -P eventlet  # 注意: proj是工程名称启动redis服务 :redis-server启动redis客户端:redis-cli

七、日志输出

日志的作用1. 记录程序运行状态1. 线上环境所有程序以 deamon 形式运行在后台, 无法使用 print 输出程序状态2. 线上程序无人值守全天候运行, 需要有一种能持续记录程序运行状态的机制, 以便遇到问题后分析处理2. 记录统计数据 3. 开发时进行 Debug (调试)简单的使用:
'''*******************
# 1、log/log.py
注意:新建一个python文件
*******************'''
import logging
from logging import handlersdef set_log():# 设置日志格式fmt = '%(asctime)s %(levelname)7.7s %(funcName)s: %(message)s'formatter = logging.Formatter(fmt, datefmt="%Y-%m-%d %H:%M:%S")# 设置 handlerhandler = logging.handlers.TimedRotatingFileHandler('myapp.log', when='D', backupCount=30)handler.setFormatter(formatter)# 定义 logger 对象logger = logging.getLogger("MyApp")logger.addHandler(handler)logger.setLevel(logging.INFO)logger.info("hello")logger.error("报错了")if __name__ == '__main__':set_log()# 在当前目录下找到myapp.log文件,内容为# 2019-08-08 11:21:48    INFO <module>: hello# 2019-08-08 11:23:39    INFO set_log: hello1. 日志的等级- DEBUG: 调试信息- INFO: 普通信息- WARNING: 警告- ERROR: 错误- FATAL: 致命错误
2. 对应函数- logger.debug(msg)- logger.info(msg)- logger.warning(msg)- logger.error(msg)- logger.fatal(msg)
3. 日志格式允许的字段- %(name)s : Logger的名字- %(levelno)s : 数字形式的日志级别- %(levelname)s : 文本形式的日志级别- %(pathname)s : 调用日志输出函数的模块的完整路径名, 可能没有- %(filename)s : 调用日志输出函数的模块的文件名- %(module)s : 调用日志输出函数的模块名- %(funcName)s : 调用日志输出函数的函数名- %(lineno)d : 调用日志输出函数的语句所在的代码行- %(created)f : 当前时间, 用UNIX标准的表示时间的浮点数表示- %(relativeCreated)d : 输出日志信息时的, 自Logger创建以来的毫秒数- %(asctime)s : 字符串形式的当前时间。默认格式是“2003-07-08 16:49:45,896”。逗号后面的是毫秒- %(thread)d : 线程ID。可能没有- %(threadName)s : 线程名。可能没有- %(process)d : 进程ID。可能没有- %(message)s : 用户输出的消息4、django 配置输出日志
'''*******************
# 1、settings.py
注意:在settings.py里加入下面配置,然后
*******************'''
# 日志配置
LOGGING = {'version': 1,'disable_existing_loggers': True,# 格式配置'formatters': {'simple': {'format': '%(asctime)s %(module)s.%(funcName)s: %(message)s','datefmt': '%Y-%m-%d %H:%M:%S',},'verbose': {'format': ('%(asctime)s %(levelname)s [%(process)d-%(threadName)s] ''%(module)s.%(funcName)s line %(lineno)d: %(message)s'),'datefmt': '%Y-%m-%d %H:%M:%S',}},# Handler 配置'handlers': {'console': {'class': 'logging.StreamHandler','level': 'DEBUG' if DEBUG else 'WARNING'},'info': {'class': 'logging.handlers.TimedRotatingFileHandler','filename': f'{BASE_DIR}/logs/info.log',  # 正常日志保存路径'when': 'D',        # 每天切割日志'backupCount': 30,  # 日志保留 30天'formatter': 'simple','level': 'INFO',},'error': {'class': 'logging.handlers.TimedRotatingFileHandler','filename': f'{BASE_DIR}/logs/error.log',  # 错误日志保存路径'when': 'W0',      # 每周一切割日志'backupCount': 4,  # 日志保留 4 周'formatter': 'verbose','level': 'WARNING',}},# Logger 配置'loggers': {'django': {'handlers': ['console'],},'inf': {'handlers': ['info'],'propagate': True,'level': 'INFO',},'err': {'handlers': ['error'],'propagate': True,'level': 'WARNING',}}
}'''*******************
# 5、user/views.py
注意:创建正常日志对象(加载setting中的'inf'配置)
inf_logger
*******************'''
# 日志
import logging
inf_logger = logging.getLogger('inf')
# 注销
def logout(request):res = redirect(reverse('index'))# 日志:记录用户登录,退出inf_logger.info(f'{username}:登录成功!')return res'''*******************
# 6、middlewares/LogMiddleware.py
注意:通过aop中间件获取所有错误并记录到文件中
要在settings中注册中间件:
'middlewares.LogMiddleware.ErrorMiddleware',err_logger = logging.getLogger('err')  # 加载settings配置
err_logger.error(exception)  # 捕获错误
*******************''' from django.utils.deprecation import MiddlewareMixinimport logging
err_logger = logging.getLogger('err')class ErrorMiddleware(MiddlewareMixin):def process_exception(self, request, exception):print("=======>ErrorMiddleware=>process_exception")# 日志:记录异常err_logger.error(exception)

八、媒体文件云存储

1. 云存储- 常见的云存储有:亚马逊 S3 服务、阿里云的 OSS 、七牛云 等
2. 七牛云接入1. 注册七牛云账号2. 创建存储空间3. 获取相关配置- AccessKey- SecretKey- Bucket_name- Bucket_URL4. 安装 qiniu SDK:pip install qiniu5. 根据接口文档进行接口封装6. 按照需要将上传、下载接口封装成异步任务7. 程序处理流程1. 用户图片上传服务器2. 服务器将图片上传到七牛云3. 将七牛云返回的图片 URL 存入数据库
例:将用户注册时上传的头像进行云存储'''*******************
# 1、templates/register.html
注意:模板定义
<p>头像: <input type="file" name="icon"></p>
*******************'''    <form action="{% url 'register' %}" method="post" enctype="multipart/form-data">{% csrf_token %}<p>用户名:<input type="text" name="username"></p><p>密码:<input type="password" name="password"></p><p>年龄:<input type="number" name="age"></p><p>头像: <input type="file" name="icon"></p><p><input type="submit" value="注册"></p></form>    '''*******************
# 2、user/views.py
注意:视图定义register*******************'''
# 注册
def register(request):if request.method == 'GET':# 进入注册页面return render(request, 'register.html')elif request.method == 'POST':# 点击注册# 接收前端发送过来的数据username = request.POST.get('username')password = request.POST.get('password')age = request.POST.get('age')icon = request.FILES.get('icon')  # 头像# 注册前先判断:用户是否已经在users = UserModel.objects.filter(username=username)if users.exists():return HttpResponse('用户名已存在!')# 注册:给UserModel添加一条记录try:user = UserModel()user.username = username# user.password = hashlib.md5(password.encode()).hexdigest()  # md5加密user.password = make_password(password)  # 使用make_pasworduser.age = ageuser.save()# 上传头像到七牛云,并将云服务器头像地址存入数据库upload_icon(user, icon)except:return HttpResponse('注册失败!')# 注册成功后进入登录页面return redirect(reverse('login'))    '''*******************
# 3、user/logic.py
注意:云存储函数
user为app
*******************'''
AccessKey = 'fsxMbgIn0_V_9TNtYeju6BjvVIz7_0Sfy1qQd0GY'
SecretKey = 'JmgnEw-WzP3Jg0ynREh5aLmYseXqROXHxfuDtSAj'
Bucket_name = 'sz1904'
Bucket_URL = 'pvwoavyf8.bkt.clouddn.com'# 云存储
# 1. 先将前端的图片存入本地服务器
def save_icon(user, icon):file_name = 'icon-%d.png' % user.id  # 图片名称file_path = os.path.join(MEDIA_ROOT, file_name)  # 图片路径with open(file_path, 'ab') as fp:for part in icon.chunks():fp.write(part)fp.flush()return file_name, file_path# 2. 然后将本地服务器的图片再上传到七牛云
def upload_to_qiniu(file_name, file_path):# 构建鉴权对象q = Auth(AccessKey, SecretKey)# 生成上传 Token,可以指定过期时间等token = q.upload_token(Bucket_name, file_name, 3600)# 上传ret, info = put_file(token, file_name, file_path)print("保存到七牛云服务器:")print(info)print(ret)# 上传头像到七牛云
def upload_icon(user, icon):# 1. 先将前端的图片存入本地服务器file_name, file_path = save_icon(user, icon)# 2. 然后将本地服务器的图片再上传到七牛云upload_to_qiniu(file_name, file_path)# 3. 将七牛云存储空间中的图片地址存入数据库中# user.icon = "http://" + Bucket_URL + '/' + file_nameuser.icon = os.path.join('http://', Bucket_URL, file_name)user.save()

九、CBV类视图

'''*******************
# 1、App/views.py
注意:类视图的写法
View:在该类中没有实现任何请求的方法,如果继承该类需要定义各请求的方法以供调用TemplateView:
在TemplateView已经定义了get方法,指定template_name,
到时会自动回应get请求,其他请求还需定义ListView:继承BaseListView,有get方法DetailView:继承BaseDetailView,有get方法View类 => as_view方法()
在as_view方法()中又定义了一个view()方法,最后返回view() 的引用 (闭包)
在view()里调用dispatch()
在dispatch方法调用自定义的get、post、put等方法,如果未定义则返回405(不允许浏览器以某种方式访问)
*******************'''   # CBV
class Index2(View):# def get(self, request):#     name = request.GET.get('name')#     return HttpResponse('get=>获取数据:' + name)def post(self, request):name = request.POST.get('name')return HttpResponse('post=>新增数据' + name)def put(self, request):return HttpResponse('put=>修改数据')def delete(self, request):return HttpResponse('delete=>删除数据')# TemplateView(在TemplateView已经定义了get方法)
class UserTempalteView(TemplateView):# get请求template_name = 'template.html'def post(self, request):return HttpResponse('post')# ListView
class UserListView(ListView):template_name = 'list.html'model = UserModelcontext_object_name = 'users'# => return render(request, 'list.html', {'users': UserModel.objects.all()})# DetailView
class UserDetailView(DetailView):template_name = 'detail.html'model = UserModelcontext_object_name = 'user'# 接收url中path路径中的参数pk_url_kwarg = 'uid'# 给user动态添加属性def get_object(self, queryset=None):obj = super().get_object()obj.wechat = 'hello'return obj# 额外增加渲染数据def get_context_data(self, **kwargs):kwargs['qq'] = 1234return super().get_context_data(**kwargs)'''*******************
# 2、urls.py
注意:视图的写法
*******************'''   urlpatterns = [url(r'^admin/', admin.site.urls),# FBVurl(r'^index/$', index),# CBVurl(r'^index2/$', Index2.as_view()),url(r'^template/$', UserTempalteView.as_view()),url(r'^list/$', UserListView.as_view()),url(r'^detail/(?P<uid>\d+)/$', UserDetailView.as_view()),]

day05form验证、验证码、cache、cors与celery(任务队列)、CBV相关推荐

  1. Django 使用celery任务队列的配置

    celery 情景:用户发起request,并等待response返回.在本些views中,可能需要执行一段耗时的程序,那么用户就会等待很长时间,造成不好的用户体验,比如发送邮件.手机验证码等. 使用 ...

  2. 问答项目---登陆验证码点击切换及异步验证验证码

    输出验证方法: public function verify(){$config = array('length' => 2,'reset' => false,'useCurve' =&g ...

  3. 手机号获取验证码、验证验证码是否正确

    html: <div class="left_box lf"> <div class="menu"> <span style=&q ...

  4. 普歌-腾讯云短信+使用node发送短信(3种方法API、SDK)、封装工具、搭建web服务、写接口、调用接口发送短信、时效性判断、验证验证码的正确性(下)

    普歌-结合腾讯云短信服务+node搭建一个简单的发送短信web小项目 涉及技术: 腾讯云服务 后端服务:node+express 前端搭建:html+js 前言:本来这篇博客应该很早就发了,中间有一些 ...

  5. tp5 验证码验证 验证码刷新

    首先使用Composer安装think-captcha扩展包: composer require topthink/think-captcha 在控制器中使用下面的代码进行验证码生成: <?ph ...

  6. Spring Boot 配置Kaptcha(谷歌验证码工具)(生成验证码、验证验证码)

    1 Kaptcha 1.1 Kaptcha简介 Kaptcha 是一个扩展自simplecaptcha的验证码库,默认情况下,Kaptcha非常易于设置和使用,并且默认输出会产生一个很难验证的验证码. ...

  7. 邮箱验证(验证码验证)

    1.添加包 <!-- 邮箱 --> <dependency> <groupId>javax.mail</groupId> <artifactId& ...

  8. Jquery中的AJax技术结合PHP实现无刷新验证验证码

    Jquery中的Ajax在页面无刷新情况下实现验证码的验证 ①准备好的html文件,代码如下 <!DOCTYPE html> <html> <head><ti ...

  9. JQuery Ajax后台无刷新验证用户名重复,前台验证两次密码一致,后台创建并验证 验证码

    写在前面 写web 的人,我想最先要解决的就是注册登录的界面了,一个小小的界面却包含着各种基本的知识,让我这个新手摸了一天. 效果图 知识 1.bootstrap渲染表单 2.JQuery ajax验 ...

最新文章

  1. IntelliJ IDEA乱码问题解决方法
  2. HDFS设置配额管理
  3. 相关系数excel_跟着思想学外汇-如何用Excel计算货币相关性
  4. 验证用户身份Filter过滤器
  5. php定时某个时间循环做,PHP定时循环执行脚本
  6. Linux内核设计的艺术
  7. .net 注册引用的dll
  8. 保护隐私型浏览器Tor发布安卓试用版
  9. leetcode·动态规划
  10. ppt转html5原理,如何实现PPT转成H5?
  11. 那些简历造假拿 Offer 的程序员,后来都怎样了?
  12. Piranha介绍:过期代码自动删除的开源工具
  13. wordpress关闭所有文章评论
  14. 当520遇到MicroPython,单身极客狗也能很开“芯”~
  15. DolphinPHP 框架wangeditor编辑器图片路径改为绝对链接
  16. java secretkey用法_Java SecretKeyFactory.generateSecret方法代码示例
  17. Latex 中文简历 过程(更新Miktex和 修改utf字体)
  18. 张飞硬件MOSFET驱动电路_sdchguyi_新浪博客
  19. php支持postgresql,php支持postgresql
  20. 自行车 快拆应该锁多紧

热门文章

  1. ADB使用总结(内附ADB push apk过程)
  2. 出海品牌如何在YouTube上进行网红营销?
  3. P2P监管暂行办法正式发布(附全文)
  4. Codeforces 723F st-Spanning Tree(连通性乱搞)
  5. 国家对科技成果转化的政策
  6. lammps反应势Reaxff力场文件下载方法
  7. 美团五年来首次职级大调整,推行扁平化管理
  8. HTML5表格的设置
  9. 微信小程序—亲测仿真摇一摇功能的算法
  10. autoJS pro-手机自动化脚本基础小功能篇(截图、版本号、打印日志)