Django 0.5
1. MVC(model view controller)框架和MTV(model template view)框架: 耦合性低、重用性高、生命周期成本低
Django的MTV模式
Model(模型):负责业务对象与数据库的对象(ORM)
Template(模版):负责如何把页面展示给用户
View(视图):负责业务逻辑,并在适当的时候调用Model和Template
此外,Django还有一个urls分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template
2. Django视图系统views.py: 接收web请求request,并返回web响应responseHttpResponse,render,redirect等)
http://www.cnblogs.com/liwenzhou/articles/8305104.html
# 当浏览器向服务端请求一个页面时,Django创建一个HttpRequest对象(一般使用request参数承接这个对象),该对象包含关于请求的元数据。然后,Django加载相应的视图,将这个HttpRequest对象作为第一个参数传递给视图函数。每个视图负责返回一个HttpResponse对象。
1. FBV(function base view) 基于函数的视图
def add_class(request):
if request.method == "POST":
class_name = request.POST.get("class_name")
models.Classes.objects.create(name=class_name)
return redirect("/class_list/")
return render(request, "add_class.html")
#在urls中需如下调用
url(r'^publisher_list/', views.add_class), # FBV的注册方式
抛出一个问题:函数的装饰器能不能直接用来装饰类中的方法
2. CBV(class base view) 基于类的视图
from django.views import View
class AddClass(View):
def get(self, request):
return render(request, "add_class.html")
def post(self, request):
class_name = request.POST.get("class_name")
models.Classes.objects.create(name=class_name)
return redirect("/class_list/")
#在urls中需如下调用
url(r'^publisher_list/', views.AddClass.as_view()), # CBV的注册方式
# 具体用FBV还是CBV看需求。一般如果情况复杂,可考虑CBV,使结构更清晰
3. request请求相关的常用值
a. path_info 返回用户访问url(不包括域名)的路径,无参数
b. get_full_path() 回用户访问url(不包括域名)的路径,和参数
c. method 请求中使用的HTTP方法的字符串表示,全大写表示。
d. GET 包含所有HTTP GET参数的类字典对象
e. POST 包含所有HTTP POST参数的类字典对象
f. body 请求体中的数据,byte类型request.POST的数据就是从body里面提取到的;GET的为b'';POST的为b'name=****'
#补充,如果一个项目有多个app。在urls.py导入时,可以给不同app中的views.py文件取别名,进而引用。
from app02 import views as v2
4. 上传文件的注意事项:
1. 如果有上传文件,views.py中应该从request.FILES中取上传的文件对象。
# request.POST取出的是字符串['hlw.png'],不是上传的文件对象。
2. 如果有上传文件,html文件中的form表单一定要加enctype="multipart/form-data"
# 若不加,取出的是一个空的类似字典的对象 ,不是上传的文件对象。
换言之,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会包含数据。
3. chunks()是django帮忙封装的优化方法,可以考虑使用。
# views.py
def upload(request):
if request.method == "POST":
file_obj = request.FILES.get("touxiang") # 拿到上传文件对象
file_name = file_obj.name # 拿到文件名
with open(file_name, "wb") as f: # 在本地新建一个同名文件
for line in file_obj.chunks():#从上传的文件对象中一点一点读取数据
f.write(line) # 写到新建的文件中
return render(request, "upload_demo.html")
# .html
<form action="/upload/" method="post" enctype="multipart/form-data">
<input type="text" name="username">
<input type="file" name="touxiang">
<input type="submit" value="提交">
</form>
5. JsonResponse对象
Django封装的一个专门用来返回JSON格式数据的方法;是HttpResponse的子类
import json
HttpResponse(json.dumps(字典)) # HttpResponse()中只能传字符串
from django.http import JsonResponse
JsonResponse(字典) # JsonResponse()默认只接收字典类型
#以上两种方式,得到的结果相同
JsonResponse(列表,safe=False) # 默认只能传递字典类型,如果要传递非字典类型需要设置一下safe关键字参数。
6. Django shortcut functions之render()
#参数
request: 用于生成响应的请求对象。
template_name:要使用的模板的完整名称,可选的参数
context:添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它。
content_type:生成的文档要使用的MIME类型。默认为DEFAULT_CONTENT_TYPE 设置的值。默认为'text/html'
status:响应的状态码。默认为200。
using: 用于加载模板的模板引擎的名称。 #django支持第三方模版方法,如果使用其他模板,可通过using设置
7. Django shortcut functions之redirect()
默认情况下,redirect()返回的是临时重定向。若设置permanent=True将返回永久重定向。
临时重定向(响应状态码:302)和永久重定向(响应状态码:301)对普通用户来说是没什么区别的,它主要面向的是搜索引擎的机器人。
A页面临时重定向到B页面,那搜索引擎收录的就是A页面。
A页面永久重定向到B页面,那搜索引擎收录的就是B页面。
3. 模板语言
http://www.cnblogs.com/liwenzhou/p/7931828.html
1. 目前已经学到的模板语言内容
# 变量相关用{{ }},逻辑相关用{% %}
1. {{变量}}
2. {% 逻辑操作%}
1. for循环
{% for i in list %}
{{ i }}
{% endfor %}
forloop.counter
forloop.counter0
forloop.last
{% empty %}
2. if判断
{% if 条件%}
条件成立要做的事儿
{% else %}
条件不成立要做的事儿
{% endif %}
3. 逻辑判断
1. in 判断
2. == 判断
2. 模板语言变量相关(点所有)
1. 字典的key对应的值
{{ dic.key}}
2. 列表按索引取值
{{ list.1 }}
3. 对象的属性和方法
{{ obj.name }}
{{ obj.dream }} --> 方法不要加括号,django自动帮助补全拼接
3. Filters (对变量做一些额外的操作)
{{ value|filter_name:参数}} # '|'左右没有空格没有空格没有空格
1. 内置的filter
{{ value|default: "nothing"}} # 如果value值没传的话就显示nothing
{{ value|length }} # 返回value的长度,如value=['a', 'b', 'c', 'd']的话,就显示4.
{{ value|filesizeformat }} # 如果value 是123456789,输出将会是117.7 MB。
{{value|slice:"2:-1"}}
{{ value|date:"Y-m-d H:i:s"}}
{{ value|safe}} # 告诉Django这段代码是安全的不必转义。
# 为保证安全,Django的模板中会对HTML标签和JS等语法标签进行自动转义。若不希望转译,可设置safe
2. 自定义的filter
1. 在app下面新建一个Python package,包名必须叫templatetags
2. 在上面的包中新建一个python文件(用于存放自定义filter的文件),里面定义函数,并且注册到django的模板语言
from django import template
# 生成一个用于注册自定义filter方法的实例
register = template.Library()
@register.filter(name="sb")
def add_sb(value):
return "{} sb".format(value)
@register.filter(name="add")
def add(value, arg):
return "{} {}".format(value, arg)
3. 使用自定义的filter方法 #在html中
{% load py文件名%}
{{ value|sb }}
{{ name|add:"super dsb" }}
4. truncatechars
{{ value|truncatechars:9}} # 显示6个原文字符+三个. ;如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。
5. Tags #和Filters相比,Tags功能更丰富,支持逻辑等
# for
<ul>
{% for user in user_list %}
<li>{{ user.name }}</li>
{% endfor %}
</ul>
forloop.counter 当前循环的索引值(从1开始)
forloop.counter0 当前循环的索引值(从0开始)
forloop.revcounter当前循环的倒序索引值(从1开始)
forloop.revcounter0 当前循环的倒序索引值(从0开始)
forloop.first 当前循环是不是第一次循环(布尔值)
forloop.last 当前循环是不是最后一次循环(布尔值)
forloop.parentloop 本层循环的外层循环
{% empty %}
# if,elif,else
{% if user_list %}
用户人数:{{ user_list|length }}
{% elif black_list %}
黑名单数:{{ black_list|length }}
{% else %}
没有用户
{% endif %}
if语句支持and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。
# with (定义一个中间变量;取别名)
{% with total=business.employees.count %}
{{ total }} employee{{ total|pluralize }}
{% endwith %}
6. 注意事项
1. Django的模板语言不支持连续判断,即不支持以下写法:
{% if a > b > c %}
...
{% endif %}
#python支持连续判断,但如果用Django模板,则不能使用连续判断
若a=10, b=20, c=-5, 判断a>b>c的布尔值
python: False; a>b and b>c -> False
HTML: True; a>b ->False, False>-5 => 0>-5 -> True
2. Django的模板语言中属性的优先级大于方法
def xx(request):
d = {"a": 1, "b": 2, "c": 3, "items": "100"}
return render(request, "xx.html", {"data": d})
{{ data.items } # 默认会取d的items key的值。
7. 母版与继承
1. 定义母版 --> 其他很多页面会用到的共用部分 我们可以提取出来放在单独的一个html文件中
2. 在母版中,通过定义不同的block 等待子页面来替换对应的内容
3. 在子页面中,通过{% extends 'base.html '%}来继承已经定义好的母版
# 继承语句要放在子模板的最上方
4. 在子页面中通过block 来实现自定义页面内容
{% extends 'base.html '%}
{% block page-main %}
<p>世情薄</p>
<p>人情恶</p>
<p>雨送黄昏花易落</p>
{% endblock %}
5. 通常会在母版中定义 子页面专用的page-css 和page-js 两个块,方便子页面替换
#base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
{% block page-css %} # 某些子页面单独用的css可置于此
{% endblock %}
</head>
<body>
<h1>这是母板的标题</h1>
{% block page-main %}
{% endblock %}
<h1>母板底部内容</h1>
{% block page-js %}
{% endblock %}
</body>
</html>
8.组件
把功能相对独立的html代码(导航条,页尾信息等)放在一个单独的文件中 作为组件 供其他页面使用
{% include 'nav.html' %} # 放在body里
# 以nav.html为例,只放<nav>...</nav>即可
#补充
一般brower会自动帮忙加载缓存,但当开发时,不希望缓存干扰测试结果,可在检查页面做如下设置