Django高级
静态文件
包含工程中的CSS, JS, 图片,Json等文件
{% load static from staticfiles %}
<!DOCTYPE html>
<html>
<script type = 'text/javascript' src = '{% static "js/nian.js" %}'></script>
</html>
中间件
概述
一个轻量级、底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入和输出。每一个中间组件都是一个独立的Python类
自定义中间件
- 工程目录下创建名为middlewares的目录
- 在middlewares目录下创建项目目录同名的目录
- 在上一步创建的目录下创建中间件的Py文件
- 在文件中定义中间件类
- 在settings.py文件中的MIDDLEWARE中添加’middlewares.myApp.myMiddle.MyMiddle’
- 注意:使用中间件,可以干扰整个处理过程,每次请求都会执行中间件的这些方法
方法
- __init__.py:无需任何参数,服务器响应第一个请求时调用一次,用于确认是否启用当前中间件
- process_request(request):执行试图之前被调用,每个请求都会调用,返回None或者HttpResponse对象
- process_view(request, view_func, view_args, view_kwags):执行视图之前被调用,每个请求上都会调用,返回None或者HttpResponse
- process_template_response(request, response):在视图刚好执行完毕之后被调用,每个请求中都会调用,返回实现了render方法的响应对象
- process_response(request, response):响应浏览器之前被调用,每个请求都会调用,返回HttpResponse对象
- process_exception(request, exception):当视图抛出异常时调用,每个请求都会调用,返回HttpResponse对象
示例
from django.utils.deprecation import MiddlewareMixin
from django.http import HttpResponse
class MyMiddle(MiddlewareMixin):
def process_request(self, request):
if request.COOKIES.get('nian') == 'bad':
return HttpReponse('Nice day')
上传文件
概述
当Django在处理文件时,文件的 数据会被保存在request.FILES
服务器接收上传文件
在static目录下创建名为media的目录
MEDIA_ROOT = os.path.join(BASE_DIR, r'static\media')
# html代码
<form action = '/upfile/' method = 'post' enctype = 'multipart/form-data'>
<input type = 'file' name = 'file'>
<input type = 'submit' value = '提交'>
</form>
# 视图函数
import os
from django.conf import settings
def upfile(request):
if request.method == 'GET':
return render(request, 'upfile.html')
else:
# 保存文件
for key in request.FILES:
fileObj = request.FILES[key]
filePath = os.path.join(settings.MEDIA_ROOT, fileObj.name)
print(filePath)
with open(filePath, 'wb') as fp:
for c in fileObj.chunks():
fp.write(c)
return HttpResponse('收到文件')
分页
Paginator对象
- 创建对象:Paginator(列表, 每页数据量)
- 属性:
count:对象总数
num_pages:页面总数
page_range:页码列表 - 方法:
page(num):创建page对象,num为要获取数据的页码,从1开始 - 异常:
InvalidPage:当向page传入一个无效的页码
PageNotAnInteger:当传入的页码不是一个整数
EmptyPage:当向page传入是有效值但页面上没有任何数据
Page对象
- 创建page对象:Paginator对象的page方法创建
- 属性:
object_list:当前页上的所有对象列表集合
number:当前页的页码
paginaor:引用创建该对象的Paginator对象 - 方法:
has_next:如果有下一页,返回True
has_previous:如果有上一页,返回True
has_other_pages:如果有上一页或者下一页,返回True
next_page_number:如果有下一页则返回下一页的页码,如果下一页不存在则抛出InvaidPage异常
previous_page_number:如果有上一页则返回上一页的页码,如果上一页不存在则抛出InvaidPage异常
len:返回当前页面对象的个数 - 示例
# html代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>分页</title>
</head>
<body>
<ul>
{% for stu in stus %}
<li>{{ stu.sname }}</li>
{% endfor %}
</ul>
{% if stus.has_previous %}
<a href="/students/{{ stus.number | add:-1 }}">上一页</a>
{% else %}
上一页
{% endif %}
{% for index in stus.paginator.page_range %}
{% if index == stus.number %}
{{ index }}
{% else %}
<a href="/students/{{ index }}">{{ index }}</a>
{% endif %}
{% endfor %}
{% if stus.has_next %}
<a href="/students/{{ stus.number | add:1 }}">下一页</a>
{% else %}
下一页
{% endif %}
</body>
</html>
# 视图代码:
from django.core.paginator import Paginator
def students(request, page):
allStudents = Students.object3.all()
# 创建Paginator对象
paginator = Paginator(allStudents, 5) # 每页5条数据
stus = paginator.page(page)
# 如果有下一页,返回True
print(stus.has_next())
# 如果有上一页,返回True
print(stus.has_previous())
# 如果有上一页或者下一页返回True
print(stus.has_other_pages())
# 如果有下一页返回下一页页码,没有抛出异常
print(stus.next_page_number())
print(stus.previous_page_number())
# 返回当前对象的个数
print(len(stus))
return render(request, 'students.html', {'stus':stus})
ajax
# 视图代码:
from django.http import JsonResponse
def ajax(request):
return render(request, 'ajax.html')
def ajax2(request):
if request.method == 'GET':
return render(request, 'ajax.html')
else:
# 接受到ajax请求
stus = Students.object3.all()
lis = []
for stu in stus:
lis.append({'name':stu.sname, 'age':stu.sage})
return JsonResponse({'data':lis})
# html代码:
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>展示学生信息</title>
<script type="text/javascript" src="{% static 'js/jquery-3.1.1.min.js' %}"></script>
</head>
<body>
<button id="btn">展示学生信息</button>
<div id="box"></div>
<script type="text/javascript">
$('#btn').bind('click', function () {
$.ajax({
type:'post',
url:'/ajax2/',
dataType:'json',
success:function (data, status) {
console.log(data)
var arr = data['data']
}
})
})
</script>
</body>
</html>
富文本
pip install django-tinymce
在admin站点中使用:
# 配置settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myApp',
'tinymce',
'djccelery',
]
# 富文本配置
TINYMCE_DEFAULT_CONFIG = {
'theme':'advanced',
'width':800,
'height':500,
}
from tinymce.models import HTMLField
class Text(models.Model):
content = HTMLField()
2. admin.py中:
# Register your models here.
from .models import Text
admin.site.register(Text)
- 生成数据表(python manage.py migrate)
- 创建admin管理用户(python manage.py createsuperuser)
在自定义视图中使用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>富文本</title>
<script type="text/javascript" src="/static/tiny_mce/tiny_mce.js"></script>
<script type="text/javascript">
tinyMCE.init({
{# # 给什么标签加#}
'mode':'textareas',
'theme':'advanced',
'width':800,
'height':500,
})
</script>
</head>
<body>
<textarea></textarea>
</body>
</html>
celery
文档:http://docs.jinkan.org/docs/celery/ - 问题:用户发起request,并等待response返回。在当前views中,可能需要较长时间,那么用户就会等着,造成不良好体验;网站每隔一段时间需要同步一些数据,但是http请求是需要发出的,难道需要每隔一段时间就请求一次吗?
- 解决:使用celery,将耗时操作交给celery去执行;使用celery定时操作
- celery:
任务:task, 就是一个Python函数,一个耗时操作就是一个任务
队列:queue, 将需要执行的任务加入到队列中
工人:worker, 在一个新的进程中,负责执行队列中的任务
代理:broker, 负责调度,在布置环境中使用redis - 安装
pip install celery
pip install celery-with-redis
pip install django-celery 配置settings.py:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'myApp', 'tinymce', 'djcelery', ] # celery配置 import djcelery djcelery.setup_loader() BROKER_URL = 'redis://用户名@127.0.0.1' CELERY_IMPORTS = ('myApp.task')
在项目目录下创建task.py文件
from celery import task import time @task def longIO(): print('111111111111111') time.sleep(5) print('2222222222')
- 迁移,生成celery数据表(python manage.py migrate)
在工程目录下的project目录下的init.py中增加
from .celery import app as celery_app
在工程目录下的project目录下创建名为celery.py的文件
from __future__ import absolute_import import os from celery import Celery from django.conf import settings os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'whthas_home.settings') app = Celery('portal') app.config_from_object('django.conf:settings') app.autodiscover_tasks(lambda :settings.INSTALLED_APPS) @app.task(bin=True) def debug_task(self): print('Request:{0!r}'.format(self.request))
- 启动redis
- 启动worker:python manage.py celery worker –loglevel=info
from .task import longIO
def celery(request):
longIO.delay()
return HttpResponse('响应')