Django扩展 一、验证码 1、简介 在常规的Form表单使用中,验证码是常用的组件,用于更好的保障请求的合法性,防止无效访问,恶意访问,暴力破解等攻击
在服务器端,生成一个随机的code:“aecd1” ,将code画到一张图片中,最终将图片写出给client。
注意:依赖第三方包:pillow
pip install pillow
2、验证码使用过程 2.1 导入第三方库 将文件拷贝到自己的项目app中,2个py文件,1个data文件夹,保证三个处于项目中的统一个目录中。
2.2 生成验证码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import random,stringfrom captcha.image import ImageCaptcha def getcaptcha (request ): image = ImageCaptcha(fonts=[os.path.abspath("xxx/segoesc.ttf" )]) code = random.sample(string.ascii_lowercase+string.ascii_uppercase+string.digits,5 ) random_code = "" .join(code) request.session['code' ]=random_code data = image.generate(random_code ) return HttpResponse(data,"image/png" )
2.3 在html中使用验证码 1 2 3 4 5 6 7 8 9 10 11 <input type ="text" name ="identifycode" > <img src ="{% url 'identify_demo:getcaptcha' %}" id ="image_code" width ="80px" height ="30px" align ="center" > <a href ="javascript:void(0)" onclick ="change()" > 换一张</a > <script > function change ( ) { var url = "{% url 'identify_demo:getcaptcha' %}?" +new Date ().getTime () $('#image_code' ).attr ('src' ,url) } </script >
2.4 验证是否正确 1 2 3 4 5 6 def registlogic (request ): code = request.session.get('code' ) if code.lower() == request.POST.get('identifycode' ).lower(): return HttpResponse("成功" ) else : return HttpResponse("失败" )
二、文件上传 1、简介 Django的模型类(django.db.models.Model)提供了两个字段FileField和ImageField用于上传文件和图片。而ImageField继承之FileField,class ImageField(FileField):
使用Django的ImageField需要提前安装pillow 模块,pip install pillow 即可。
2、使用步骤 使用FileField或者ImageField字段的步骤:
在settings文件中,配置MEDIA_ROOT ,作为你上传文件在服务器中的基本路径。
添加FileField或者ImageField字段到模型中,定义好upload_to参数,文件最终会放在MEDIA_ROOT目录的“upload_to”子目录中。
所有真正被保存在数据库中的,只是指向你上传文件路径的字符串而已。可以通过url属性,在Django的模板中方便的访问这些文件。例如,假设有一个ImageField字段,名叫mug_shot,那么在Django模板的HTML文件中,可以使用来获取该文件。
可以通过name和size属性,获取文件的名称和大小信息。
3、实例:为用户上传头像 3.1 设置文件保存目录 1 2 3 MEDIA_ROOT = os.path.join(BASE_DIR,"media" )
3.2 定义Model 1 2 3 4 class User (models.Model): name = models.CharField(max_length=20 ) pic = models.ImageField(upload_to="pics" )
注意:定义好Model,记得生成移植文件并执行
1 2 3 4 5 6 <form action ="{% url 'uploadfile_demo:uplogic' %}" method ="post" enctype ="multipart/form-data" > {% csrf_token %} 用户名:<input type ="text" name ="name" > <br > 头像:<input type ="file" name ="source" > <input type ="submit" value ="提交" > </form >
3.4 定义view函数 1 2 3 4 5 6 7 8 9 10 def uplogic (request ): try : name = request.POST.get('name' ) file = request.FILES.get('source' ) file.name = generateUUID(file.name) user = User.objects.create(name=name, pic=file) return HttpResponse("上传成功" ) except : return HttpResponse("上传失败" )
1 2 3 4 5 import uuid,osdef generateUUID (filename ): id = str (uuid.uuid4()) extend = os.path.splitext(filename)[1 ] return id +extend
注意,此时数据库中存储的路径是相对于MEDIA_ROOT的路径
所以可以将MEDIA_ROOT设置为静态资源根目录,可便于后续的头像回显
3.5 回显图片
设置静态资源根目录
1 2 3 4 MEDIA_ROOT = os.path.join(BASE_DIR,'media' ) STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static' ), MEDIA_ROOT ]
view函数
1 2 3 def query (request ): users = User.objects.all () return render(request,'uploadfile_demo/detail.html' ,{'users' :users})
模板中使用
1 2 3 {% load static %} <img src="{% static user.headpic.url %}" width="50px">
补充: Python原生文件操作
1 2 3 4 5 6 7 8 9 10 11 def test_upload2 (r ): import os,uuid b = r.FILES.get("source" ) unique_name = str (uuid.uuid4()) ext = os.path.splitext(b.name)[1 ] name = unique_name + ext with open (file=os.path.join(os.path.abspath("media/just_test/" ),name),mode="wb" ) as output: for chunk in b.chunks(): output.write(chunk) return HttpResponse("ok" )
三、分页显示 1、简介 Django自身提供了一些类来实现管理分页,数据被分在不同的页面中,并带有“上一页/下一页”标签。这个类叫做Pagination,其定义位于 django/core/paginator.py 中。
2、Paginator分页器 2.1 初始化方法 pagtor = Paginator(User.objects.all(),per_page=3)
# 构造分页器对象
1 2 3 4 5 6 7 8 9 10 class Paginator (object ): def __init__ (self, object_list, per_page, orphans=0 , allow_empty_first_page=True ): self.object_list = object_list self.per_page = int (per_page) self.orphans = int (orphans) self.allow_empty_first_page = allow_empty_first_page self._num_pages = self._count = None
2.2 属性
Paginator.count:所有页面对象总数,即统计object_list中item数目。
Pagnator.num_pages:页面总数。
pagiator.page_range:页面范围,从1开始,例如[1,2,3,4]。
1 2 3 4 pagtor = Paginator(User.objects.all (),per_page=3 ) print (pagtor.count) print (pagtor.num_pages) print (pagtor.page_range)
2.3 page方法(重点) Paginator.page(number):根据参数number返回一个Page对象,表示第number页。
1 page = Paginator(User.objects.all (),per_page=3 ).page(1 )
3、Page对象 1 2 3 4 5 6 class Page (collections.Sequence ): def __init__ (self, object_list, number, paginator ): self.object_list = object_list self.number = number self.paginator = paginator
3.1 方法
Page.has_next
() 如果有下一页,则返回True
。
Page.has_previous
() 如果有上一页,返回 True
。
Page.has_other_pages
() 如果有上一页或下一页,返回True
。
Page.next_page_number
() 返回下一页的页码。如果下一页不存在,抛出InvlidPage
异常。
Page.previous_page_number
() 返回上一页的页码。如果上一页不存在,抛出InvalidPage异常。
Page.start_index
() 返回当前页上的第一个对象,相对于分页列表的所有对象的序号,从1开始。比如,将五个对象的列表分为每页两个对象,第二页的start_index()
会返回3
。
Page.end_index
() 返回当前页上的最后一个对象,相对于分页列表的所有对象的序号,从1开始。 比如,将五个对象的列表分为每页两个对象,第二页的end_index()
会返回 4
。
3.2 属性
Page.object_list
当前页上所有对象的列表。
Page.number
当前页的序号,从1开始。
Page.paginator
相关的Paginator
对象。
4、实例 4.1 简单分页 1 2 3 4 5 6 def index (request ): number = request.GET.get('num' ) pagtor = Paginator(User.objects.all (),per_page=4 ) page = pagtor.page(number) return render(request,'page_demo/index.html' ,{'page' :page})
1 2 3 4 5 { {% for user in page.object_list %} {{ user.id }} -- {{ user.name }} -- {{ user.password }} <br> {% endfor %}
4.2 输出序号 1 2 3 4 5 6 7 8 9 10 { {% for user in page.object_list %} {{ user.id }} -- {{ user.name }} -- {{ user.password }} <br> {% endfor %} { {% for page_num in page.paginator.page_range %} <a href="/page/index/?num={{ page_num }}" >{{ page_num }}</a> {% endfor %}
4.3 显示上一页/下一页 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 {% for user in page.object_list %} {{ user.id }} -- {{ user.name }} -- {{ user.password }} <br> {% endfor %} {% if page.has_previous %} { <a href="/page/index/?num={{ page.previous_page_number }}" >上一页</a> {% endif %} {% for num in page.paginator.page_range %} <a href="/page/index/?num={{ num }}" >{{ num }}</a> {% endfor %} {% if page.has_next %} { <a href="/page/index/?num={{ page.next_page_number }}" >下一页</a> {% endif %}
4.4 页码样式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <style> .a { width :20px ; height : 20px ; border :1px solid #e1e2e3 ; cursor :pointer; display : inline-block; text-align : center; line-height : 20px ; } .b { border :0 ; width :20px ; height : 20px ; cursor :pointer; display : inline-block; text-align : center; line-height : 20px ; } a { text-decoration :none; } </style>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 {% for user in page.object_list %} {{ user.id }} -- {{ user.name }} -- {{ user.password }} <br> {% endfor %} {% if page.has_previous %} <a href="/page/index/?num={{ page.previous_page_number }}" >上一页</a> {% endif %} {% for num in page.paginator.page_range %} <a href="/page/index/?num={{ num }}" > {% if num == page.number %} { <span class ="a" >{{ num }}</span> {% else %} <span class ="b" >{{ num }}</span> {% endif %} </a> {% endfor %} {% if page.has_next %} <a href="/page/index/?num={{ page.next_page_number }}" >下一页</a> {% endif %}
四、中间件 1、简介 中间件(Middleware)用于在http请求到达视图函数之前
和 视图函数return之后
,django会根据自己的规则在合适的时机执行中间件中相应的方法。
常用作view中冗余功能的抽取,如每个页面(或某些页面)在访问前强制登录 。
2、定义中间件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class MyMiddleware (MiddlewareMixin ): def __init__ (self,get_response ): super ().__init__(get_response) print ("init1" ) def process_request (self,request ): print ("request:" ,request) def process_view (self,request, view_func, view_args, view_kwargs ): print ("view:" ,request,view_func,view_args,view_kwargs) def process_response (self,request,response ): print ("response:" ,request,response) return response def process_exception (self,request,ex ): print ("exception:" ,request,ex)
中间件中常用的两个过程: process_request , process_response
3、激活中间件 每当有请求发生时,所有中间件都会执行自己的生命周期。
1 2 3 4 5 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware' , .... 'middleware115.middlewares.MyMiddleware' , ]
4、强制登录实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class MyMiddleAware2 (MiddlewareMixin ): def process_request (self,request ): if "login" not in request.path: print ("登录验证" ) session = request.session if session.get("login" ): print ("已登录" ) else : print ("未登录" ) return render(request,"login.html" ) else : print ("正在登录" ) def process_response (self,request,response ): print ("response:" ,request,response) return response