Django的高级使用

静态文件

  1. css,js,图片,json文件,字体文件等:

    就像templates一样,一般都是在manage.py所在文件夹创建一个static文件夹,里面再创建每个app对应的文件夹,在app文件夹下存放css,js,img,font等
    1555681294793

  2. 配置setting.py:
    setting.py本身就有STATIC_URL选项

    1
    STATIC_URL = '/static/'

    但是,我们需要配置

    1
    2
    SRATICFIELS_DIRS = [os.path.join(BASE_DIR,'static')]
    # 这里的static对应static文件夹

    所以,当我们想用static/myapp/css/style.css时就要:

    1
    2
    3
    4
    5
    <link rel='stylesheet' type='text/css' href='/static/myapp/css/style.css'/>

    <script type='text/javascript' scr='/static/myapp/js/hyl.js'></script>

    <img src='/static/myapp/img/hyl.png'/>
  3. url可以反向解析,静态文件一样可以.

    1
    2
    {# urls的反向解析 #}
    <a href="{% url 'myapp:good' 199 %}">链接</a>
    1
    2
    3
    4
    5
    {# 首先在模块顶部导入 #}
    {% load static from staticfiles %}

    {# 导入需要的文件 #}
    <img src="{% static 'myapp/img/hyl.png' %}"/>FIELS

中间件

  1. 概述:
    一个轻量级,底层的插件(C语言写的),可以==介入Django的请求和响应==.

  2. 本质:
    一个Python类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 引入一个中间件的类
    MIDDLEWARE = [
    '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',
    ]
  3. 方法:

    1. __init__.py:
      不需要传参数,服务器响应第一个请求的时候自动调用.用于确定是否启用该中间件.
    2. process_request(self,request):
      分配url匹配视图之前调用.返回None或者HttpResponse对象
    3. process_view(self,request,view_func,view_args,view_kwargs):
      调用视图之前执行,返回None或者HttpResponse对象.
    4. process_template_response(self,request,response):
      在视图刚好执行完后调用,返回None或者HttpResponse对象.==在这里可以使用render==
    5. process_response(self,request,response):
      响应返回浏览器之前调用,返回HttpResponse对象.
    6. process_exception(self,request,exception):
      视图发生异常时调用,返回HttpResponse对象.
  4. 中间件作用位置示意图:

    中间件位置示意图

  5. 自定义中间件:

    1. 和template一样,在manage.py目录下创建一个middleware目录,在创建每个APP对应的目录,里面存放相应的中间件.
      1555721765806

    2. 首先导入MiddlewareMixin:

      1
      from django.utils.deprecation import MiddlewareMixin

      之后每个中间件都要继承MiddlewareMixin

    3. 示例:

      1
      2
      3
      def MyMiddleClass(MiddlewareMixin):
      def process_request(self,request):
      print('get的参数为',request.GET.get('a'))
    4. 配置setting.py文件:
      MIDDLEWARE参数中添加:

      1
      2
      3
      4
      MIDDLEWARE = [
      ...
      'middleware.myapp.mymiddleware.MyMiddleClass'
      ]

上传图片

  1. 概述:

    • 文件上传时,==文件数据存储在urequest.FILES属性中==,

    • 在static目录下啊创建upfile目录用于储存接收上传的文件.
      1555722727469

    • 配置setting.py

      1
      2
      # 上传文件目录
      MEDIA_ROOT = os.path.join(BASE_DIR,r'static\upfile')
  2. 代码示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # myapp/views.py
    import os
    from django.conf import settings
    def savefile(request):
    if request.method == 'POST':
    f = request.FILES['file']
    # 文件在服务器端的路径
    filepath = os.path.join(settings.MEDIA_ROOT,f.name)

    with open(filepath,'wb') as fp:
    # 分流读写(分段写入)
    for info in f.chunks():
    fp.write(info)
    return HttpResponse('上传成功')
    else:
    return HttpResponse('上传失败')

    def upfile(request):
    return render(request,'myapp/upfile.html')

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    {# templates/upfile.html #}
    <html lang='cn'>
    <head>
    <meta charset="UTF-8">
    <title>登录</title>
    </head>

    <body>
    <!-- form表单上传文件需要加enctype属性 -->
    <form action="/savefile/" method="post" enctype="multipart/form-data">
    {%csrf_token%}
    <input type="file" name="file"/>
    <input type="submit" value="上传"/>
    </form>
    </body>
    </html>

    结果:
    1555725737772
    1555725751967
    1555725761266

分页

  1. Paginator对象:

    • 创建对象:
      格式:

      1
      2
      3
      Paginator(列表,整数)
      # 例如,25条数据,每页5个,那么就是
      # Paginator([...],5)

      返回值:
      返回一个分页对象

    • 属性:

      1. count:对象总数
        (25条数据,每页6个,所以Paginator.count就是25)
      2. num_pages:页面总数
        (25条数据,每页6个,所以Paginator.num_pages就是5)
      3. page_range:页码列表
        (就是num_pages的列表,num_pages为5,那么Paginator.page_range就是[1,2,3,4,5])
        注意页码从1开始.
    • 方法:
      Page(num):获得一个Page对象.
      Paginator分出5页,那么就有5个Page对象.
      如果提供的页码不存在会抛出InvaildPag异常

    • 异常:

      1. InvaildPage:
        当向Page传递的是一个无效的页码时抛出
      2. PageNotAnInteger:
        当向Page()传递的不是一个整数时抛出.
      3. EmptyPage:
        当先Page()传递一个有效值,但是该页面没有数据时抛出.
  2. Page对象:

    • 创建对象:
      Pageinator对象的page()方法返回得到Page对象.不需要手动创建.
    • 属性:
      1. object_list:
        当前页上所有的数据(对象)列表
      2. number:
        当前页的页码值
      3. paginator:
        当前page对象关联的paginator对象
    • 方法:
      1. has_next():
        判断是否有下一页,若有返回Ture
      2. has_previous():
        判断是否有上一页,若有返回True
      3. has_other_pages():
        判断是否有上一页或下一页
      4. next_page_number():
        返回下一页的页码,若下一页不存在抛出InvaildPage异常
      5. previous_page_number():
        返回上一页的页码,若上一页不存在抛出InvaildPage异常
      6. len():
        返回当前页的数据个数
  3. Paginator对象与Page对象的关系:
    现在有25条数据,每页6条数据.

    • student.objects.all()获取25条数据
    • 调用Paginator方法形成一个Paginator对象
    • 调用Pageinator的Page方法,形成5个Page对象
    • 前面4个Page对象每个对象6条数据,第5个Page对象1条数据

    Paginator对象和Page对象的关系

  4. 代码示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # 匹配路由
    url(r'^studentspage/(\d+)/$',views.studentspage)

    # 视图函数
    from django.core.paginator import Paginator
    def studentspage(request,pageid):
    # 所有的学生列表
    all_list = Students.objects.all()
    # 调用Paginator函数,生成paginator对象
    paginator = Paginator(all_list,6)
    # 调用paginator对象的page方法,生成page对象
    page = paginator.page(pageid)
    return render(request,'myapp/studentspage.html',{'students':page})
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    {# myapp/studentspage.html #}
    <!DOCTYPE html>
    <html lang='cn'>
    <head>
    <meta charset="UTF-8">
    <title>分页显示</title>
    </head>

    <body>
    <ul>
    {% for stu in students %}
    <li>
    {{stu.name}}
    </li>
    {% endfor %}
    </ul>
    </body>
    </html>

    结果:
    1555737479032
    1555737489813

  5. 我们还可以制作一个简易的跳转页面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <html lang='cn'>
    <head>
    <meta charset="UTF-8">
    <title>分页显示</title>
    </head>

    <body>
    <ul>
    {% for stu in students %}
    <li>
    {{stu.name}}
    </li>
    {% endfor %}
    </ul>

    <ul>
    {%for idx in students.paginator.page_range %}
    <li>
    {# 在这里跳转 #}
    <a href="/studentspage/{{idx}}/">{{idx}}</a>
    </li>
    {% endfor %}
    </ul>
    </body>
    </html>

    1555738156594
    1555738216439

ajax

  1. 需要动态生成,请求json数据

  2. 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # 配置url
    url(r'ajaxstudents/(\d+)/$',views.ajaxstudents),
    url(r'^studentsinfo/$',views.studentsinfo)

    # 视图函数
    from django.http import JsonResponse
    def ajaxstudents(request):
    return render(request,'myapp/ajaxstudents.html')

    def studentsinfo(request):
    stus = Students.objects.all()
    list = []
    for stu in stus:
    list.append([stu.name,stu.gender])
    return JsonResponse({"data":list})
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    {# myapp/ajaxstudents.html #}
    <html lang='cn'>
    <head>
    <meta charset="UTF-8">
    <title>学生信息</title>
    <script type="text/javascript" src="/static/myapp/js/jquery-3.1.1.min.js"></script>
    </head>

    <body>
    <h1>学生信息列表</h1>
    <button id = "btn">显示学生信息</button>
    <script type="text/javascript" src="/static/myapp/js/hyl.js"></script>
    </body>
    </html>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /*   static/myapp/js/hyl.js   */
    $(document).ready(function(){
    document.getElementByIdI("btn").onclick =
    function(){
    $.ajax({
    type:"get",
    url :'studentsinfo',
    dataType:"json"
    success:function(data,status){
    console.log(data);
    }
    })
    }
    }

富文本

  1. 依赖项:
    pip install django-tinymce

  2. 在站点中使用:

    • 配置setting.py文件:
      installed_apps中添加'tinymce'

    • 配置TINYMCE_DEFAULT_CONFIG:

      1
      2
      3
      4
      5
      6
      7
      # setting.py
      # 富文本
      TINYMCE_DEFAULT_CONFIG = {
      'theme':'advanced',
      'width':600,
      'height':400,
      }
    • 创建模型类:

      1
      2
      3
      4
      5
      # modles.py
      # 创建HTMLField
      from tinymce.models import HTMLField
      class Text(models.Model):
      str = HTMLField()
    • 配置站点:

      1
      2
      3
      # admin.py
      from .models import Grades,Students,Text
      admin.site.register(Text)
  3. 在自定义视图中使用:

    使用textarea标签

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <!DOCTYPE html>
    <html lang='cn'>
    <head>
    <meta charset="UTF-8">
    <title>富文本</title>
    <script type="text/javascript" src="/staitic/tiny_mce/tiny_mce.js"></script>

    <script type="text/javascript">
    tinyMCE.init({
    'mode':'textareas',
    'theme':'advanced',
    'width':800,
    'height':600,
    })
    </script>
    </head>

    <body>
    <form>
    <textarea name="str">hello world</textarea>
    </form>
    </body>
    </html>

celery

  1. http://docs.jinkan.org/docs/celery/

  2. 问题

    • 用户发起request,并且等待response返回,但是在视图中有一些耗时的操作,导致用户可能会等待很长时间才能接受到response.
    • 网站每个一段时间要同步一次数据,但是HTTP请求需要触发的.
  3. 安装:

    1
    pip intall django-celery
  4. 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # url.py
    url(r'^celery/$',views.celery)

    # views.py
    import time
    def celery(request):
    # 耗时操作
    time.sleep(5)
    return render(request,'myapp/celery.html')
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    {# celery.html #}
    <!DOCTYPE html>
    <html lang='cn'>
    <head>
    <meta charset="UTF-8">
    <title>good</title>
    </head>

    <body>
    <h1>this is celery page</h1>
    </body>
    </html>

    当进入127.0.0.1/celery时就会等待5秒钟,之后才能进入

  5. 解决:

    • 将耗时的操作放到celery中执行
    • 使用celery定时执行
  6. celery:

    • 任务task:
      本质是一个python函数,将耗时操作封装成一个函数
    • 队列queue:
      将要执行的任务放队列里
    • 工人worker:
      负责执行队列中的任务
    • 代理broker:
      负责调度,在部署环境中使用redis
  7. 安装:

    • pip install celery
    • pip install celery-with-redis
    • pip install django-celery
  8. 配置setting.py

    • INSTALLED_APPS:

      1
      2
      3
      4
      INSTALLED_APPS = [
      ...
      'djcelery',
      ]
    • 配置celery:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      # celery
      import djcelery
      # 初始化
      djcelery.setup_loader()
      # redis://:密码@ip地址:端口/数据库号
      BROKER_URL = 'redis://:hyl@127.0.0.1:6379/0'
      # 项目名
      # 调用mapp文件夹下的task.py
      CELERY_IMPORTS =('myapp.task')
  9. 在应用目录下创建task.py文件:
    在project/myapp/目录下创建task.py

  10. 迁移,生成celery需要的数据库表:

1
python manage.py migrate
  1. 在工程目录下的project目录下创建celery.py的文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    from __future__ import absolute_import

    import os
    from celery import Celery
    from django.conf import settings

    os.environ.setdefault('DJANGO_SETTINGS_MODULE','whatas_home.settings')

    app = Celery('portal')

    app.config_from_object('django.conf:settings')
    app.autodiscover_tasks(lambda : settings.INSTALLED_APPS)


    @app.task(bind=True)
    def debug_task(self):
    print('Request: {0!r}'.format(self.request))
  2. 在工程目录下的project目录下的__init__.py文件中添加

    1
    from .celery import app as celery_app
  3. 视图:
    将前面的视图函数修改为:

    1
    2
    3
    4
    5
    6
    import time
    from .task import task_func
    def celery(request):
    # 添加到celery中执行,不会阻塞
    task_func.delay()
    return render(request,'myapp/celery.html')
  4. 启动redis

  5. 启动服务

  6. 启动worker

    1
    python manage.py celery worker --loglevel=info