Django的高级使用
静态文件
css,js,图片,json文件,字体文件等:
就像templates一样,一般都是在manage.py所在文件夹创建一个static文件夹,里面再创建每个app对应的文件夹,在app文件夹下存放css,js,img,font等
配置setting.py:
setting.py本身就有STATIC_URL选项1
STATIC_URL = '/static/'
但是,我们需要配置
1
2SRATICFIELS_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'/>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
中间件
概述:
一个轻量级,底层的插件(C语言写的),可以==介入Django的请求和响应==.本质:
一个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',
]方法:
- __init__.py:
不需要传参数,服务器响应第一个请求的时候自动调用.用于确定是否启用该中间件. - process_request(self,request):
分配url匹配视图之前调用.返回None或者HttpResponse对象 - process_view(self,request,view_func,view_args,view_kwargs):
调用视图之前执行,返回None或者HttpResponse对象. - process_template_response(self,request,response):
在视图刚好执行完后调用,返回None或者HttpResponse对象.==在这里可以使用render== - process_response(self,request,response):
响应返回浏览器之前调用,返回HttpResponse对象. - process_exception(self,request,exception):
当视图发生异常时调用,返回HttpResponse对象.
- __init__.py:
中间件作用位置示意图:
自定义中间件:
和template一样,在manage.py目录下创建一个middleware目录,在创建每个APP对应的目录,里面存放相应的中间件.
首先导入MiddlewareMixin:
1
from django.utils.deprecation import MiddlewareMixin
之后每个中间件都要继承MiddlewareMixin
示例:
1
2
3def MyMiddleClass(MiddlewareMixin):
def process_request(self,request):
print('get的参数为',request.GET.get('a'))配置setting.py文件:
在MIDDLEWARE
参数中添加:1
2
3
4MIDDLEWARE = [
...
'middleware.myapp.mymiddleware.MyMiddleClass'
]
上传图片
概述:
文件上传时,==文件数据存储在urequest.FILES属性中==,
在static目录下啊创建upfile目录用于储存接收上传的文件.
配置setting.py
1
2# 上传文件目录
MEDIA_ROOT = os.path.join(BASE_DIR,r'static\upfile')
代码示例
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>结果:
分页
Paginator对象:
创建对象:
格式:1
2
3Paginator(列表,整数)
# 例如,25条数据,每页5个,那么就是
# Paginator([...],5)返回值:
返回一个分页对象属性:
- count:对象总数
(25条数据,每页6个,所以Paginator.count就是25) - num_pages:页面总数
(25条数据,每页6个,所以Paginator.num_pages就是5) - page_range:页码列表
(就是num_pages的列表,num_pages为5,那么Paginator.page_range就是[1,2,3,4,5])
注意页码从1开始.
- count:对象总数
方法:
Page(num):获得一个Page对象.
Paginator分出5页,那么就有5个Page对象.
如果提供的页码不存在会抛出InvaildPag异常
异常:
- InvaildPage:
当向Page传递的是一个无效的页码时抛出 - PageNotAnInteger:
当向Page()传递的不是一个整数时抛出. - EmptyPage:
当先Page()传递一个有效值,但是该页面没有数据时抛出.
- InvaildPage:
Page对象:
- 创建对象:
Pageinator对象的page()方法返回得到Page对象.不需要手动创建. - 属性:
- object_list:
当前页上所有的数据(对象)列表 - number:
当前页的页码值 - paginator:
当前page对象关联的paginator对象
- object_list:
- 方法:
- has_next():
判断是否有下一页,若有返回Ture - has_previous():
判断是否有上一页,若有返回True - has_other_pages():
判断是否有上一页或下一页 - next_page_number():
返回下一页的页码,若下一页不存在抛出InvaildPage异常 - previous_page_number():
返回上一页的页码,若上一页不存在抛出InvaildPage异常 - len():
返回当前页的数据个数
- has_next():
- 创建对象:
Paginator对象与Page对象的关系:
现在有25条数据,每页6条数据.- student.objects.all()获取25条数据
- 调用Paginator方法形成一个Paginator对象
- 调用Pageinator的Page方法,形成5个Page对象
- 前面4个Page对象每个对象6条数据,第5个Page对象1条数据
代码示例
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 #}
<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>结果:
我们还可以制作一个简易的跳转页面
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>
ajax
需要动态生成,请求json数据
示例:
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);
}
})
}
}
富文本
依赖项:
pip install django-tinymce在站点中使用:
配置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)
在自定义视图中使用:
使用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
问题
- 用户发起request,并且等待response返回,但是在视图中有一些耗时的操作,导致用户可能会等待很长时间才能接受到response.
- 网站每个一段时间要同步一次数据,但是HTTP请求需要触发的.
安装:
1
pip intall django-celery
示例:
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 #}
<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秒钟,之后才能进入
解决:
- 将耗时的操作放到celery中执行
- 使用celery定时执行
celery:
- 任务task:
本质是一个python函数,将耗时操作封装成一个函数 - 队列queue:
将要执行的任务放队列里 - 工人worker:
负责执行队列中的任务 - 代理broker:
负责调度,在部署环境中使用redis
- 任务task:
安装:
- pip install celery
- pip install celery-with-redis
- pip install django-celery
配置setting.py
INSTALLED_APPS:
1
2
3
4INSTALLED_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')
在应用目录下创建task.py文件:
在project/myapp/目录下创建task.py迁移,生成celery需要的数据库表:
1 | python manage.py migrate |
在工程目录下的project目录下创建celery.py的文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17from __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)
def debug_task(self):
print('Request: {0!r}'.format(self.request))在工程目录下的project目录下的__init__.py文件中添加
1
from .celery import app as celery_app
视图:
将前面的视图函数修改为:1
2
3
4
5
6import time
from .task import task_func
def celery(request):
# 添加到celery中执行,不会阻塞
task_func.delay()
return render(request,'myapp/celery.html')启动redis
启动服务
启动worker
1
python manage.py celery worker --loglevel=info