一、视图层(view)
视图函数,本质上就是一个python函数,他接受web请求并返回响应。响应内容可以是HTML网页、重定向、404错误等任何东西,但本质都是返回一个HttpResponse对象。视图函数约定俗成写在view.py文件内
二、请求对象-HttpRequest
request对象 部分常用属性
当一个页面被请求时, django将请求报文中的请求行、首部信息、内容主题封装成HttpRequest类中的属性 。
Django会将这个对象自动传递给响应的视图函数,一般视图函数约定俗成地使用 request 参数承接这个对象。
1. request.method #方式,返回的是纯大写的字符串。 2. request.GET #获取用户提交的get请求数据,返回的是列表套对象。 3. request.GET.get() #获取列表中的最后一个 4. request.GET.getlist() #获取列表类型的数据 5. request.POST #获取用户提交的post请求数据 6. request.POST.get() #获取列表中的最后一个 7. request.POST.getlist() #获取列表类型的数据 8. request.FILES #包含所有的上传文件信息。
注意:FILES 只有在请求的方法为POST 且提交的from表单带有enctype="multipart/form-data"
的情况下才会包含数据。否则,FILES 将为一个空的类似于字典的对象。
三、响应对象-HttpResponse
响应形式多种多样,可以是HTML网页、重定向、404错误等任何东西,但本质都是返回一个HttpResponse对象。具体的说响应对象主要有三种形式:HttpResponse、render、redirect
3-1. HttpResponse()
HttpResponse()括号内直接跟一个具体的字符串作为响应体。 即返回字符串
3-2. render()
render(request,template_name,[context])
参数:
- request:用于生成响应的请求对象。
- template_name:要使用的模板名称。
- context:添加到模板上下文的一个字典。默认空字典,如果字典中某个值是可调用的,视图将在渲染模板前调用它。
render方法就是将一个模板页面中的模板语法进行渲染,最终渲染成一个html页面作为响应体。
3-3. redirect()
传递要重定向的一个硬编码的URL,即本地的URL文件
def my_view(request): ... return redirect('some/url')
也可以是一个完整的URL:
def my_view(request): ... return redirect('http://www.baidu.com')
四、JsonResponse
向前端返回一个json格式字符串的两种方式
# 第一种方式 import json def my_view(request): data=['xxx','yyy'] return HttpResponse(json.dumps(data)) # 第二种方式 from django.http import JsonResponse def my_view(request): data = ['xxx', 'yyy'] return JsonResponse(data1,safe=False) # 默认safe=True代表 只能序列化字典,safe=False代表可以序列化其他数据类型
五、FBV与CBV
FBV基于函数的视图(Function base view)
CBV是基于类的视图(Class base view)
# FBV # FBV视图层书写方式 def login(request): print('我是login函数') return render(request,'login.html') # FBV路由层的书写 url(r'^index/',views.index), # CBV # CBV视图层书写方式 from django.views import View class MyLogin(View): def get(self,request): print('我是MyLogin里面的get方法') return render(request,'login.html') def post(self,request): print('我是MyLogin里面的post方法') return HttpResponse('post') # CBV路由层的书写 url(r'^login/',views.MyLogin.as_view())
六、 给CBV加装饰器
# 第一种方法:直接书写 class MyLogin(View): @outter # 1.直接写 def get(self,request): print('我是MyLogin里面的get方法') return render(request,'login.html') @outter # 1.直接写 def post(self,request): print('我是MyLogin里面的post方法') time.sleep(1) return HttpResponse('post') # 第二种使用内置函数,推荐方法 from django.utils.decorators import method_decorator # 1-1. 内置函数也可以在外面写,并且可以指定给谁装 @method_decorator(outter,name='post') class MyLogin(View): @method_decorator(outter) # 1-2. 推荐写法 def get(self,request): print('我是MyLogin里面的get方法') return render(request,'login.html') def post(self,request): print('我是MyLogin里面的post方法') time.sleep(1) return HttpResponse('post') # 第三种内置函数联合重写dispatch方法 from django.utils.decorators import method_decorator class MyLogin(View): @method_decorator(outter) def dispatch(self, request, *args, **kwargs): # 如果你想在视图函数执行之前 做一些操作 你可以在你的CBV中定义dispatch方法来拦截 return super().dispatch(request,*args,**kwargs) def get(self,request): print('我是MyLogin里面的get方法') return render(request,'login.html') def post(self,request): print('我是MyLogin里面的post方法') time.sleep(1) return HttpResponse('post')
----------------------------------------------------------
一、模板层(template)
存放在template文件夹下的html文件称之为模板文件,利用模板语法可以在html中展示动态数据,简单来说Django的模板=HTML代码+模板语法
二、模板语法之注释
{# this won't be rendered #} 单行注释 注释多行使用comment标签
三、模板语法之变量
在django模板中遍历复杂数据结构的关键是句点字符,语法:{{ 变量名 }}。变量类似于python中的变量。
变量的命名包括任何字母数字以及下划线("_")的组合。点(".")也有可能会在变量名中出现,不过它有特殊的含义。注意:最重要的是,变量名称中不能有空格或标点符号。
views.py:
name='abc' age=18 li=[1,2,'3','4'] dic={'name':'abc','age':18,''li:[1,2,4]} def test(): #函数 print('abc') return 'abchahahah' class Person(): def __init__(self,name,age) self.name=name self.age=age def get_name(self): return self.name @classmethod def cls_test(cls): return 'cls' @staticmethod def static_test(): return 'static' --------- # 模板里不支持带参数 def get_name_cs(self,ttt): return self.name ---------- xxx=Person('xxx',18) yyy=Person('yyy',28) person_list=[xxx,yyy]
html:
相当于print了该变量
<p>字符串:{{ name }}</p> <p>数字:{{ age }}</p> <p>列表:{{ li }}</p> <p>元祖:{{ tu }}</p> <p>字典:{{ dic }}</p> <p>函数:{{ test }}</p> {#只写函数名:相当于函数名(),返回函数执行结果#} <p>对象:{{ xxx }}</p> {#对象内存地址#}
深度查询:
<p>列表第1个值:{{ ll.0 }}</p> <p>列表第4个值:{{ ll.3 }}</p> <p>字典取值:{{ dic.name }}</p> <p>字典取列表值:{{ dic.li }}</p> <p>对象取数据属性:{{ xxx.name }}</p> <p>对象取绑定给对象的函数属性:{{ xxx.get_name }}</p> <p>对象取绑定给类的函数属性:{{ xxx.cls_test }}</p> <p>对象取静态方法:{{ xxx.static_test }}</p>
四、模板语法之标签
一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。一些标签需要开始和结束标签 语法为{% tagname %}
模板语法的取值 只有一种方式 统一采用句点符 (.)
4-1. for循环
# 遍历每一个元素 {% for person in person_list %} <p>{{ person }}</p> {% end for%} # 遍历一个字典: {% for k,v in dic.items %} <p>{{ k }}:{{ v }}</p>
下面是Django为for标签内置的一些属性,可以当作变量一样使用{{ }}
在模版中使用。
- forloop.counter:循环的当前索引值,从1开始计数;常用于生成一个表格或者列表的序号
- forloop.counter0:循环的当前索引值,从0开始计数;
- forloop.revcounter: 循环结束的次数(从1开始)
- forloop.revcounter0 循环结束的次数(从0开始)
- forloop.first:判断当前是否循环的第一次,是的话,该变量的值为True。我们经常要为第一行加点特殊的对待,就用得上这个判断了,结合if。
- forloop.last:如果这是最后一次循环,则为真
- forloop.parentloop:对于嵌套循环,返回父循环所在的循环次数
4-2. for...empty
for标签带有一个可选的{% empty %}
从句,在给出的组是空的或者没有被找到时执行的操作
注:循环的对象是空,才会走到empty,而不是对象里面的东西为空
{% for person in person_list %} <p>{{ person.name }}</p> {% empty %} <p>sorry,no person here</p> {% endfor %}
4-3. if判断
{% if %}
会对一个变量求值,如果它的值是“True”(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。
{% if num > 100 or num < 0 %} <p>无效</p> {% elif num > 80 and num < 100 %} <p>优秀</p> {% else %} <p>良好</p> {% endif %}
注:在if标签中使用括号是错误的语法,这点不同于Pythonif语句支持 ,优先级可以使用if嵌套。if支持and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。
4-4. 标签实例
# for if联合使用 {% for foo in l %} {% if forloop.first %} <p>这是我的第一次</p> {% elif forloop.last %} <p>这是最后一次了啊</p> {% else %} <p>{{ foo }}</p> {% endif %} {% empty %} <p>当for循环的对象是空的时候会走</p> {% endfor %} # 模板语法的取值 只有一种方式 统一采用句点符 (.) comp_dic = {'username':'jason','hobby':['read','study',['run','rap',{'age':18}]]} # 获取字典嵌套中的age <p>{{ comp_dic.hobby.2.2.age }}</p>
五、模板语法之过滤器
在Django的模板语言中,通过使用过滤器来改变变量的显示。过滤器的语法: {{ value|filter_name:参数 }}
注意事项:
- 过滤器支持“链式”操作。即一个过滤器的输出作为另一个过滤器的输入。
- 过滤器可以接受参数,只能接受一个参数
- 过滤器参数包含空格的话,必须用引号包裹起来。比如使用逗号和空格去连接一个列表中的元素,如:{{ list|join:', ' }}
- '|'左右没有空格
常用过滤器
1. default
<!-- 如果变量是false或者为空,则使用给定的默认值。--> {{ value|default:'nothing'}}
2. length
<!-- 返回值的长度,对字符串和列表都起作用--> value=[1,2,3,4] {{ value|length}} 输出是4
3. filesizeformat
<!-- 将值格式化成'人类可读的'文件尺寸。--> {{1024|filesizeformat}} 输出为1kb
4. safe
<!-- Django模板为了安全默认会对HTML标签和js等语法标签进行转义,有时候我们不希望这些元素被转义,可以通过设置过滤器。--> script="'<script>alert(111)</script>" {{ script|safe }} # 补充:后端也可以利用模块取消转义 from django.utils.safestring import mark_safe sss2 = "<h2>我的h2标签</h2>" res = mark_safe(sss2)
5.slice
<!-- 切片,不支持负数 --> {{ name|slice:'0:3:3' }}
6.truncatechars
<!-- 如果字符串多余指定字符数量,多余会被截断,替换成("...")结尾。 --> {{ value|truncatechars:9}}
7.truncatewords
<!-- 在一定数量的字后截断字符串。--> {{ value|truncatewords:9}}
六、自定义标签和过滤器
6-1. 自定义前置准备
在应用名(app文件夹)下新建一个
templatetags
包(名字固定),与views.py、models.py等文件在同一目录在该文件夹内 新建一个任意名称的.py文件, 如:
my_tags.py
在该.py文件中 必须先写下面两句代码
from django.template import Library register = Library()
6-2. 自定义过滤器
自定义过滤器实际就是一个带有一个或两个参数的python函数
注:函数的第一个参数是要过滤的对象,第二个是自定义参数,函数一共只能有两个参数。
- 变量的值:不一定是字符串形式
- 可以有一个初始值,或者不需要这个参数
# 自定义过滤器 跟默认的过滤器一样 最多只能接受两个参数 # 利用register.filter注册并给该过滤器起别名 @register.filter(name='baby') def index(a,b): return a + b # 自定义过滤器的使用 # 在要使用自定义过滤器的模板文件中导入创建的py文件。语法:{% load 文件名 %} {% load mytag %} {{ 1|baby:1 }} {{ 1|baby:100 }} # 自定义的过滤器可以在逻辑语句使用 而自定义的标签不可以 {% if mytag '1' '2' '3' '4' %} <p>有值</p> {% else %} <p>无值</p> {% endif %}#
6-3. 自定义标签
除了装饰器,其它步骤与自定义过滤器相似。
过滤器只能有两个参数,自定义标签可以传多个值,空格传值。
注:过滤器可以用在if判断中,标签不能
# 自定义标签 可以接受任意多个参数 # 利用register.simple_tag()注册并给该标签起别名 @register.simple_tag(name='mytag') def mytag(a,b,c,d): return '%s?%s?%s?%s'%(a,b,c,d) # 自定义标签的使用 可以接受多个参数 参数与参数之间必须空格隔开 {% load mytag %} {% mytag 'a' 'b' 'c' 'd' %}
6-4. 自定义inclusion_tag
""" 是一个函数 能够接受外界传入的参数 然后传递给一个html页面 页面上获取数据 渲染 完成之后 将渲染好的页面 放到调用inclusion_tag的地方 """ # 自定义inclusion_tag @register.inclusion_tag('mytag.html',name='xxx') def index666(n): l = [] for i in range(n): l.append('第%s项'%i) return locals() # 将l直接传递给mytag.html页面 # 自定义inclusion_tag的使用 当你需要使用一些页面组件的时候 并且该页面组件需要参数才能够正常渲染 你可以考虑使用inclusion_tag</p> {% load mytag %} {% xxx 5 %}
七、模板的继承
模版继承可以创建一个基本的“骨架”模版,它包含站点中的全部元素,并且可以定义能够被子模版覆盖的 blocks
注意:
- 模板上的block区域越多 页面的扩展性越强,一个模板页面最好有三块区域:css区域、html代码区域、js区域 html区域可以设置多个block。有了这三块区域,就能够实现每一个页面都有自己独立的css和js代码
- 不能在一个模板中定义多个相同名字的block标签
- 如果在模板中使用
{% extends %}
标签,它必须是模板中的第一个标签
# 子模板login.html继承index.html文件模板,全部继承的情况下无法修改内容 # 即login.html中只需要写一句代码 {% extends 'home.html' %} # 如果子模板需要修改部分,就需要用到 block # 母模板 index.html ... <body> <div id="sidebar"> # 划定这块区域可以修改,并取别名sidebar {% block sidebar %} <ul> <li><a href="/">Home</a></li> <li><a href="/blog/">Blog</a></li> </ul> {% endblock %} </div> <div id="content"> # 划定这块区域可以修改,并取别名content {% block content %}{% endblock %} </div> # 子模板 login.html {% extends 'home.html' %} # 使用block,pycharm会自动提示有哪些区域 {% block sidebar %} ...修改内容 </style> {% endblock %} {% block content %} ...修改内容 {% endblock %}
八、模板的导入
用简单的模板语句解决了重复组件的代码冗余
语法:{% include '模板名称' %}
# 做好注册前提准备,简单的代码可以直接运行imp路径 # imp.html文件内容 {% include 'fr.html' %} # fr.html文件内容 <p>这是一个特别好看的form表单</p>