慕课DJANGO配置
重写内置的错误处理视图
在项目urls.py中添加配置 handler500 = "app01.views.page_500" handler404 = "app01.views.page_404" handler403 = "app01.views.page_403" 在项目视图中如下填写 from django.core.exceptions import PermissionDenied def test(request): # raise ValueError raise PermissionDenied return HttpResponse('ok') def page_500(request): return HttpResponse('500') def page_404(request): return HttpResponse('404') def page_403(request): return HttpResponse('403') 切换到生产模式DEBUG=False
STATIC处理静态文件
在项目settings.py中添加配置 STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, "static"), ]
在项目settings.py中添加配置 MEDIA_URL='/media/' MEDIA_ROOT=os.path.join(BASE_DIR,'medias') 在项目urls中添加配置 from django.views.static import serve from django.conf import settings urlpatterns += [ url(r'^medias/(?P<path>.*)$',serve,{ 'document_root':settings.MEDIA_ROOT, }), ]
请求对象HttpRequest
请求头信息META REMOTE_ADDR------请求的IP地址 HTTP_USER_AGENT-----用户请求终端信息
常见的Content-Type
text/html——超文本标记语言文本(HTML) text/plain——普通文本 text/xml——XML文档 image/png、image/jpeg、image/gif——图片或图形 application/json ——json数据类型
响应对象
HttpResponse
HttpResponseRedirect
JsonResponse——响应json
FileResponse——响应文件
HttpResponse
status查看HTTP响应状态码
status_code查看HTTP响应状态码
content_type设置响应的类型
write()写入响应内容
def content(request): dic = { 'username':'jamie', } # return HttpResponse('ok',content_type='text/plain') import json ret = json.dumps(dic) # return HttpResponse(ret,content_type='application/json') return JsonResponse(dic) def status(request): # 改变响应状态码 ret = HttpResponse('status_code', status=404) # 重新设置HTTP的状态码 ret.status_code = 200 # 打印HTTPS状态码 print(ret.status_code) # 写入响应内容 ret.write('多写入响应内容') return ret def image(request): # pring image import os from django.conf import settings try: file_name = os.path.join(settings.BASE_DIR,'medias/images/1111.png') f = open(file_name, 'rb') except Exception as e: print(e) return FileResponse(f,content_type='image/png') # application/vnd.ms-excel 这样可以导出EXCEL
使用CLASS重写视图
url(r'^class/',views.classview.as_view(), name='class'), from django.views.generic import TemplateView class classview(TemplateView): '''class''' template_name = 'class.html'
渲染机制
思考:没有模板引擎怎样在浏览器展示HTML
View Code
View Code
View Code
View Code
View Code
View Code
View Code
View Code
View Code
View Code
View Code
View Code
View Code
View Code
View Code
View Code
View Code
View Code
View Code
1. 从磁盘读取html字符串
2. 将满足特定规则的内容进行替换 3. 发送给浏览器展示
步骤一:从磁盘读取模板文件(get_template)
步骤二:选择合适的模板引擎(select_template)
步骤三:将制定内容对模板进行渲染(render)
步骤四:发送给浏览器显示
配置选项
APP_DIRS——决定模板引擎是否应该进入每个已安装 的应用中查找模板
每种模板引擎后端都定义了一个惯用的名称作为应用内部存放 模板的子目录名称
DTL——templates目录
Jinja2——jinja2目录
OPTIONS——其他选项配置
同时支持俩种引擎模板
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'mine.context_processors.const', ], }, }, { 'BACKEND': 'django.template.backends.jinja2.Jinja2', 'DIRS': [os.path.join(BASE_DIR, 'jiaja2')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
渲染静态图片
img_url = "/medias/images/1111.png" return render(request,'image1.html',{'img_url':img_url}) <img src="{{ img_url }}" alt="403报错图片">
模板标签的使用
循环控制 {% for item in data_list %} <li>内容</li> {% endfor %} 条件控制 {% if condition_a %} 满足了A条件 {% elif condition_b %} 满足了B条件 {% else %} 都不满足 {% endif %}
注释
添加注释 {# 注释内容 #} 与HTML注释的区别 <!-- 注释内容 -->
重复循环
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .row1 { background-color: pink; } .row2 { background-color: red; } .row3 { background-color: gray; } </style> </head> <body> <ul> {% for foo in tag reversed%} <li class="{% cycle 'row1' 'row2' 'row3' %}">{{ forloop.counter }}{{ foo }}</li> {% empty %} <li>列表要是空就走这里</li> {% endfor %} </ul> </body> </html>
过滤器:对变量进行特殊处理后再渲染?
过滤器语法 {{ value|filter_name: params }} 使用过滤器将字母大写 {{ value|upper}}
内置过滤器
def test_tp_filter(request): import math pi = math.pi html = '<h1>lalalalalalalalala</h1>' import datetime time = datetime.datetime.now() user_info = { 'username': 'jamie', 'age': None, 'sex': False, 'pi': pi, 'html': html, 'time': time } return render(request, 'filter.html', {'userinfo': user_info})
日期对象格式化 {{ value|date:"D d M Y" }} 默认值显示 {{ value|default:"" }} # 为none时候显示我 {{ value|default_if_none:“无" }} # 为空false显示我 数字四舍五入显示 {{ value | floatformat:3 }} 富文本内容转义显示 {{ value|safe }} 字符串截取 {{ value|truncatechars:9 }} {{ value|truncatechars_html:9 }} # 不算Html字符 {{ value|truncatewords:2 }}
自定义过滤器
步骤一:在app目录下新建包templatetags polls/ __init__.py models.py templatetags/ __init__.py poll_extras.py views.py 步骤二:实现过滤器poll_filter.py from django import template register = template.Library() def warning(value): """ 将第一个字符变红 """ return '<span class="red">' + value[0] +'</span>'+ value[1:] register.filter('warning', warning) 步骤三:在模板中使用过滤器 {% load poll_filter %} {{ value| warning|safe }} 切记:添加自定义过滤器后记得重启开发服务器
模板抽象和继承
步骤一:将可变的部分圈出来(base.html) {% block sidebar %} <!--菜单栏的内容 --> {% endblock %} 步骤二:继承父模板 {% extends "base.html" %} 步骤三:填充新的内容(index.html) {% extends "base.html" %} {% block sidebar %} <!-- 新的菜单栏的内容 --> {% endblock %} 步骤四:复用父模板的内容(可选) {% extends "base.html" %} {% block sidebar %} {{ supper }} <!-- 新的菜单栏的内容 --> {% endblock %}
在模板中添加公共部分
步骤一:将可变的部分拆出来(footer.html) <footer> 这是页脚公共的部分 </footer> 步骤二:将拆出来的部分包进来(index.html) {% extends "base.html" %} {% block content %} <!– 页面主要内容区域--> {# 公用的footer #} {% include "footer.html" %} {% endblock %}
Django工具及管理
常用的内置命令(mine是一个app应用)
检查djangoORM模型
python manage.py check
生成同步原语
python manage.py makemigrations
模型同步
python manage.py migrate
收集依赖中的静态文件
python manage.py collectstatic
django控制台
python manage.py shell
清除过期会话
python manage.py clearsessions
自定义Django命令行工具
第一步:创建指定的目录及文件结构 mine/ __init__.py models.py management/ __init__.py commands/ __init__.py update.py urls.py views.py 第二步:实现自定义命令 实现django.core.management.base.BaseCommand的子类 添加命令参数add_arguments 处理命令逻辑handle 显示处理过程(self.stdout.write/self.stderr.write) """ update.py 更新订单状态 订单超过半小时不支付,取消订单,释放库存 """ from django.core.management.base import BaseCommand class Command(BaseCommand): help = """ 更新订单状态 回收订单 """ def add_arguments(self, parser): """ 添加命令的参数 argparse https://docs.python.org/3/library/argparse.html 1. 回收所有超时未支付的订单 python manage.py update --all 2. 指定回收某一个订单 python manage.py update --one 20001 :param parser: :return: """ # 添加参数 dest匹配参数,交给handel处理, parser.add_argument( '--all', # 不需要加参数的意思,但是还没确定 action='store_true', dest='all', default=False, help='回收所有超时未支付的订单' ) parser.add_argument( '--one', action='store', dest='one', default=False, help='指定回收某一个订单' ) def handle(self, *args, **options): if options['all']: self.stdout.write('开始回收订单') # 逻辑处理 self.stdout.write('-------') self.stdout.write('处理完成') elif options['one']: self.stdout.write('开始回收订单{}'.format(options['one'])) else: self.stderr.write('指令异常')
Django中间件的开发和使用
上下文处理器,为模板添加全局变量,utils是创建在项目里面的公用脚本目录
渲染上下文Context 请求上下文RequestContext 连接views(视图)和templates(模板) 场景举例: 在每个页面都显示IP地址,多个页面展示购物车信息 TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'mine.context_processors.const', # 这里定义上下文的路径 ], }, }, ] from utils import constants def const(request): addr = '湖南' return { 'constants': constants.UserList, 'addr':addr, } # Utils是个创建在项目下的目录 # !/usr/bin/env python # _*_ coding:utf-8 _*_ # Author: Jamie UserList = ['吊哥','傻逼'] 模板调用 {% for foo in constants %} {{ foo }} {% endfor %} {{ addr }}
中间件,过滤请求,拦截请求
场景1:用户非法请求拦截 添加IP地址黑名单,在名单内的用户限制访问 场景2:模拟用户登录 实现简单的用户登录中间件 步骤一:实现中间件,处理业务逻辑 方式1:函数式自定义中间件 方式2: OOP(面向对象)自定义中间件 步骤二:激活中间件,添加到setting.py配置 ''' 保存在Utils目录里面,公共方法,ip_middleware.py ''' from django.http import HttpResponse from weibo.models import WeiboUser def ip_middleware(get_response): def middleware(request): # 请求到达前的业务逻辑 print('请求到达前的业务逻辑') # 请求不满足业务规则:IP被限制 ip = request.META.get('REMOTE_ADDR', None) ip_disable_list = [ '127.0.0.1' ] print(ip) # for ip_dis in ip_disable_list: # if ip_dis == ip: if ip in ip_disable_list: return HttpResponse('not allowed', status=403) reponse = get_response(request) # 在视图函数调用之后的业务逻辑 print('在视图函数调用之后的业务逻辑') return reponse return middleware class MallAuthMiddleware(object): """ 自定义的登录验证中间件 """ def __init__(self, get_response): self.get_response = get_response def __call__(self, request, *args, **kwargs): print('MallAuthMiddleware请求到达前的业务逻辑') # 请求不满足业务规则:IP被限制 user_id = request.session.get('user_id', None) print('middle:%s' %user_id) if user_id: user = WeiboUser.users.get(pk=user_id) else: user = None request.my_user = user print('--------------', user) reponse = self.get_response(request) # 在视图函数调用之后的业务逻辑 print('MallAuthMiddleware在视图函数调用之后的业务逻辑') return reponse MIDDLEWARE = [ # 'debug_toolbar.middleware.DebugToolbarMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', # 'utils.middleware.ip_middleware', 'utils.middleware.MallAuthMiddleware' ]
另一篇实例 https://www.cnblogs.com/jokerbj/p/8173820.html
Django扩展
DRF(Django REST Framework)REST接口框架 django-cms 内容管理系统 django-debug-toolbar 调试工具 pypi.org搜索,要对应JDANGO版本 django-channels Websocket通信
表单重复提交
支付时,快速点击,多次提交会有什么问题? csfttoken
View Code
View Code
BUG邮件通知
1.发送文字邮件 2.发送HTML邮件 3.发送带附件的邮件 4.发送多个邮件 5.打破连接限制,连接复用 第一步:邮件配置 第二步:准备邮件内容 第三步:发送邮件 ''' SETTINGS.PY ''' # 邮件发送配置 EMAIL_HOST = 'smtp.qq.com' EMAIL_HOST_USER = 'navcat@foxmail.com' EMAIL_HOST_PASSWORD = 'vgppwryinupwbfgb' # 自己发送,from django.core.mail import send_mail send_mail(邮件主题,邮件内容,发件人,发送给谁,是个列表) # 触发异常就会给ADMINS发邮件,DEBUG = False SERVER_EMAIL = 'navcat@foxmail.com' ADMINS = [('admin', 'navcat@foxmail.com')]
https://docs.djangoproject.com/en/1.11/topics/email/
日志记录配置
logging的四个部分 1.Loggers——日志记录入口 2.Handlers——决定处理logger中消息的方式 3.Filters——对日志进行条件控制 4.Formatters——日志记录的文本顺序(格式) Logger的级别 DEBUG:用于调试目的的底层系统信息 INFO:普通的系统信息 WARNING:警告,较小的问题,不影响执行顺序 ERROR:错误,较大的问题 CRITICAL:严重,致命的问题 ''' SETTINGS.PY ''' # 日志的配置 LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'verbose': { 'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s' }, 'simple': { 'format': '%(levelname)s %(message)s' }, }, 'handlers': { 'sql_log_file': { 'level': 'DEBUG', 'class': 'logging.FileHandler', 'filename': os.path.join(BASE_DIR, 'log/sql.log'), }, 'log_index_file': { 'level': 'DEBUG', 'class': 'logging.FileHandler', 'formatter': 'verbose', 'filename': os.path.join(BASE_DIR, 'log/index.log'), }, 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', # 'formatter': 'simple' }, 'mail_admins': { 'level': 'ERROR', 'class': 'django.utils.log.AdminEmailHandler', # 'filters': ['special'] } }, 'loggers': { 'django.db.backends': { 'handlers': ['sql_log_file',], 'level': 'DEBUG', 'propagate': True, }, 'index': { 'handlers': ['log_index_file', 'console'], 'level': 'DEBUG', } }, }
上传图片方式
# !/usr/bin/env python # _*_ coding:utf-8 _*_ # Author: Jamie import re from django import forms from weibo import models class UserLoginForm(forms.Form): username = forms.CharField(label='用户名',max_length=64) password = forms.CharField(label='密码',max_length=64,widget=forms.PasswordInput) verify_code = forms.CharField(label='验证码',max_length=64) def clean_username(self): username = self.cleaned_data['username'] pattern = r'^0{0,1}1[0-9]{10}$' if not re.search(pattern,username): raise forms.ValidationError('请输入正确的手机号码') return username def clean(self): cleand_data = super().clean() username = cleand_data.get('username',None) password = cleand_data.get('password',None) if username and password: user_list = models.WeiboUser.users.filter(username=username) if user_list.count() == 0: raise forms.ValidationError('用户名不存在') if not user_list.filter(password=password).exists*(): raise forms.ValidationError('密码错误') return cleand_data class UserForm(forms.ModelForm): class Meta: model = models.WeiboUser fields = ['username','password'] widgets = { 'password':forms.PasswordInput(attrs={ 'class':'text-error', }) } labels = { 'username':'手机号码', } error_messages = { 'username':{ 'required':'请输入手机号码', 'max_length':'最长不超过32', } } class AvatarUploadForm(forms.Form): remark = forms.CharField(label='备注',max_length=32) touxiang = forms.FileField(label='头像') class WeiboImageForm(forms.ModelForm): content = forms.CharField(label='微博内容',max_length=256,widget=forms.Textarea(attrs={'placeholder':'请输入微博内容'})) class Meta: model = models.WeiboImage fields = ['image'] def save(self,user,commit=False): obj = super().save(commit) data = self.cleaned_data content = self.cleaned_data['content'] #1 创建微博记录 weibo = models.Weibo.objects.create(user=user,content=content) #2 修改微博关联关系 obj.weibo = weibo obj.save() return obj
def upload_one(request): if request.method == 'POST': file = request.FILES.get('touxiang',None) import os from dalaohu import settings filename = os.path.join(settings.MEDIA_ROOT,'touxiang') with open(filename,'wb+') as f: for i in file.chunks(): f.write(i) print('上传陈功了') return render(request,'upload_one.html') def upload_two(request): if request.method == 'POST': form = forms.AvatarUploadForm(request.POST,request.FILES) if form.is_valid(): file = request.FILES.get('touxiang', None) import os from dalaohu import settings filename = os.path.join(settings.MEDIA_ROOT, 'touxiang1') with open(filename, 'wb+') as f: for i in file.chunks(): f.write(i) print('上传陈功了') else: form = forms.AvatarUploadForm() return render(request,'upload_two.html',{'form':form}) def upload_three(request): if request.method == 'POST': user = WeiboUser.users.get(pk=1) form = forms.WeiboImageForm(request.POST,request.FILES) if form.is_valid(): obj = form.save(user,False) print('保存陈功了',obj.pk) else: form = forms.WeiboImageForm() return render(request,'upload_three.html',{ 'form':form })
自带登录验证
import re from django import forms from django.forms import widgets from django.forms import fields from django.contrib.auth import authenticate, login from django.contrib.auth.models import User from utils.verify import VerifyCode class UserLoginForm(forms.Form): """ 用户登录表单 """ username = forms.CharField(label='用户名', max_length=64,widget=widgets.TextInput(attrs={'class':'form-control','placeholder':'请输入用户名'}), error_messages={ 'required': '请输入用户名', } ) password = forms.CharField(label='密码', max_length=64,widget=widgets.PasswordInput(attrs={'class':'form-control','placeholder':'请输入密码'}), error_messages={ 'required': '请输入密码', }) verify_code = forms.CharField(label='验证码', max_length=4,widget=widgets.TextInput(attrs={'class':'form-control','placeholder':'验证码'}), error_messages={ 'required': '请输入验证码', }) def __init__(self, request, *args, **kwargs): super().__init__(*args, **kwargs) self.request = request # def clean_username(self): # """ 验证用户名 hook 钩子函数""" # username = self.cleaned_data['username'] # print(username) # # 判断用户名是否为手机号码 # pattern = r'^0{0,1}1[0-9]{10}$' # if not re.search(pattern, username): # raise forms.ValidationError('请输入正确的手机号码') # return username def clean_verify_code(self): """ 验证用户输入的验证码是否正确 """ verify_code = self.cleaned_data['verify_code'] if not verify_code: raise forms.ValidationError('请输入验证码') client = VerifyCode(self.request) if not client.validate_code(verify_code): raise forms.ValidationError('验证码不正确') return verify_code def clean(self): cleaned_data = super().clean() print(cleaned_data) # 获取用户名和密码 ,不建议使用[]的方式 # username = cleaned_data['username'] username = cleaned_data.get('username', None) password = cleaned_data.get('password', None) if username and password: # 查询用户名和密码匹配的用户 user_list = User.objects.filter(username=username) if user_list.count() == 0: raise forms.ValidationError('用户名不存在') # # 验证密码是否正确 # if not user_list.filter(password=password).exists(): # raise forms.ValidationError('密码错误') if not authenticate(username=username, password=password): raise forms.ValidationError('密码错误') return cleaned_data class UserRegistForm(forms.Form): """ 用户注册表单 """ username = forms.CharField(label='用户名', max_length=64) nickname = forms.CharField(label='昵称', max_length=64) password = forms.CharField(label='密码', max_length=64, widget=forms.PasswordInput) password_repeat = forms.CharField(label='重复密码', max_length=64, widget=forms.PasswordInput) verify_code = forms.CharField(label='验证码', max_length=4) def __init__(self, request, *args, **kwargs): super().__init__(*args, **kwargs) self.request = request def clean_username(self): """ 验证用户名是否已经被注册 """ data = self.cleaned_data['username'] if User.objects.filter(username=data).exists(): raise forms.ValidationError('用户名已存在') return data def clean_verify_code(self): """ 验证用户输入的验证码是否正确 """ verify_code = self.cleaned_data['verify_code'] if not verify_code: raise forms.ValidationError('请输入验证码') client = VerifyCode(self.request) if not client.validate_code(verify_code): raise forms.ValidationError('您输入的验证码不正确') return verify_code def clean(self): cleaned_data = super().clean() password = cleaned_data.get('password', None) password_repeat = cleaned_data.get('password_repeat', None) if password and password_repeat: if password != password_repeat: raise forms.ValidationError('两次密码输入不一致') return cleaned_data def register(self): """ 注册方法 """ data = self.cleaned_data # 1. 创建用户 User.objects.create_user(username=data['username'], password=data['password'], level=0, nickname='昵称') # 2. 自动登录 user = authenticate(username=data['username'], password=data['password']) login(self.request, user) return user
from django.contrib.auth import authenticate, login, logout from utils.verify import VerifyCode from weibo.forms import UserLoginForm,UserRegistForm from django.contrib.auth.models import User def user_add(request): '''创建用户''' user = User.objects.create_user('liqianlong','lal@126.com',123456) return HttpResponse('创建账号成功') def user_login1(request): """ 用户登录 """ # 如果登录是从其他页面跳转过来的,会带next参数,如果有next参数,登录完成后,需要调转到 # next所对应的地址,否则,跳转到首页上去 next_url = request.GET.get('next', 'weibo:index') if request.method == 'POST': form = UserLoginForm(request=request, data=request.POST) # print(request.POST) # client = VerifyCode(request) # code = request.POST.get('verify_code', None) # rest = client.validate_code(code) # print('验证结果:', rest) # 表单是否通过了验证 if form.is_valid(): # 执行登录 data = form.cleaned_data # ## 使用自定义的方式实现登录 # # 查询用户信息 [MD5]加密算法,不可逆的加密算法 1243 -> sdfadfad # user = User.objects.get(username=data['username'], password=data['password']) # # 设置用户ID到session # request.session[constants.LOGIN_SESSION_ID] = user.id # # 登录后的跳转 # return redirect('index') ### 使用django-auth来实现登录 user = authenticate(request, username=data['username'], password=data['password']) print('view:%s' %user.id) if user is not None: ### 为了测试自定义中间件加的session request.session['user_id'] = user.id login(request, user) # 登录后的跳转 return redirect(next_url) else: print(form.errors) else: form = UserLoginForm(request) return render(request, 'login.html', {'form': form,'next_url':next_url}) def user_logout(request): """ 用户退出登录 """ logout(request) return redirect('weibo:user_login1') import logging logger = logging.getLogger('index') logger.debug('调试信息') logger.info('普通信息') logger.error("异常") @login_required def index(request): # 记录调试信息 print('登录成功,打开首页',request.my_user) return render(request,'wbindex.html') def user_register(request): """ 用户注册 """ if request.method == 'POST': form = UserRegistForm(request=request, data=request.POST) if form.is_valid(): # 调用注册方法 form.register() return redirect('index') else: print(form.errors) else: form = UserRegistForm(request=request) return render(request, 'register.html', { 'form': form }) def code(request): client = VerifyCode(request) return client.gen_code()
# 用户登录 url(r'^user/user_add/$', views.user_add, name='user_add'), url(r'^user/login/$', views.user_login1, name='user_login1'), # 用户退出 url(r'^user/logout/$', views.user_logout, name='user_logout'), # 用户注册 url(r'^user/register/$', views.user_register, name='user_register'), # 验证码 url(r'^user/code/$', views.code, name='verify_code'), # index url(r'^user/index/$', views.index, name='index'),
""" 生成验证码: 1. 准备素材 字体(ttf),文字内容,颜色,干扰线 2. 画验证码 pip install Pillow 、random 创建图片 记录文字内容,django session【服务器,python代码】 abcdefg cookie 【浏览器】 (1) 第一次请求,cookie + session 对应关系生成 (2) 第二次请求,携带了cookie,找到对应的session【提交表单】 请求带上验证码参数 与 session中的验证码进行比较 3. io文件流 BytesIO """ import random import os from PIL import Image, ImageDraw, ImageFont from django.conf import settings from io import BytesIO from django.http import HttpResponse class VerifyCode(object): """ 验证码类 """ def __init__(self, dj_request): self.dj_request = dj_request # 验证码长度 self.code_len = 4 # 验证码图片尺寸 self.img_width = 100 self.img_height = 30 # django中session的名称 self.session_key = 'verify_code' def gen_code(self): """ 生成验证码 """ # 1. 使用随机数生成验证码字符串 code = self._get_vcode() # 2. 把验证码存在的session self.dj_request.session[self.session_key] = code # 3. 准备随机元素(背景颜色、验证码文字的颜色、干扰线、) font_color = ['black', 'darkblue', 'darkred', 'brown', 'green', 'darkmagenta', 'cyan', 'darkcyan'] # RGB随机背景色 bg_color = (random.randrange(230, 255), random.randrange(230, 255), random.randrange(230, 255)) # 字体路径 font_path = os.path.join(settings.BASE_DIR, 'medias', 'fonts', 'timesbi.ttf') # 创建图片 im = Image.new('RGB', (self.img_width, self.img_height), bg_color) draw = ImageDraw.Draw(im) # 画干扰线 # 随机条数,到底画几条 for i in range(random.randrange(1, int(self.code_len / 2) + 1)): # 线条的颜色 line_color = random.choice(font_color) # 线条的位置 point = ( random.randrange(0, self.img_width * 0.2), random.randrange(0, self.img_height), random.randrange(self.img_width - self.img_width * 0.2, self.img_width), random.randrange(0, self.img_height)) # 线条的宽度 width = random.randrange(1, 4) draw.line(point, fill=line_color, width=width) # 画验证码 for index, char in enumerate(code): code_color = random.choice(font_color) # 指定字体 font_size = random.randrange(15, 25) font = ImageFont.truetype(font_path, font_size) point = (index * self.img_width / self.code_len, random.randrange(0, self.img_height / 3)) draw.text(point, char, font=font, fill=code_color) buf = BytesIO() im.save(buf, 'gif') return HttpResponse(buf.getvalue(), 'image/gif') def _get_vcode(self): random_str = 'ABCDEFGHIGKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789' code_list = random.sample(list(random_str), self.code_len) code = ''.join(code_list) return code def validate_code(self, code): """ 验证验证码是否正确 """ # 1. 转变大小写 code = str(code).lower() vcode = self.dj_request.session.get(self.session_key, '') # if vcode.lower() == code: # return True # return False return vcode.lower() == code # if __name__ == '__main__': # client = VerifyCode(None) # client.gen_code()
其他settings配置
# orm时间查询时候要是false USE_TZ = False # 使用自定义模型的时候,当没有经过验证就会走这里 LOGIN_URL = '/weibo/user/login/' # CSRF 跨站请求伪造的另一个种解决方法,这样相当于植入到COOKIE中,模板通过jquery.cookie可以获取到 CSRF_USE_SESSIONS=False
文件备份脚本
import os import os.path class FileBackup(object): """ 文本文件备份 """ def __init__(self, src, dist): """ 构造方法 :param src: 目录 需要备份的文件目录 :param dist: 目录 备份后的目录 """ self.src = src self.dist = dist def read_files(self): """ 读取src目录下的所有文件 """ ls = os.listdir(self.src) print(ls) for l in ls: # 循环处理每一个文件/文件夹 # self.backup_file(l) self.backup_file2(l) def backup_file(self, file_name): """ 处理备份 :param file_name: 文件/文件夹的名称 """ # 1. 判断dist是否存在,如果不存在,要创建这个目录 if not os.path.exists(self.dist): os.makedirs(self.dist) print('指定的目录不存在,创建完成') # 2. 判断文件是否为我们要备份的文件 # 拼接文件的完整路径 full_src_path = os.path.join(self.src, file_name) full_dist_path = os.path.join(self.dist, file_name) # 首先要判断是否为文件夹,然后借助于文件的后缀名进行判断 if os.path.isfile(full_src_path) and os.path.splitext(full_src_path)[-1].lower() == '.txt': print(full_src_path) # 3. 读取文件内容 with open(full_dist_path, 'w', encoding='utf-8') as f_dist: print('>> 开始备份【{0}】'.format(file_name)) with open(full_src_path, 'r', encoding='utf-8') as f_src: while True: rest = f_src.read(100) if not rest: break # 4. 把读取到的内容写入到新的文件中 f_dist.write(rest) f_dist.flush() print('>>> 【{0}】备份完成'.format(file_name)) else: print('文件类型不符合备份要求,跳过>>') def backup_file2(self, file_name): """ 处理备份-优化版本 :param file_name: 文件/文件夹的名称 """ # 1. 判断dist是否存在,如果不存在,要创建这个目录 if not os.path.exists(self.dist): os.makedirs(self.dist) print('指定的目录不存在,创建完成') # 2. 判断文件是否为我们要备份的文件 # 拼接文件的完整路径 full_src_path = os.path.join(self.src, file_name) full_dist_path = os.path.join(self.dist, file_name) # 首先要判断是否为文件夹,然后借助于文件的后缀名进行判断 if os.path.isfile(full_src_path) and os.path.splitext(full_src_path)[-1].lower() == '.txt': # 3. 读取文件内容 with open(full_dist_path, 'w', encoding='utf-8') as f_dist, \ open(full_src_path, 'r', encoding='utf-8') as f_src: print('>> 开始备份【{0}】'.format(file_name)) while True: rest = f_src.read(100) if not rest: break # 4. 把读取到的内容写入到新的文件中 f_dist.write(rest) f_dist.flush() print('>>> 【{0}】备份完成'.format(file_name)) else: print('文件类型不符合备份要求,跳过>>') if __name__ == '__main__': # # 要备份的文件目录地址 # src_path = 'C:\\Users\\yima1\\Desktop\\py_learn\\chapter04\\src' # # 备份后的目录地址 # dist_path = 'C:\\Users\\yima1\\Desktop\\py_learn\\chapter04\\dist' # 当前代码的目录名称 # C:\Users\yima1\Desktop\py_learn\chapter04\ test_backup.py base_path = os.path.dirname(os.path.abspath(__file__)) # 要备份的文件目录地址 src_path = os.path.join(base_path, 'src') print(src_path) # 备份后的目录地址 dist_path = os.path.join(base_path, 'dist') print(dist_path) bak = FileBackup(src_path, dist_path) bak.read_files() BACKUPFILE