Django 框架 基本知识
一、什么事web框架
框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支持结构,使用框架可以使我们快速开发特定的系统,简单来说,就是讲实现方式的底层结构进行封装,提供相应的接口给开发人员。通俗来讲,就像一个搭建好的舞台,我们开发人员就可以通过这个舞台尽情的表演节目。
二、什么是web应用
对应所有的web应用,其本质来说就是一个socket服务端,而浏览器就是socket客户端:
from socket import * #服务端 IP_PORT = ("127.0.0.1",8080) BACK_LOG = 5 BUFFER_SIZE = 1024 sever = socket(AF_INET,SOCK_STREAM) sever.bind(IP_PORT) sever.listen(BACK_LOG) conn,addr = sever.accept() try: while True: data = conn.recv(BUFFER_SIZE) print("收到数据:",data.decode("utf-8")) deal_data = data.decode("utf-8").upper() conn.send(deal_data.encode("utf-8")) print("发送数据:",deal_data) except ConnectionResetError as e: print(e) sever.close()
from socket import *
#客户端 IP_PORT = ("127.0.0.1",8080) BUFFER_SIZE = 1024 #建立连接 client = socket(AF_INET,SOCK_STREAM) #生成套接字对象 client.connect(IP_PORT) #连接到对应的端口 #数据传输 data = input(">>:") client.send(data.encode("utf-8")) sever_data= client.recv(BUFFER_SIZE) print("success recv:" ,sever_data.decode("utf-8"))
三、什么是Django
Django是一个开放源代码的Web应用框架,由Python写成。采用了MTV的框架模式,即模型M,模板T和视图V。它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是CMS(内容管理系统)软件。并于2005年7月在BSD许可证下发布。这套框架是以比利时的吉普赛爵士吉他手Django Reinhardt来命名的。
四、Django的MTV模式
Django是一个基于MVC构造的框架。但是在Django中,控制器接受用户输入的部分由框架自行处理,所以 Django 里更关注的是模型(Model)、模板(Template)和视图(Views),称为 MTV模式。
模型(Model),即数据存取层 |
处理与数据相关的所有事务: 如何存取、如何验证有效性、包含哪些行为以及数据之间的关系等。 |
模板(Template),即业务逻辑层 |
处理与表现相关的决定: 如何在页面或其他类型文档中进行显示。 |
视图(View),即表现层 |
存取模型及调取恰当模板的相关逻辑。模型与模板的桥梁。 |
五、Django基本命令
安装Django框架后,就可以创建Django项目:
django-admin.py startproject mysite
创建完成后,会生成一下目录:
- manage.py ----- Django项目里面的工具,通过它可以调用django shell和数据库等。
- settings.py ---- 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量,主要就是一些Djanjo项目的配置信息。
- urls.py ---- 负责把URL模式映射到应用程序,这样就可以通过ip和端口及路由访问服务器。
创建项目完成后,就可以创建应用:
python manage.py startapp blog
admin:
apps:
migrations:
models:一般是创建一些数据库想表
views:视图,处理服务端的一系列逻辑,通过客户端访问实现的逻辑就在这。
这样我们就可以启动我们的项目了:
python manage.py runsever 8080 #8080是端口号
这样我们的django就启动起来了!当我们访问:http://127.0.0.1:8080/时就可以看到:
Django 项目环境的终端
python manage.py shell
作用:这个命令和 直接运行 python 进入 shell 的区别是:你可以在这个 shell 里面调用当前项目的 models.py 中的 API,对于操作数据的测试非常方便。
Django 查看所有指令
python manage.py
static的配置:#3、STATIC文件还可以配置STATICFILES_DIRS,指定额外的静态文件存储位置。 # STATIC_URL的含义与MEDIA_URL类似。
# ---------------------------------------------------------------------------- #注意1: #为了后端的更改不会影响前端的引入,避免造成前端大量修改 STATIC_URL = '/static/' #引用名 STATICFILES_DIRS = ( os.path.join(BASE_DIR,"statics") #实际名 ,即实际文件夹的名字 )
#这里的BASE_DIR在配置文件settings上已经有了,我们直接引用就可以了 #django对引用名和实际名进行映射,引用时,只能按照引用名来,不能按实际名去找 #<script src="/statics/jquery-3.1.1.js"></script> #------error-----不能直接用,必须用STATIC_URL = '/static/': #<script src="/static/jquery-3.1.1.js"></script>
同理:
#在客户端访问时,服务端返回的静态文件路径也是static,而不是实际的statics路径
#注意2(statics文件夹写在不同的app下,静态文件的调用): STATIC_URL = '/static/' STATICFILES_DIRS=( ('hello',os.path.join(BASE_DIR,"app01","statics")) , ) #<script src="/static/hello/jquery-1.8.2.min.js"></script> #注意3: STATIC_URL = '/static/'
<head>
{% load staticfiles %} #在html引入静态文件时比较推荐用的一种方式,
</head> # <script src={% static "jquery-1.8.2.min.js" %}></script>
路由配置系统:
URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。
URL格式:
'''
urlpatterns = [ url(正则表达式, views视图函数,参数,别名),
] 参数说明: 一个正则表达式字符串 一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串 可选的要传递给视图函数的默认参数(字典形式) 一个可选的name参数 '''
新版本:
urlpatterns = [
path(路由名/[<converters:html参数>],views视图函数,参数,别名)
re_path(正则表达式,views视图函数,参数,别名) 和 url一样
]
converters:指的是转换器,可以将html接收到的数据进行类型转换,默认支持的转换器有:
- str,匹配除了路径分隔符(
/
)之外的非空字符串,这是默认的形式 - int,匹配正整数,包含0。
- slug,匹配字母、数字以及横杠、下划线组成的字符串。
- uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
- path,匹配任何非空字符串,包含了路径分隔符
别名:为你的 URL 取名能使你在 Django 的任意地方唯一地引用它,尤其是在模板中。这个有用的特性允许你只改一个文件就能全局地修改某个 URL 模式。
当然可以自定制转换器,可以在Django里面查询。
url解析和传入方式:
#从上到下解析,知道找到就执行 urlpatterns = [ path('admin/', admin.site.urls), path('show/',views.show_time), path('show/<int:year>/<int:month>/',views.show_time), #带名字传入 re_path('show/[0-9]+/',views.hello), #使用了正则必须用re_path re_path('show/?P<name>[0-9]/?P<month>[0-9]{2}/',views.show_time) #带名字传入 ]
关于别名的例子:
path('ab_name/',views.ab,name="abc") #用name变量表示别名 #在前端模板使用别名 <form action="{% url 'abc' %}"> <input type="submit"> </form>
编写视图
一个视图函数,或者简短来说叫做视图,是一个简单的Python函数或者也可以类,它接受web请求,并且返回web响应。响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. . . 是任何东西都可以。无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你的Python目录下面。除此之外没有更多的要求了——可以说“没有什么神奇的地方”。为了能够把代码放在某个地方,惯例是把视图放在叫做views.py的文件中,然后把它放到你的项目或者应用目录里。
下面是一个简单的返回时间的视图:
from django.shortcuts import render,HttpResponse from datetime import datetime # Create your views here. def show_time(request): return render(request,"showTime.html",{"time":datetime.now()})
url分发:解决项目过大时,路由过多,降低其耦合性的问题
配置其url:
主路由:
urlpatterns = [ path('admin/', admin.site.urls), path('blog/',include('blog.urls')), ] 通过include来关联url blog:一般是你app的路径,这个路径下必须有一个urls
from django.urls import path, re_path, include from blog import views urlpatterns = [ path('show/',views.show_time), path('show/<int:year>/<int:month>/',views.show_time), #带名字传入 re_path('show/[0-9]+/',views.hello), #使用了正则必须用re_path re_path('show/?P<name>[0-9]/?P<month>[0-9]{2}/',views.show_time), #带名字传入 ] #在新的urls下写自己的路由已经关联的视图函数
访问的时候/blog加上你要访问的路由即可
步骤:
- 从django.shortcuts中导入render模块,HttpResponse模块有类似的功能,会在下面说到
- 接着,我们定义了show_time函数。它是一个视图函数。每个视图函数都应接收HttpRequest对象作为第一个参数,一般叫做request。
- 在视图里面的函数不能一样,这样不好识别
- 返回一个render对象,这个对象会调用HttpResponse,这个对象包含响应,可以这么说每个视图函数都要返回HttpResponse对象
注意:
http请求-响应过程中有两个核心的对象:
Http请求对象:HttpRequest
Http响应对象:HttpResponse
所在位置:django.http
快捷函数:也就是一些类似于render的返回请求的函数
request对象的属性和方法:
属性: django将请求报文中的请求行、首部信息、内容主体封装成 HttpRequest 类中的属性。除了特殊说明的之外,其他均为只读的。 1.HttpRequest.scheme 一个字符串,代表请求的方案,一般为 ‘http’ 或 ‘https’。 2.HttpRequest.body 一个字符串,代表请求报文的主体。在处理非 HTTP 形式的报文时非常有用,例如:二进制图片、XML等。 但是,如果要处理表单数据的时候,推荐还是使用 HttpRequest.POST 。 另外,我们还可以用 python 的类文件方法去操作它,详情参考 HttpRequest.read() 。 3.HttpRequest.path 一个字符串,表示请求的路径组件(不含域名)。 例如:"/music/bands/the_beatles/" 4.HttpRequest.path_info 一个字符串,在某些 Web 服务器配置下,主机名后的 URL 部分被分成脚本前缀部分和路径信息部分。path_info 属性将始终包含路径信息部分,不论使用的Web 服务器是什么。使用它代替 path 可以让代码在测试和开发环境中更容易地切换。 例如,如果应用的WSGIScriptAlias 设置为"/minfo",那么当 path 是"/minfo/music/bands/the_beatles/" 时path_info 将是"/music/bands/the_beatles/"。 5.HttpRequest.method 一个字符串,表示请求使用的HTTP 方法。必须使用大写。 例如:"GET"、"POST" 6.HttpRequest.encoding 一个字符串,表示提交的数据的编码方式(如果为 None 则表示使用 DEFAULT_CHARSET 的设置,默认为 'utf-8')。这个属性是可写的,你可以修改它来修改访
问表单数据使用的编码。接下来对属性的任何访问(例如从 GET 或 POST 中读取数据)将使用新的 encoding 值。如果你知道表单数据的编码不是 DEFAULT_CHARSET ,则使用它。
7.HttpRequest.GET 一个类似于字典的对象,包含 HTTP GET 的所有参数。详情请参考 QueryDict 对象。 8.HttpRequest.POST 一个类似于字典的对象,如果请求中包含表单数据,则将这些数据封装成 QueryDict 对象。 POST 请求可以带有空的 POST 字典 —— 如果通过 HTTP POST 方法发送一个表单,但是表单中没有任何的数据,QueryDict 对象依然会被创建。因此,不应该使用 if request.POST 来检查使用的是否是POST 方法;应该使用 if request.method == "POST" 另外:如果使用 POST 上传文件的话,文件信息将包含在 FILES 属性中。 9.HttpRequest.REQUEST 一个类似于字典的对象,它首先搜索POST,然后搜索GET,主要是为了方便。灵感来自于PHP 的 $_REQUEST。 例如,如果 GET = {"name": "john"} 而 POST = {"age": '34'} , REQUEST["name"] 将等于"john", REQUEST["age"] 将等于"34"。 强烈建议使用 GET 和 POST 而不要用REQUEST,因为它们更加明确。 10.HttpRequest.COOKIES 一个标准的Python 字典,包含所有的cookie。键和值都为字符串。 11.HttpRequest.FILES 一个类似于字典的对象,包含所有的上传文件信息。FILES 中的每个键为<input type="file" name="" /> 中的name,值则为对应的数据。 注意,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会包含数据。否则,FILES 将为一个空的类似于字典的对象。 12.HttpRequest.META 一个标准的Python 字典,包含所有的HTTP 首部。具体的头部信息取决于客户端和服务器,下面是一些示例: CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。 CONTENT_TYPE —— 请求的正文的MIME 类型。 HTTP_ACCEPT —— 响应可接收的Content-Type。 HTTP_ACCEPT_ENCODING —— 响应可接收的编码。 HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。 HTTP_HOST —— 客服端发送的HTTP Host 头部。 HTTP_REFERER —— Referring 页面。 HTTP_USER_AGENT —— 客户端的user-agent 字符串。 QUERY_STRING —— 单个字符串形式的查询字符串(未解析过的形式)。 REMOTE_ADDR —— 客户端的IP 地址。 REMOTE_HOST —— 客户端的主机名。 REMOTE_USER —— 服务器认证后的用户。 REQUEST_METHOD —— 一个字符串,例如"GET" 或"POST"。 SERVER_NAME —— 服务器的主机名。 SERVER_PORT —— 服务器的端口(是一个字符串)。 从上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,请求中的任何 HTTP 首部转换为 META 的键时,都会将所有字母大写并将连接符替换
为下划线最后加上 HTTP_ 前缀。所以,一个叫做 X-Bender 的头部将转换成 META 中的 HTTP_X_BENDER 键。
13.HttpRequest.user
一个 AUTH_USER_MODEL 类型的对象,表示当前登录的用户。
如果用户当前没有登录,user 将设置为 django.contrib.auth.models.AnonymousUser 的一个实例。你可以通过 is_authenticated() 区分它们。
HttpRequest方法:
1.HttpRequest.read(size=None)
像文件一样读取请求报文的内容主体,同样的,还有以下方法可用。
HttpRequest.readline()
HttpRequest.readlines()
HttpRequest.xreadlines()
其行为和文件操作中的一样。
HttpRequest.__iter__():说明可以使用 for 的方式迭代文件的每一行。
注意:我们在视图如果调用HttpRequest对象,一般会在创建视图时,使用request来生成一个HttpRequest对象
def show_time(request): 这里的request就是用来生成一个httpRequest: 这个request只是一个名字默认,可以修改 print(request.path) return render(request,"showTime.html",{"time":datetime.now()})
HttpResponse:
对于HttpRequest对象来说,是由Django自动创建的,但是HttpResponse对象必须我们自己创建,每个视图(view)请求处理方法必须返回一个HttpResponse对象
from django.shortcuts import render,HttpResponse from datetime import datetime # Create your views here. def hello(request): return HttpResponse("hello")
HttpResponse常用的扩展方法:
网页渲染: render() render_to_response() 两者唯一区别: render需要request而后者不要 路由跳转: redirect() locals: 可以直接将函数中的所有变量传给模板
render函数:
---------------render(request, template_name[, context]) 结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象。 参数: request: 用于生成响应的请求对象。 template_name:要使用的模板的完整名称,可选的参数 context:添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它。 content_type:生成的文档要使用的MIME类型。默认为DEFAULT_CONTENT_TYPE 设置的值。 status:响应的状态码。默认为200。
redirect函数:
#redirect 路由跳转,即从当前运行的url跳转到另一个url上 -----------------------------------url.py url(r"login", views.login), url(r"yuan_back", views.yuan_back), def run(): return redirect("/login") 从这个视图跳转到另一个路由上
模板(Template)
模板系统简介
-
对页面设计进行的任何改变都必须对 Python 代码进行相应的修改。 站点设计的修改往往比底层 Python 代码的修改要频繁得多,因此如果可以在不进行 Python 代码修改的情况下变更设计,那将会方便得多。
-
Python 代码编写和 HTML 设计是两项不同的工作,大多数专业的网站开发环境都将他们分配给不同的人员(甚至不同部门)来完成。 设计者和HTML/CSS的编码人员不应该被要求去编辑Python的代码来完成他们的工作。
-
程序员编写 Python代码和设计人员制作模板两项工作同时进行的效率是最高的,远胜于让一个人等待另一个人完成对某个既包含 Python又包含 HTML 的文件的编辑工作。
基于这些原因,将页面的设计和Python的代码分离开会更干净简洁更容易维护。 我们可以使用 Django的 模板系统 (Template System)来实现这种模式,这就是本章要具体讨论的问题。
Python的模板:HTML代码+逻辑控制代码
模板语法:
{{ 变量 }} ----------------------------------Template和Context对象 >>> python manange.py shell (进入该django项目的环境) >>> from django.template import Context, Template >>> t = Template('My name is {{ name }}.') >>> c = Context({'name': 'Stephane'}) >>> t.render(c) 'My name is Stephane.' # 同一模板,多个上下文,一旦有了模板对象,你就可以通过它渲染多个context,无论何时我们都可以 # 像这样使用同一模板源渲染多个context,只进行 一次模板创建然后多次调用render()方法渲染会 # 更为高效: # Low for name in ('John', 'Julie', 'Pat'): t = Template('Hello, {{ name }}') print t.render(Context({'name': name})) # Good t = Template('Hello, {{ name }}') for name in ('John', 'Julie', 'Pat'): print t.render(Context({'name': name}))
Django 模板解析非常快捷。 大部分的解析工作都是在后台通过对简短正则表达式一次性调用来完成。 这和基于 XML 的模板引擎形成鲜明对比,那些引擎承担了 XML 解析器的开销,且往往比 Django 模板渲染引擎要慢上几个数量级。
from django.shortcuts import render,HttpResponse from django.template.loader import get_template #记得导入 # Create your views here. import datetime from django.template import Template,Context # def current_time(req): #原始的视图函数 # now=datetime.datetime.now() # html="<html><body>现在时刻:<h1>%s.</h1></body></html>" %now # return HttpResponse(html) # def current_time(req): #django模板修改的视图函数 # now=datetime.datetime.now() # t=Template('<html><body>现在时刻是:<h1 style="color:red">{{current_date}}</h1></body></html>') #t=get_template('current_datetime.html') # c=Context({'current_date':now}) # html=t.render(c) # return HttpResponse(html) #另一种写法(推荐) def current_time(request): now=datetime.datetime.now() return render(request, 'current_datetime.html', {'current_date':now})
深度变量查找:
----------------------------------Template和Context对象 >>> python manange.py shell (进入该django项目的环境) >>> from django.template import Context, Template >>> t = Template('My name is {{ name }}.') >>> c = Context({'name': 'Stephane'}) >>> t.render(c) 'My name is Stephane.' # 同一模板,多个上下文,一旦有了模板对象,你就可以通过它渲染多个context,无论何时我们都可以 # 像这样使用同一模板源渲染多个context,只进行 一次模板创建然后多次调用render()方法渲染会 # 更为高效: # Low for name in ('John', 'Julie', 'Pat'): t = Template('Hello, {{ name }}') print t.render(Context({'name': name})) # Good t = Template('Hello, {{ name }}') for name in ('John', 'Julie', 'Pat'): print t.render(Context({'name': name})) 复制代码 Django 模板解析非常快捷。 大部分的解析工作都是在后台通过对简短正则表达式一次性调用来完成。 这和基于 XML 的模板引擎形成鲜明对比,那些引擎承担了 XML 解析器的开销,且往往比 Django 模板渲染引擎要慢上几个数量级。 复制代码 from django.shortcuts import render,HttpResponse from django.template.loader import get_template #记得导入 # Create your views here. import datetime from django.template import Template,Context # def current_time(req): #原始的视图函数 # now=datetime.datetime.now() # html="<html><body>现在时刻:<h1>%s.</h1></body></html>" %now # return HttpResponse(html) # def current_time(req): #django模板修改的视图函数 # now=datetime.datetime.now() # t=Template('<html><body>现在时刻是:<h1 style="color:red">{{current_date}}</h1></body></html>') #t=get_template('current_datetime.html') # c=Context({'current_date':now}) # html=t.render(c) # return HttpResponse(html) #另一种写法(推荐) def current_time(req): now=datetime.datetime.now() return render(req, 'current_datetime.html', {'current_date':now}) 复制代码 4.2.2 深度变量的查找(万能的句点号) 在到目前为止的例子中,我们通过 context 传递的简单参数值主要是字符串,然而,模板系统能够非常简洁地处理更加复杂的数据结构,例如list、dictionary和自定义的对象。在 Django 模板中遍历复杂数据结构的关键是句点字符 (.)。 #最好是用几个例子来说明一下。
'''
用 . 号来访问字典,类,函数以及 .索引值的方式就可以访问这些对象的属性
'''
# 首先,句点可用于访问列表索引,例如: >>> from django.template import Template, Context >>> t = Template('Item 2 is {{ items.2 }}.') >>> c = Context({'items': ['apples', 'bananas', 'carrots']}) >>> t.render(c) 'Item 2 is carrots.' #假设你要向模板传递一个 Python 字典。 要通过字典键访问该字典的值,可使用一个句点: >>> from django.template import Template, Context >>> person = {'name': 'Sally', 'age': '43'} >>> t = Template('{{ person.name }} is {{ person.age }} years old.') >>> c = Context({'person': person}) >>> t.render(c) 'Sally is 43 years old.' #同样,也可以通过句点来访问对象的属性。 比方说, Python 的 datetime.date 对象有 #year 、 month 和 day 几个属性,你同样可以在模板中使用句点来访问这些属性: >>> from django.template import Template, Context >>> import datetime >>> d = datetime.date(1993, 5, 2) >>> d.year 1993 >>> d.month 5 >>> d.day 2 >>> t = Template('The month is {{ date.month }} and the year is {{ date.year }}.') >>> c = Context({'date': d}) >>> t.render(c) 'The month is 5 and the year is 1993.' # 这个例子使用了一个自定义的类,演示了通过实例变量加一点(dots)来访问它的属性,这个方法适 # 用于任意的对象。 >>> from django.template import Template, Context >>> class Person(object): ... def __init__(self, first_name, last_name): ... self.first_name, self.last_name = first_name, last_name >>> t = Template('Hello, {{ person.first_name }} {{ person.last_name }}.') >>> c = Context({'person': Person('John', 'Smith')}) >>> t.render(c) 'Hello, John Smith.' # 点语法也可以用来引用对象的方法。 例如,每个 Python 字符串都有 upper() 和 isdigit() # 方法,你在模板中可以使用同样的句点语法来调用它们: >>> from django.template import Template, Context >>> t = Template('{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}') >>> t.render(Context({'var': 'hello'})) 'hello -- HELLO -- False' >>> t.render(Context({'var': '123'})) '123 -- 123 -- True' # 注意这里调用方法时并* 没有* 使用圆括号 而且也无法给该方法传递参数;你只能调用不需参数的 # 方法。
模板中:变量的过滤器的使用
语法格式: {{obj|filter:param}}
# 1 add : 给变量加上相应的值 # # 2 addslashes : 给变量中的引号前加上斜线 # # 3 capfirst : 首字母大写 # # 4 cut : 从字符串中移除指定的字符 # # 5 date : 格式化日期字符串 # # 6 default : 如果值是False,就替换成设置的默认值,否则就是用本来的值 # # 7 default_if_none: 如果值是None,就替换成设置的默认值,否则就使用本来的值 #实例: #value1="aBcDe" {{ value1|upper }}<br> #value2=5 {{ value2|add:3 }}<br> #value3='he llo wo r ld' {{ value3|cut:' ' }}<br> #import datetime #value4=datetime.datetime.now() {{ value4|date:'Y-m-d' }}<br> #value5=[] {{ value5|default:'空的' }}<br> #value6='<a href="#">跳转</a>' {{ value6 }} {% autoescape off %} {{ value6 }} {% endautoescape %} {{ value6|safe }}<br> {{ value6|striptags }} #value7='1234' {{ value7|filesizeformat }}<br> {{ value7|first }}<br> {{ value7|length }}<br> {{ value7|slice:":-1" }}<br> #value8='http://www.baidu.com/?a=1&b=3' {{ value8|urlencode }}<br> value9='hello I am yuan'
标签(tag)的使用
语法格式: {% tags %}
{% if %}的使用
{% if %}标签计算一个变量值,如果是“true”,即它存在、不为空并且不是false的boolean值,系统则会显示{% if %}和{% endif %}间的所有内容
{% if num >= 100 and 8 %} {% if num > 200 %} <p>num大于200</p> {% else %} <p>num大于100小于200</p> {% endif %} {% elif num < 100%} <p>num小于100</p> {% else %} <p>num等于100</p> {% endif %} {% if %} 标签接受and,or或者not来测试多个变量值或者否定一个给定的变量 {% if %} 标签不允许同一标签里同时出现and和or,否则逻辑容易产生歧义,例如下面的标签是不合法的: {% if obj1 and obj2 or obj3 %}
{% for %}的使用
{% for %}标签允许你按顺序遍历一个序列中的各个元素,每次循环模板系统都会渲染{% for %}和{% endfor %}之间的所有内容
<ul> {% for obj in list %} <li>{{ obj.name }}</li> {% endfor %} </ul> #在标签里添加reversed来反序循环列表: {% for obj in list reversed %} ... {% endfor %} #{% for %}标签可以嵌套: {% for country in countries %} <h1>{{ country.name }}</h1> <ul> {% for city in country.city_list %} <li>{{ city }}</li> {% endfor %} </ul> {% endfor %} #系统不支持中断循环,系统也不支持continue语句,{% for %}标签内置了一个forloop模板变量, #这个变量含有一些属性可以提供给你一些关于循环的信息 1,forloop.counter表示循环的次数,它从1开始计数,第一次循环设为1: {% for item in todo_list %} <p>{{ forloop.counter }}: {{ item }}</p> {% endfor %} 2,forloop.counter0 类似于forloop.counter,但它是从0开始计数,第一次循环设为0 3,forloop.revcounter 4,forloop.revcounter0 5,forloop.first当第一次循环时值为True,在特别情况下很有用: {% for object in objects %} {% if forloop.first %}<li class="first">{% else %}<li>{% endif %} {{ object }} </li> {% endfor %} # 富有魔力的forloop变量只能在循环中得到,当模板解析器到达{% endfor %}时forloop就消失了 # 如果你的模板context已经包含一个叫forloop的变量,Django会用{% for %}标签替代它 # Django会在for标签的块中覆盖你定义的forloop变量的值 # 在其他非循环的地方,你的forloop变量仍然可用 #{% empty %} {{li }} {% for i in li %} <li>{{ forloop.counter0 }}----{{ i }}</li> {% empty %} <li>this is empty!</li> {% endfor %} # [11, 22, 33, 44, 55] # 0----11 # 1----22 # 2----33 # 3----44 # 4----55
csrf_token标签
用于生成csrf_token的标签,用于防治跨站攻击验证。 其实,这里是会生成一个input标签,和其他表单标签一起提交给后台的。
若不添加则,出现403的报错 :
{% csrf_token %}
#用于在post提交时的,而出现的报错问题:因为在浏览器第一次进行post提交数据时,服务端会认为是不安全的,但是如果加上这个代码,则回带着一个密钥访问服务端,这样就不会报错 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', ]
{% with %}
用更简单的变量名替代复杂的变量名
{% with total=fhjsaldfhjsdfhlasdfhljsdal %} {{ total }} {% endwith %}
加载标签库:自定义filter和simple_tag
a、在应用中创建templatetags模块(必须做)
b、创建 .py文件例如:my_tags
c、创建自定义标签或过滤器filter
from django import template from django.utils.safestring import mark_safe register = template.Library() # register名字是固定的,不可以改变 #自定义过滤器 filter @register.filter #用装饰器装饰我们新定义的filter函数 def filter_multi(v1,v2): #在filter 最多有两个参数,一个是其本身,一个是我们传过去操作的数据,但第二个参数可以是列表 return v1+v2 #自定义标签 @register.simple_tag #可以任意个参数 def my_singer(v1,v2,v3): return v1 +v2+v3
d、使用方式
{% load my_tags %} #在使用之前必须导入 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> #过滤器 只能传一个参数,参数与过滤器名用:隔开 {{ 3|filter_multi:3 }}
#标签 可以传多个参数 参数与参数之间用空格隔开,不能用在控制语句中 {% my_singer 3 4 5 %} </body> </html>
extend模板继承
到目前为止,我们的模板范例都只是些零星的 HTML 片段,但在实际应用中,你将用 Django 模板系统来创建整个 HTML 页面。 这就带来一个常见的 Web 开发问题:
在整个网站中,如何减少共用页面区域(比如站点导航)所引起的重复和冗余代码?Django 解决此类问题的首选方法是使用一种优雅的策略—— 模板继承 。
本质上来说,模板继承就是先构造一个基础框架模板,而后在其子模板中对它所包含站点公用部分和定义块进行重载。
让我们通过修改 current_datetime.html 文件,为 current_datetime 创建一个更加完整的模板来体会一下这种做法:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title>The current time</title> </head> <body> <h1>My helpful timestamp site</h1> <p>It is now {{ current_date }}.</p> 当前使用的一些信息 <hr> <p>Thanks for visiting my site.</p> </body> </html>
如何替换上面的p标签呢?
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title>Future time</title> </head> <body> <h1>My helpful timestamp site</h1> <p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p> #我们重写一个html <hr> <p>Thanks for visiting my site.</p> </body> </html>
从上面可以看到,我们通过重新写一个html页面,但我们却仅仅修改了其中一部分,代码量虽然不多,但当我们建一个大型网站的时候,这种html页面相同的地方肯定很多,
所以说,为了减少我们的代码量,让开发变得更加简洁优雅,可以使用模板的继承来做这些事情:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title>{% block title %}{% endblock %}</title> #这里加上一些block块,表示这是可能要改变的地方 </head> <body> <h1>My helpful timestamp site</h1> {% block content %}{% endblock %} #这里也加上了一下block块,可能要改变的地方 block后面跟块的名字 {% block footer %} <hr> <p>Thanks for visiting my site.</p> {% endblock %} #必须要有结束语 </body> </html>
这个叫做 base.html 的模板定义了一个简单的 HTML 框架文档,我们将在本站点的所有页面中使用。 子模板的作用就是重载、添加或保留那些块的内容。 (如果你一直按顺序学习到这里,保存这个文件到你的template目录下,命名为 base.html .)
我们使用模板标签: {% block %} 。 所有的 {% block %} 标签告诉模板引擎,子模板可以重载这些部分。 每个{% block %}标签所要做的是告诉模板引擎,该模板下的这一块内容将有可能被子模板覆盖。
现在我们已经有了一个基本模板,我们可以修改 current_datetime.html 模板来 使用它:
{% extends "base.html" %} #继承我们定义的基础模板 {% block title %}The current time{% endblock %} #改变对应块的包含的内容 {% block content %} <p>It is now {{ current_date }}.</p> {% endblock %}
注意:
<1>如果在模板中使用 {% extends %} ,必须保证其为模板中的第一个模板标记。 否则,模板继承将不起作用。 <2>一般来说,基础模板中的 {% block %} 标签越多越好。 记住,子模板不必定义父模板中所有的代码块,因此 你可以用合理的缺省值对一些代码块进行填充,然后只对子模板所需的代码块进行(重)定义。 俗话说,钩子越 多越好。 <3>如果发觉自己在多个模板之间拷贝代码,你应该考虑将该代码段放置到父模板的某个 {% block %} 中。 如果你需要访问父模板中的块的内容,使用 {{ block.super }}这个标签吧,这一个魔法变量将会表现出父模 板中的内容。 如果只想在上级代码块基础上添加内容,而不是全部重载,该变量就显得非常有用了。 <4>不允许在同一个模板中定义多个同名的 {% block %} 。 存在这样的限制是因为block 标签的工作方式是双向的。 也就是说,block 标签不仅挖了一个要填的坑,也定义了在父模板中这个坑所填充的内容。如果模板中出现了两个 相同名称的 {% block %} 标签,父模板将无从得知要使用哪个块的内容。
模板导入:将一部分经常使用的html代码写在一个html文件,遇到使用的地方就将其导入。用:{% include a.html %}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title></title> 方 </head> <body> {% include a.html %} #我想在这个地方导入进程使用的回htmll代码 </body> </html>