Django之CSRF、分页、paginator、page对象笔记

/ 0评 / 0

一、CSRF,即Cross-Site Request Forgey

  1. 跨站请求伪造攻击(CSRF,即Cross-Site Request Forgey)
    • 某些恶意网站上包含链接、表单按钮或者JavaScript,它们会利用登录过的用户在浏览器中的认证信息试图在你的网站上完成某些操作。
  2. 说明:
    • CSRF中间件和模板标签提供对跨站请求伪造简单易用的防护。
  3. 作用:
    • 不让其它表单提交到此Django服务器
  4. 防范步骤:

    1. settings.py中确认MIDDLEWARE中。django.middleware.csrf.CSRFViewMiddleware是否打开。
    2. 模板中,form标签下添加如下标签 {csrf_token}
    3. 如果某个视图不需要django进行csrf保护,可以用装饰器关闭对此视图的检查。

      from django.views.decorators.csrf import csrf_exempt
      @csrf_exempt
      def my_view(request):
          return HttpResponse('Hello world')
      

二、分页

  1. 分页是指在webd页面有大量数据需要显示,为了阅读方便在每个页面中只显示部分数据。
  2. 好处:
    • 方便阅读。
    • 减少数据提取量,减轻服务器压力。
  3. Django提供了Paginator类可以方便的实现分页功能。
  4. Paginator类位于django.core.paginator

三、Paginator对象

  1. 负责分页数据整体的管理
  2. 对象的构造方法

    • paginator = Paginator(object_list,per_page)
    • 参数
      • object_list 需要分类数据的对象列表
      • per_page 每页数据个数
    • 返回值
      • Paginator对象
    • Paginator 属性
      • count: 需要分类数据的对象总数
      • num_pages: 分页后的页面总数
      • page_range: 从1开始的range对象,用于记录当前页面码数
      • per_page 每页数据的个数
    • Paginator方法
      • page(number)
        • 参数number为页码信息(从1开始)
        • 返回当前number页对应的页信息
        • per_page每页数据的个数
    • Paginator异常exception
      • InvalidPage: 总异常基类,包含以下两个异常子类
        1. PageNotAnInteger: 当向page()传入一个不是整数的值时抛出
        2. EmptyPage: 当向page()提供一个有效值,但是那个页面上没有任何对象时抛出

    四、Page对象

    1. 负责具体某一页的数据管理
    2. 创建对象,Paginator对象的page()方法返回Page对象
      • page = paginator.page(页码)
    3. Page对象属性
      • object_list: 当前面上所有数据对象的列表
      • number: 当前的序号,从1开始
      • Paginator: 当前page对象相关的Paginator对象
    4. Page对象方法
      • has_next(): 如果有下一页返回True
      • has_previous(): 如果有上一页返回True
      • has_other_pages(): 如果有上一页或下一页返回True
      • next_page_number(): 返回下一页的页码,如果下一页不存在、抛出InvalidPage异常
      • previous_page_number(): 返回上一页的页码,如果上一页不存在,抛出InvalidPage异常
      • len(): 返回当前页面对象的个数
    5. 说明:Page对象是可迭代对象,可以用for语句来访问当前页面中的每个对象。
    6. 分页示例:

      • 视图函数
      from django.core.paginator import Paginator
      def book(request):  
          bks = Book.objects.all()
          paginator = Paginator(bks, 10)
          cur_page = request.GET.get('page', 1)  # 得到默认的当前页
          page = paginator.page(cur_page)
          return render(request, 'bookstore/book.html', locals())
      
    7. 模板设计

      <html>
      <head>
      <title>分页显示</title>
      </head>
      <body>
      {% for b in page %}
      <div>{{ b.title }}</div>
      {% endfor %}
      ​
      {% if page.has_previous %}
      <a href="{% url 'book' %}?page={{ page.previous_page_number }}">上一页</a>
      {% else %}
      上一页
      {% endif %}
      ​
      {% for p in paginator.page_range %}
      {% if p == page.number %}
      {{ p }}
      {% else %}
      <a href="{% url 'book' %}?page={{ p }}">{{ p }}</a>
      {% endif %}
      {% endfor %}
      ​
      {% if page.has_next %}
      <a href="{% url 'book' %}?page={{ page.next_page_number }}">下一页</a>
      {% else %}
      下一页
      {% endif %}
      </body>
      </html>
      

五、文件下载

  1. Django可直接在视图函数中生成csv文件并响应给浏览器。

    import csv
    from django.http import HttpResponse
    from .models import Book
    ​
    def make_csv_view(request):
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = 'attachment; filename="mybook.csv"'
        all_book = Book.objects.all()
        writer = csv.writer(response)
        writer.writerow(['id', 'title'])
        for b in all_book:    
            writer.writerow([b.id, b.title])
    ​
        return response
    
  2. 响应获得一个特殊的MIME类型text/csv。告诉浏览器该文档是CSV文件,而非HTML文件。

  3. 响应会获得一个额外的Content-Disposition标头,其中包含CSV文件中的名称。它将被浏览器用于”另存为...“对话框

  4. 对于CSV文件中第一行,调用writer.writerow,传递一个可迭代对象,如列表或元组。

六、文件上传

  1. 文件上传必须为POST提交方式
  2. 表单
    中文件上传必须有带有enctype="multipart/form-data"时才会包含文件内容数据。
  3. 表单中用<input type="file" name="xxx">标签上传文件
    • 名字xxx对应的内在缓冲文件流对象。可通过request.FILES['xxx']`返回的对象获取上传文件数据
    • file=request.FILES['xxx']file绑定文件流对象,可以通过文件流对象如下信息获取文件数据
    • file.name 文件名
    • file.file文件的字节流数据
  4. 上传文件的表单书写方式

    <!-- file: index/templates/index/upload.html -->
    <html>
    <head>
        <meta charset="utf-8">
        <title>文件上传</title>
    </head>
    <body>
        <h3>上传文件</h3>
        <form method="post" action="/test_upload" enctype="multipart/form-data">
            <input type="file" name="myfile" /><br>
            <input type="submit" value="上传">
        </form>
    </body>
    </html>        
    
  5. 在setting.py设置MEIDA相关配置;Django把用户上传的文件,统称为media资源

    # file: settings.py
    MEDIA_URL = '/media/'
    MEDIA_ROOT = os.path.join(BASE_DIR,'media')
    
  6. 在当前项目文件夹下创建media文件夹

    • $ Mkdir media
  7. 上传文件视图处理函数

    • 方案1 传统写入
    # file views.py
    from django.http import HttpResponse
    from django.conf import settings
    from django.views.decorators.csrf import csrf_exempt
    import os
    ​
    @csrf_exempt
    def upload_view(request):
        if request.method == 'GET':
            return render(request, 'test_upload.html')
        elif request.method == "POST":
            a_file = request.FILES['myfile']
            print("上传文件名是:", a_file.name)
            filename =os.path.join(settings.MEDIA_ROOT, a_file.name)
            with open(filename, 'wb') as f:
            data = a_file.file.read()
            f.write(data)  
            return HttpResponse("接收文件:" + a_file.name + "成功")
    
    • 方案2 借助orm
    #test_upload/models.py
    from django.db import models
    
    #Create your models here.
    class Content(models.Model):
    ​
    desc = models.CharField(max_length=100)
    myfile = models.FileField(upload_to='myfiles')
    ​
    #test_upload/views.py
    from test_upload.models import *
    from django.views.decorators.csrf import csrf_exempt
    ​
    @csrf_exempt
    def upload_view_dj(request):
        if request.method == 'GET':
            return render(request, 'test_upload.html')
        elif request.method == 'POST':
            title = request.POST['title']
            a_file = request.FILES['myfile']
            Content.objects.create(desc=title,myfile=a_file)
            return HttpResponse('----upload is ok-----')
    
  8. 若要在浏览器中访问上传的资源,runserver环境下,需要在项目主跟路由添加media路由绑定

    from django.conf import settings
    from django.conf.urls.static import static
    urlpatterns += static(settings.MEDIA_URL,       document_root=settings.MEDIA_ROOT)
    

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注