在Django的官方文档中是这么定义视图的: "一类具有相同功能和模板的网页的集合",概念比较抽象,我们直接 拿比较简单常见论坛网站来举例,可能要求创建以下视图:
在Django中,千万不要把视图理解为前端展示给我们的页面,请大家回顾下Django的MTV 模式。
我们在第二篇公众号中已经演示了最简单视图,在 demo_app/views.py
中
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. This is your first Django")
根据前面的学习我们得知,当我们在浏览器中输入 http://localhost:8000/demo_app/
时,Django 的路由规则会将这个请求分配到这个 index
这个视图上进行处理,那如果我们输入的url带有参数(如带参数的Get请求)那我们的视图该如何处理呢?看看下面的实例
from django.http import HttpResponse
* 不带参数的视图
def index(request):
return HttpResponse("Hello, world. This is your first Django")
* 带参数的视图
def hello_country(request, country_name):
return HttpResponse("Hello," % country_name)
在 demo_app/views.py
中新增 hello_country
的配置新的路由规则:
from django.urls import path
from . import views # . 表示在同级父目录下
urlpatterns = [
path('', views.index, name='index'),
path('hello/<str:country_name>/', views.hello_country, name='hello'),
]
str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
int,匹配正整数,包含 0。
slug,匹配字母、数字以及横杠、下划线组成的字符串。
uuid,匹配格式化的 uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
path,匹配任何非空字符串,包含了路径分隔符
当浏览器输入 http://localhost:8003/demo_app/hello/china
时,我们新配置的路由规则发挥作用,决定过了 demo_app/views.py
中的 hello_country
视图来处理该请求,那我们就会看到页面上返回
在视图中你可以操作数据库,可以使用模板引擎(Django自带的,或者第三方的)等,Django 对视图的要求是返回一个 HttpResponse
,或者抛出异常。我们现在就来演示下Django 如何使用模板系统。
我们通过登录到后台管理系统新建几个Cat对象(也可通过Django自带的数据库API),我们将在视图中通过模板使用他们。
首先我们在 demo_app
目录下新建templates目录,Django将会在这个目录里查找模板文件。在Django的配置文件中默认设置了 APP_DIRS
为True,这一选项会让Django在每个 INSTALLED_APPS
文件夹中寻找 templates
子目录。
在刚新建的 templates
目录里再新建一个目录 demo_app
,然后在其中新建 index.html
文件。我们在这推荐使用这样的目录结构,虽然我们也可以个把 index.html
文件建在 demo_app\templates
目录中。 index.html
新建后目录结构如下:
demo_proj/
manage.py
demo_proj/
__init__.py
settings.py
urls.py
wsgi.py
demo_app
migrations
templates
demo_app
index.html
__init__.py
admin.py
apps.py
models.py
test.py
views.py
在 demo_app/tempaltes/demp_app/index.html
文件中输入如下代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Cat List</title>
</head>
<body>
<table border="1">
<tr>
<td>Name</td>
<td>age</td>
</tr>
{% if cats_list %}
{% for cat in cats_list %}
<tr>
<td>{{ cat.name }}</td>
<td>{{ cat.age }}</td>
</tr>
{% endfor %}
{% else %}
<p>No cat</p>
{% endif %}
</table>
</body>
</html>
我们更新 demo_app/views.py
文件来调用我们刚才建立的模板
def index(request):
cats_list = Cat.objects.all()
from django.template import loader
template = loader.get_template('demo_app/index.html')
context = {
'cats_list': cats_list,
}
return HttpResponse(template.render(context, request))
上面代码的作用,就是载入 demo_app/index.html
模板文件,并向该模板传递一个context,这个上下文是个字典,可以理解为 将Python对象 cats_list
映射成 模板内的变量 cats_list
,所以,我们在模板中能够引用变量(类似于 {%ifcats_list%}
这样的格式{{ xxx }}).
用浏览器 访问 http://127.0.0.1:8003/demo_app/
,将会看到一个表格,列出了我们新建的几个Cat对象.
回顾下刚才views.py中使用模板的实现过程,我们先载入模板,再填充上下文,最后返回由它生成的 HttpResponse
对象,略显繁琐,Django提供了render() 函数来简化这个流程,我们重新更新 demo_app/views.py
文件
def index(request):
cats_list = Cat.objects.all()
context = {
'cats_list': cats_list,
}
return render(request,'demp_app/index.html',context)
重新用浏览器 访问 http://127.0.0.1:8003/demo_app/
,会返回同样的结果。
回顾下我们的index()视图,它向模板传递了一个 cats_list
变量,我们再来看看 index.html
模板中是怎么使用变量的。
{% if cats_list %}
{% for cat in cats_list %}
<tr>
<td>{{ cat.name }}</td>
<td>{{ cat.age }}</td>
</tr>
{% endfor %}
{% else %}
<p>No cat</p>
{% endif %}
在模板系统中,我们引用变量的属性都用 {{xx}}
, 如 {{cat.name}}
, {{cat.age}}
。
一些 判断,循环也有固定的格式:
{% for xx in xxx %}
...
...
...
{% end for %}
{% if xxxxx %}
{% else %}
{% endif %}
http://xxxxx/demo_app/x
时进入id=x 的详情页面。其路由配置为from django.urls import path
from . import views # . 表示在同级父目录下
urlpatterns = [
path('', views.index, name='index'),
path('hello/<str:country_name>/', views.hello_country, name='hello'),
path('<int:id>/', views.detail, name='detail'),
]
我们将 index.html
改造下,让其显示id,并且id 为超链接
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Cat List</title>
</head>
<body>
<table border="1">
<tr>
<td>Id</td>
<td>Name</td>
<td>age</td>
</tr>
{% if cats_list %}
{% for cat in cats_list %}
<tr>
<td><a href = "{% url 'demo_app:dtail' cat.id %}">{{ cat.id }}</a></td>
<td>{{ cat.name }}</td>
<td>{{ cat.age }}</td>
</tr>
{% endfor %}
{% else %}
<p>No cat</p>
{% endif %}
</table>
</body>
</html>
以前 href 中的网址 被 {%url'demo_app:detail'cat.id%}
所代替。注意其语法格式:
demo_app:detail
是指 在 demo_app
应用的 urls.py 文件中 name=detail
的路由规则。cat.id
则是传入的参数 以空格隔开。模板系统当然还有其他的特定用法,我们会在后面的课程中陆续接触。
我们最后来处理下抛出异常的情况,那我们的detail视图来举例
在 demo_app/views.py
添加如下代码
from django.http import Http404
def detail(request, id):
try:
cat = Cat.objects.get(id = id)
except Cat.DoesNotExist:
raise Http404("Cat does not exist")
return render(request, 'demo_app/detail.html',{'cat':cat})
根据id 获取具体的cat 对象,如果对象不存在,则抛出404异常 。否则,把获取的cat对象作为上下文传递给 detail.hmtl
。代码逻辑很清楚,但Django 还是提供了一个更为简单的函数 get_object_or_404()
from django.shortcuts import render,get_object_or_404()
def detail(request, id):
cat = get_object_or_404(Cat, id=id)
return render(request, 'demo_app/detail.html',{'cat':cat})
get_object_or_404()
返回具体对象或者抛出404异常,类似的也有 get_list_or_404()
函数,大家可以直接练习下。