首先,先简单理解下django的MTV模式。
- M 代表模型(Model):负责业务对象和数据库的关系映射(ORM)。即:创建数据的字段和行为。
- T 代表模板 (Template):负责如何把页面展示给用户(html)。
- V 代表视图(View):负责业务逻辑,并在适当时候调用Model和Template(数据来源于哪个model及指定通过哪个template去展示)。
除了以上三层之外,还需要一个URL分发器,它的作用是将一个个URL的页面请求分发给不同的View处理。即:前端页面的url路径,与视图,与对应的名称(前端页面跳转时可指定名称去跳转)是通过url文件去关联的。
上一篇我们已经创建了模型,这里来看看View视图和Template模板。
View视图——通用视图ListView和DetailView
我们需要显示的视图如下:
- 项目索引页——展示所有项目列表
- 项目详情页——展示某个项目描述和该项目的进度列表
上一篇中已经创建过一个简单的index视图,现在我们会创建更复杂一点的视图。在这里使用django的两个通用视图: ListView
和 DetailView
。这两个视图分别抽象“显示一个对象列表”和“显示一个特定类型对象的详细信息页面”这两种概念。
代码如下:
from django.views import generic
from .models import Project, Schedule
class ProjectView(generic.ListView):
model = Project
template_name = 'projtrack/project.html'
def get_queryset(self):
return Project.objects.order_by('-cre_date')
class ScheduleView(generic.DetailView):
model = Project
template_name = 'projtrack/schedule.html'
注意:
- 每个通用视图需要知道它将作用于哪个模型。 这由
model
属性提供。 -
ListView
使用一个叫做<app name>/<model name>_list.html
的默认模板;我们使用template_name
来告诉ListView
使用我们的"projtrack/project.html"
模板。类似的,DetailView
也是如此,使用"projtrack/schedule.html"
模板。 - 对于
ListView
,定义了model
为Project
后,会自动生成context
变量project_list
,可以在html页面调用获取所有项目列表。也可以自定义一个context变量,比如“latest_project_list”
,然后重写get_queryset
方法,返回最近10条(自定义)的项目列表。 -
DetailView
期望从 URL 中捕获名为"pk"
的主键值 - 对于
DetailView
,定义了model
为Project
后,也会自动生成context
变量project
,可在html页面调用。
添加url对应视图的关系
在projtrack/urls.py
中添加path:
from django.urls import path
from . import views
app_name = 'projtrack'
urlpatterns = [
path('', views.index, name='index'),
path('project/', views.ProjectView.as_view(), name='project'),
path('project/<int:pk>', views.ScheduleView.as_view(), name='schedule'),
]
注意:
- 为了去除html页面中跳转页面时使用硬编码,可通过 name 参数为 URL 定义名字,这样就可以使用
{% url %}
标签。
比如点击某个项目名称,进入该项目的进度视图页面时使用的href:
<td><a href="/project/{{ project.id }}/">{{ project.project_name }}</a></td>
如果url.py中的path发生修改,则html页面的改动是挺麻烦的。用{% url %}
标签后:
<td><a href="{% url 'schedule' project.id %}">{{ project.project_name }}</a></td>
即:寻找名为schedule的路径,路径中参数pk的值为project.id
- 为 URL 名称添加命名空间,分辨不同应用中重名的 URL
当项目中存在多个应用时,在url中只通过name去找路径,有可能出现重名而定位不到或定位错误的问题。可通过添加命名空间解决。
在projtrack/urls.py
中添加app_name = 'projtrack'
,html页面中的href改为:
<td><a href="{% url 'projtrack:schedule' project.id %}">{{ project.project_name }}</a></td>
即:在projtrack中寻找名为schedule的路径。
Template模板
我们在View中指定了projtrack/project.html和projtrack/schedule.html作为前端页面去展示。在url.py中定义了视图对应的路径和路径名称。现在,在projtrack/中创建这两个页面并添加如下代码。
注意:这里project.html和schedule.html都是{% extends "projtrack/index.html %}"
。也就是作为index.html页面的扩展,把一些公共的元素放在index页面,比如导航栏,用户显示,登录注册按钮等(这部分详细写在下一篇)。这里先简化index.html。
# projtrack/index.html
<!DOCTYPE html>
<html lang="zh-cn">
<title>Project Tracking System</title>
<head>
<meta charset="utf-8">
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
# projtrack/project.html
{% extends "projtrack/index.html" %}
{% block body %}
<div class="table-responsive">
<h2 class="sub-header">项目</h2>
<table class="table table-hover">
<thead>
<tr><th>#</th><th>项目</th><th>描述</th><th>创建时间</th><th>状态</th></tr>
</thead>
{% if project_list %}
{% for project in project_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td><a href="{% url 'projtrack:schedule' project.id %}">{{ project.project_name }}</a></td>
<td>{{project.description}}</td>
<td>{{project.cre_date}}</td>
<td>{{project.project_status}}</td>
</tr>
{% endfor %}
{% else %}
<tr>No projects are available.</tr>
{% endif %}
</table>
</div>
{% endif %}
{% endblock %}
# projtrack/schedule.html
{% extends "projtrack/index.html" %}
{% block body %}
<div class="table-responsive">
<h2>项目:{{ project.project_name }}</h2>
<h4>进度列表</h4>
<table class="table table-hover">
<thead>
<tr><th>#</th><th>阶段</th><th>进度名称</th><th>状态</th><th>文件</th><th>备注</th><th>修改时间</th><th>修改人</th></tr>
</thead>
{% for schedule in project.schedule_set.all %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ schedule.stage }}</td>
<td>{{ schedule.schedule_text }}</td>
<td>{{ schedule.status }}</td>
<td>{{ schedule.photo }}</td>
<td>{{ schedule.notes }}</td>
<td>{{ schedule.modify_date }}</td>
<td>{{ schedule.edit_by }}</td>
</tr>>
{% endfor %}
</table>
</div>
{% endif %}
{% endblock %}
模板系统统一使用点符号来访问变量的属性。在示例 {{ project.project_name }}
中,首先 Django 尝试对 project 对象使用字典查找(也就是使用 obj.get(str) 操作),如果失败了就尝试属性查找(也就是 obj.str 操作),结果是成功了。如果这一操作也失败的话,将会尝试列表查找(也就是 obj[int] 操作)。
在{% for %}
循环中发生的函数调用:project.schedule_set.all
被解释为 Python 代码 project.schedule_set.all()
,将会返回一个可迭代的 Schedule
对象,这一对象可以在 {% for %}
标签内部使用。
网友评论