day02 Django: url控制器 视图函数views 模板templates
一.Django: url控制器
Django1和Django2唯一的不同点就是这个: 路由层(URLconf), 版本的语法: 是向下兼容的
1.urls.py的作用
请求路径与视图函数的映射关系
2.简单的路由配置:
2.1.无名分组: 通过分组获取url上的动态数据, 对应的是位置参数
from django.conf.urls import url
urlpatterns = [
url(r'^admin/$', admin.site.urls),
url(r'^articles/2003/$',views.special_case_2003), #完全匹配没啥好说的
url(r'^articles/(\d{4})/$',views.year_group_archive), #year_group_archive(request, 2006) 分组的数据默认是一个参数,
url(r'^articles/(\d{4})/(\d{2})/$',views.month_archive), #month_archive(request, 2006,12) 分组的数据默认是一个参数,分组的参数默认是一个参数
]
2.2.有名分组: 给分组命名 (?P<name>pattern), 对应的是关键字参数
url(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$',views.month_archive) #month_archive(request,year=2006,month=12)
3.注意:
1.要获取url中的一个值,只需要在它周围放置一对圆括号
2.不需要添加一个前导的斜杠,也不能加,因为Django已经给我们加好了
3.r''是可选的,但是建议加上,它告诉python这个字符串是'原始的'
4.r''里面后面的斜杠有点意思, 分发的时候: 不加好像不行
4.分发
问题描述: 如果一个项目有很多应用,每个应用的url很多,这时候url都写到一个全局的urls.py里就不合适了
如何解决: include: Django提供的分发接口
4.1.主urls.py文件
from django.conf.urls import url
from django.urls import include, path
from app01 import views
urlpatterns = [
url(r'^$',views.index), #r'^$': 匹配的是根路径
url(r'^app01/', include('app01.urls')),
url(r'^app02/', include('app02.urls')),
]
4.2.以app01应用为例,从urls.py文件
from django.conf.urls import url, include
from app01 import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/(\d{4})/$', views.year_group_archive),
url(r'^articles/(\d{4})/(\d{2})/$', views.month_archive),
]
5.反向解析
问题描述: 如果你url里面写好了路径,之后你需要改这个路径的名字,那么与之关联的路径名都要改,很麻烦
如何解决: 使用url()的name参数, 给当前url起个别名, 与之关联的东西使用这个别名: 之后只要改urls.py中的路径,其他关联的自己更新
url(r'^login.html/', views.login, name='aliasLogin'), #urls.py文件: 起个别名
<form action="{% url 'aliasLogin' %}" method="post"> #html文件: 使用"{% url 'aliasLogin' %}"去urls.py中找最新的url,这个过程就叫做反向解析
二.Django: 视图函数
1.request:请求对象
def index(request):
print(request.method) #请求方式
print(request.path) #请求路径
print(request.POST) #POST请求时的数据: 字典格式
print(request.GET) #GET请求时的数据: 字典格式
print(request.META) #请求头里的信息
print(request.get_full_path()) #除了路径,参数也可以取出来
print(request.is_ajax()) #判断是不是ajax发的,浏览器发的就是false
return HttpResponse('ok')
2.response:响应对象
共有3种形式,Django对于请求最后一定相应的是HttpPResponse的实例对象
2.1.HttpResponse('字符串')
2.2.render(request, '页面')
功能一: 把'页面'的内容读出来,返回
功能二: 嵌入变量
render()里面加入第三个参数{}, 把html中的数据名称和变量对应起来
def index(request): #views.py文件
var = '苹果'
name = '八戒'
return render(request, 'index.html', {'shop': var, 'name': name})
<body> #html文件
<h3>商品信息</h3>
<p>{{ shop }}</p>
<p>{{ name }}</p>
</body>
2.3.redirect('路径') 重定向
比如登录页面: 登录成功重定向到首页,让浏览器多发一次请求
return render(request, 'index.html', {'shop': var, 'name': name}) #问题一: 不能刷新,一刷新就变成登录界面 问题二: 因为是直接打开文件,html不能使用render的第三个参数
return redirect('/index/') #redirect()可解决上面的两个问题
三.Django:模板templates
模板语法, 是由render()来渲染的
1.{{ var }} 用来渲染变量的
1.1.var的数据类型可以是: 字符串,数字,列表,元祖,字典,也可以是对象,还可以是标签
1.2.深度查询: 使用句点符号
列表,元组,字典: 直接用句点来深度查询
对象: 模板里调方法,不能加括号,有参数怎么办, 那就调不了; 这里调用后得到的是函数里的返回值
def index(request): #views.py文件
name = '八戒'
age = 19
lst = ['bajie', 'wukong', 'datang']
tup = ('bajie', 'wukong', 'datang')
dic = {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
class Animal(object):
def __init__(self, name, age):
self.name = name
self.age = age
def running(self):
return 'running'
bajie = Animal('bajie', 18)
wukong = Animal('wukong', 10)
datang = Animal('datang', 16)
person_list = [bajie, wukong, datang]
#return render(request, 'index.html', {'name': name, 'age': age, 'lst': lst, 'dic': dic, }) #也可以用locals()代替{}传参
return render(request, 'index.html', locals())
<body>
<p>this is 模板语法</p> #html文件
<h4>{{ name }}
{{ age }}
{{ lst }}
{{ tup }}
{{ tup.2 }}
{{ lst.2 }}
{{ dic }}
{{ dic.k1 }}
{{ person_list }}
{{ person_list.2.name }}
{{ person_list.2.running }}
</h4>
</body>
1.3.过滤器 filter
语法: {{ var|filter_name:参数 }}
def index(request): #views.py文件
import datetime
now = datetime.datetime.now()
book_list = ['xiyou', 'dahua', 'dongyou']
file_size = 123210
var = 'mynameisbajie'
artical = 'abcd efg hig klmn opq rstuvw xyz, zkl olm nil abc ink shell.'
tag = "<script>alert(123)</script>"
link = "<a href='http://www.baidu.com/'>点我</a>"
return render(request, 'index.html', locals())
<body> #html文件
<p>过滤器</p>
<h4>{{ now|date:"Y-m-d" }} #日期过滤器
{{ book_list|default:"没有符合条件的数据" }} #默认过滤器: 如果没有值得话, 设置默认显示的内容
{{ book_list|length }} #长度
{{ file_size|filesizeformat }} #格式化大小
{{ var|slice:"2:-1" }} #切片
{{ artical|truncatechars:10 }} #截字符: 截取前几个字符,还要预留3个给 ...
{{ artical|truncatewords:5 }} #截取单词: 截取前几个单词,不用预留给 ...
{{ link }} #没有在浏览器渲染出来, 因为你给浏览器的是特殊符号(哪来的,Django给转义的)组成的文本,而不是标签, 怎么办?
{{ tag }} #Django为了安全考虑,因为你的数据是从数据库取到的,有可能是用户写的恶意标签数据: xss攻击
{{ link|safe }} #安全过滤器: 在确认你的标签是安全的情况下: 告诉Django按标签处理,不需要转义
</h4>
</body>
2.{% %} 用来渲染标签的
2.1.for 循环标签 {% for %}
def index(request): #views.py文件
book_list = ['xiyou', 'dahua', 'dongyou']
return render(request, 'index.html', locals())
<body>
<p>渲染标签</p> #html文件
<ul>
{% for book in book_list %} #for的语法只能这样,没有break,continue啥的
<li>{{ forloop.first }} {{ forloop.counter }} {{ book }}</li> #forloop只能在这里用, 计数器; forloop.first返回布尔值
{% endfor %}
</ul>
</body>
2.2.if 标签 {% if %}
def index(request): #views.py文件
age = 22
class Animal(object):
def __init__(self, name, age):
self.name = name
self.age = age
def running(self):
return 'running'
bajie = Animal('bajie', 18)
wukong = Animal('wukong', 10)
datang = Animal('datang', 16)
person_list = [bajie, wukong, datang]
return render(request, 'index.html', locals())
<body>
<p>渲染标签</p> #html文件
{% if age > 50 %} #if 的使用
<p>50</p>
{% else %}
<p>{{ age }}</p>
{% endif %}
{% for person in person_list %} #if 与 for的组合使用
{% if person.age > 17 %}
<p>{{ person.name }} {{ person.age }}</p>
{% endif %}
{% endfor %}
</body>
2.3.with 起个别名 {% with %}
当.句点语法比较长的是时候可以考虑用这个
<p>
{% with person_list.2.name as name %}
{{ name }}
{% endwith %}
</p>
2.4.csrf_token {% csrf_token %}
这个标签用于跨站请求'伪造保护'
当不写这句的时候, 提交POST请求会被Forbidden掉
那么{% csrf_token %}这个究竟做了什么?
给form表单搞了个通行证: <input type="hidden" name="csrfmiddlewaretoken" value="4en0Q7Q9xUyb11LicKltEUuQ4mmP1LXSsX2Ik9LGz9XB14T2WJHiewcpM23QSrTp">
作用是什么?
forbidden那些上来就直接给我发POST请求的非法人, 使用中间件来验证
3.模板的继承extend {% extends 'base.html' %} (extend 延伸)
我们需要一个母版, 当有相同结构的网页时, 可以继承这个母版
3.1.目前我们向服务器发送请求的三种方式
一.浏览器的地址栏直接输入url
二.form表单里的action, 可以是GET,POST
三.a标签, 是最常用的方式
3.2.母版的使用: 首页,订单,和商品列表三个页面有 80% 以上的代码重复了, 怎么办? 给它们三个找个母版
3.2.1.母版中:
保留重复的代码
个性的代码用{% block content %} {% endblock %}占位
base.html
<!DOCTYPE html>
<html lang="zh-CN">
<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>Bootstrap 101 Template</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
*{margin: 0; padding: 0;}
.header{width: 100%; height: 50px;}
</style>
</head>
<body>
<div class="header"></div>
<div class="container">
<div class="row">
<div class="col-md-3">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
<p><a href="/index/">首页</a></p>
<p><a href="/order/">订单</a></p>
<p><a href="/shopping/">商品列表</a></p>
</div>
</div>
</div>
<div class="col-md-9">
{% block content %}
{% endblock %}
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script>
</body>
</html>
3.2.2.每个页面: 使用render()进行渲染时
先使用{% extends 'base.html' %}引进母版中保留的代码
再使用{% block content %} {% endblock %}编写自己个性的代码
index.html
{% extends 'base.html' %}
{% block content %}
<div class="jumbotron">
<h1>Hello, world!</h1>
<p>...</p>
<p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
</div>
{% endblock %}
order.html
{% extends 'base.html' %}
{% block content %}
{% for order in order_list %}
<p>{{ order }}</p>
{% endfor %}
{% endblock %}
shopping.html
{% extends 'base.html' %}
{% block content %}
{% for shopping in shopping_list %}
<p>{{ shopping }}</p>
{% endfor %}
{% endblock %}
3.2.3.{% block content %} {% endblock %}占位的盒子里面也可以有默认的内容, 需要的时候,再进行覆盖,使我们的代码无限灵活
3.3.模板继承注意事项
1.当在模板中使用 {% extends 'base.html' %} 时, 必须是第一个标签, 否则模板继承无法使用
2.在母版中设置的 {% block %} 越多越好,多一点钩子总比少一点好
3.{{ block.super }} 变量可以直接使用,代表的是母版中被占位的标签
4.{% block content %} {% endblock content%} 首位呼应,增加易读性
5.一个母版中 block标签的名字不能重复