****************************************第二篇笔记从这里开始************************************************
模板
定义模板
变量
变量传递给模板的数据
要遵守标识符规则
语法 {{ var }}
注意:如果使用的变量不存在,则插入的是空字符串
在模板中使用点语法
字典查询
属性或者方法
数字索引
在模板中调用对象的方法
注意:在模板里定义的函数不能传递self以外的参数
标签:语法 {% tag %}
作用
在输出中创建文本
控制逻辑和循环
标签示例:
if 格式
{% if 表达式 %}
语句
{% endif %}
if-else 格式
{% if 表达式 %}
语句1
{% else %}
语句else
{% endif %}
if-elif-else 格式
{% if 表达式 %}
语句1
{% elif 表达式 %}
语句2
...
{% else %}
语句else
{% endif %}
for 格式
{% for 变量 in 列表 %}
语句
{% endfor %}
格式2
{% for 变量 in 列表 %}
语句
{% empty %} # 注意:列表为空或者列表不存在时执行语句2
语句2
{% endfor %}
格式3
{{ forloop.counter }}
示例:
<ul>
{% for stu in students %}
<li>
{{forloop.counter}}--{{stu.sname}}--{{stu.sgrade}}
</li>
{% empty %}
<li>目前没有学生</li>
{% endfor %}
commnet 格式
{% commnet %}
被注释的内容
{% endcomment %}
作用:相当于多行注释,被注释的内容不再执行
ifequal/ifnotequal 作用 判断是否相等或者不相等
格式
{% ifequal 值1 值2 %}
语句1
{% endifequal %} # 如果值1等于值2,执行语句1,否则不执行语句1
include
作用:加载模板并以标签内的参数渲染
格式:{% include '模板目录' 参数1 参数2 %}
url
作用:反射解析
格式:{% url 'namespace: name' p1 p2 %}
csrf_token
作用:用于跨站请求伪造保护
格式:{% csrf_token %}
block, extends
作用:用于模板的继承
autoescape
作用:用于HTML转义
过滤器
语法 {{ var|过滤器 }}
作用:在变量被显示前修改它,只是加一个效果,对变量不会造成影响
示例:
lower
upper
过滤器可以传递参数,参数用引号引起来
join 格式 列表|join:"#"
示例:{{list1|join:"#"}}
如果一个变量没有被提供,或者值为false,空,我们可以通过 default 语法使用默认值
格式: {{str1|default:"没有"}}
根据给定格式转换日期为字符串:date
格式: {{dateVal|date:'y-m-d'}}
HTML转义:escape
加减乘除示例:
<h1>num = {{num|add:10}}</h1>
<h1>num = {{num|add:-10}}</h1>
<h1>num = {% num widthratio num 1 5%}</h1>
<h1>num = {% num widthratio num 5 1%}</h1>
注释
单行注释:语法: {# 被注释的内容 #}
多行注释
{% commnet %}
被注释的内容
{% endcomment %}
反射解析
示例:
project/project/urls.py
url(r'^', include('myApp.urls', namespace='app')),
project/myApp/urls.py
url(r'^good/(\d+)$', views.good, name="good")
templates/good.html
<a href={% url 'app:good' 1 %}>链接</a>
模板继承
作用:模板继承可以减少页面的重复定义,实现页面的重用
block标签:在父模板中预留区域 ,子模板去填充
语法 : {% block 标签名 %}
{% endblock 标签名 %}
extends标签:继承模板,需要写在模板文件的第一行
语法 : {% extends 'myApp/base.html' %}
{% block main %}
内容
{% endblock 标签名 %}
示例:
定义父模板
body标签中
{% block main %}
{% endblock main %}
{% block main %}
{% endblock main2 %}
定义子模板
{% extends 'myApp/base.html' %}
{% block main %}
<h1>sunck is a good man</h1>
{% endblock main %}
{% block main2 %}
<h1>kaige is a good man</h1>
{% endblock main2 %}
HTML转义
问题:return render(request, 'myApp/index.html', {"code": "<h1>sunck is a very good man</h1>"})中的{{code}}
{{code}}里的code被当作<h1>sunck is a very good man</h1>显示,未经过渲染
解决方法:
{{code|safe}}
或 {% autoescape off %}
{{code}}
{% endautoescape %} # 这个可以一口气解决一堆
CSRF:
跨站请求伪造
某些恶意网站包含链接,表单,按钮,js,利用登录用户在浏览器中认证,从而攻击服务
防止CSRF
在settings.py文件的MIDDLEWARE增加'django.middleware.csrf.CsrfViewMiddleware'
{% csrf_token %}
验证码
作用
在用户注册,登录页面的时候使用,为了防止暴力请求,减轻服务器的压力
是防止CSRF的一种方式
验证码代码示例:
写在views.py里面
=================================================================================================
def verifycode(request):
# 引入绘图模块
from PIL import Image, ImageDraw, ImageFont
# 引入随机函数模块
import random
# 定义变量,用于画面的背景色,宽,高
bgcolor = (random.randrange(20, 100), random.randrange(20, 100), random.randrange(20, 100))
width = 100
height = 50
# 创建画面对象
im = Image.new('RGB', (width, height), bgcolor)
# 创建画面对象
draw = ImageDraw.Draw(im)
# 调用画笔的point()函数绘制噪点
for i in range(0, 100):
xy = (random.randrange(0, width), random.randrange(0, height))
fill = (random.randrange(0, 255), 255, random.randrange(0, 255))
draw.point(xy, fill=fill)
# 定义验证码的备选值
str = '1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm'
# 随机选取4个值作为验证码
rand_str = ''
for i in range(0, 4):
rand_str += str[random.randrange(0, len(str))]
# 构造字体对象
font = ImageFont.truetype(r'C:\Windows\Fonts\AdobeArabic-Bold.otf', 40)
# 构造字体颜色
fontcolor1 = (255, random.randrange(0, 255), random.randrange(0, 255))
fontcolor2 = (255, random.randrange(0, 255), random.randrange(0, 255))
fontcolor3 = (255, random.randrange(0, 255), random.randrange(0, 255))
fontcolor4 = (255, random.randrange(0, 255), random.randrange(0, 255))
# 绘制4个字
draw.text((5, 2), rand_str[0], font=font, fill=fontcolor1)
draw.text((25, 2), rand_str[1], font=font, fill=fontcolor2)
draw.text((50, 2), rand_str[2], font=font, fill=fontcolor3)
draw.text((75, 2), rand_str[3], font=font, fill=fontcolor4)
# 释放画笔
del draw
# 存入session,用于做进一步的验证
request.session['verifycode'] = rand_str
# 内存文件操作
import io
buf = io.BytesIO()
# 将图片保存在内存中,文件类型为png
im.save(buf, 'png')
# 将内存中的图片数据返回给客户端,MIME类型为图片png
return HttpResponse(buf.getvalue(), 'image/png')
from django.shortcuts import render, redirect
def verifycodefile(request):
f = request.session["falg"]
str = ""
if f == False:
str = "请重新输入!"
request.session.clear()
return render(request, 'myApp/verifycodefile.html', {"flag":str})
def verifycodecheck(request):
code1 = request.POST.get("verifycode").upper()
code2 = request.session["verify"].upper()
if code1 == code2:
return render(request, 'myApp/success.html')
else:
request.session["flag"] = False
return redirect('/verifycodefile')
==============================================================================
写在verifycodefile.html的<body>标签中
<body>
<form method="post" action="/verifycodecheck/">
{%csrf_token%}
<input type="text" name="verifycode"/>
<img src="/verifycode">
<input type="submit" name="登录">
<span>{{flag}}</span>
</form>
</body>
==============================================================================
Django高级扩展
静态文件
css,js,图片,json文件,字体文件等
配置settings.py
STATIC_URL = '/static'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]
中间件
概述:一个轻量级,底层的插件,可以介入Django的请求和响应。
本质:一个Python类
方法:
__init__
不需要传参数,服务器响应第一个请求的时候自动调用,用于确定是否启用该中间件
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__ --> process_request--> url --> process_view --> view --> process_template_response --> template --> process_response -->返回开头部分
执行位置:
自定义中间件
在工程目录下的middleware目录下创建myApp
创建一个python文件
from django.utils.deprecation import middlewareMixin
class MyMiddle(middlewareMixin):
def process_request(self, request):
print("get参数为: ", request.GET.get("a"))
使用自定义中间件
配置settings.py文件 在MIDDLEWARE中添加 'middleware.myApp.MyMiddle.MyMiddle',
上传图片
概述:
文件上传时,文件数据request.FILES属性中.
注意:form表单要上传文件需要加enctype="multipart/form-data"
注意:上传文件必须用post请求
存储路径:
在static目录下创建upfile目录用于存储上传的文件
配置settings.py文件 MDEIA_ROOT = os.path.join(BASE_DIR, r'static\upfile')
views.py内容
==============================================================================
def upfile(request):
return render(request, 'myApp/upfile.html')
import os
from django.conf import settings
def savefile(request):
if request.method == "POST":
f = request.FILES["file"]
# 文件在服务器端的路径
filePath = os.pasth.join(settings.MDEIA_ROOT, f.name)
with open(filePath, 'wb') as fp:
for info in f.chunks():
fp.write(info)
return HttpResponse("上传成功。")
else:
return HttpResponse("上传失败。")
==============================================================================
upfile.html中<body>里的内容
<body>
<form method="post" action="/savefile" enctype="multipart/form-data">
{%csrf_token%}
<input type="file" name="file"/>
<input type="submit" value="上传"/>
</form>
</body>
==============================================================================
分页
Paginator对象
创建对象
格式 Paginator(列表,整数)
返回值 返回的分页对象
属性
count 对象总数
num_pages 页面总数
page_range
页码列表
[1,2,3,4,5]
页码从1开始
方法
page(num) 获得一个Page对象,如果提供的页码不存在会抛出"InvalidPage"异常
异常
InvalidPage:当向 page()传递的是一个无效的页码时抛出
PageNotAnInteger:当向 page()传递的不是一个整数时抛出
EmptyPage:当向 page()传递一个有效值,但是该页面里没有数据时抛出
Page对象
创建对象
Paginator对象的 page()方法返回得到Page对象
不需要手动创建
属性
object_list:当前页上所有数据(对象)列表
number:当前页面的页码值
paginator:当前page对象关联的paginator对象
方法
has_next() 判断是否有下一页,如果有返回 True
has_previous() 判断是否有上一页,如果有返回 True
has_other_pages() 判断是否有上一页或者下一页,如果有返回 True
next_page_number() 返回下一页的页码,如果下一页不存在抛出InvalidPage异常
previous_page_number() 返回上一页的页码,如果上一页不存在,抛出InvalidPage异常
len() 返回当前页的数据(对象)个数
Paginator与Page对象关系(略)
代码示例:
配置路由:url(r'^studentpage/(\d+)/$', views.studentpage),
配置视图:
from .models import Students
from django.core.paginator import Paginator
def studentpage(request, pageid):
# 所有学生列表
allList = Students.objects.all()
paginator = Paginator(allList, 6)
page = paginator.page(pageid)
return render(request, 'myApp/studentpage.html', {"students": page})
配置html
studentpage.html中body标签中的内容:
<body>
<ul>
{% for stu in students %}
<li>
{{stu.sname}}--{{stu.sgrade}}
</li>
{% endfor %}
</ul>
<ul>
{% for index in students.paginator.page_range %}
{% if index == students.number %}
<li>
{{index}}
</li>
{% else %}
<li>
<a href="/sunck/studentpage/{{index}}">{{index}}</a>
</li>
{% endif %}
{% endif%}
</ul>
</body>
==============================================================================
ajax
需要动态生成,请求JSON数据
代码示例
ajaxstudents.html页面示例
<script type="text/javascript" src="/static/myApp/js/jquery-3.1.1.min.js"></script>
<body>
<h1>学生信息列表</h1>
<button id="btn">显示学生信息</button>
<script type="text/javascript" src="/static/myApp/js/sunck.js"></script>
</body>
sunck.js代码示例
$(document).ready(function (){
document.getElementById("btn").onclick = function (){
$.ajax({
type:"get",
url:"/studentsinfo/",
dataType:"json",
success:function(data, status){
console.log(data)
var d = data["data"]
for(var i=0; i<d.length; i++){
document.write('<p>' + d[i][0] + '</p>')
}
}
})
}
})
views.py代码示例
def ajaxstudents(request):
return render(request, 'myApp/ajaxstudents.html')
from django.http import JsonResponse
def studentsinfo(request):
stus = Students.objects.all()
list = []
for stu in stus:
list.append([stu.sname, stu.sage])
return JsonResponse({"data":list})
==============================================================================
富文本
pip install django-tinymce
在站点中使用
配置settings.py文件
INSTALLED_APPS 列表中添加 'tinymce',
增加
# 富文本
TINYMCE_DEFAULT_CONFIG = {
'theme':'advanced',
'width':600,
'height':400,
}
创建一个模型类:
在models.py文件中增加
from tinymce.models import HTMLField
class Text(models.Model):
str = HTMLField()
配置站点:
from .models import Text
admin.site.register(Text)
自定义视图使用
<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':'600',
})
</script>
</head>
<body>
<form action="/saveedit/" method="post">
<textarea name="str">sunck is a good man</textarea>
<input type="submit" value="提交"/>
</form>
</body>
Celery
http://docs.jinkan.org/docs/celery/
问题:
用户发起request,并且要等待response返回,但在视图中有一些耗时的操作,
导致用户可能会等待很长时间才能接收response,这样用户体验很差
网站每隔一段时间要同步一次数据,但是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 列表中添加 'djcelery',
# Celery
import djcelery
djcelery.setup_loader() # 初始化
BROKER_URL='redis://:sunck@127.0.0.1:6379/0'
CELERY_IMPORTS=('myApp.task')
在应用目录下创建task.py文件
迁移生成celery需要的数据库表:python manage.py migrate
在工程目录下的project目录下创建celery.py文件
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(bind=True)
def debug_task(self):
print('request: {0!r}'.format(self.request))
在工程目录下的 project目录下的 __init__.py文件中添加
网友评论