系列文章:学习Python
Django的MVT设计模式由Model(模型), View(视图) 和Template(模板)三部分组成,分别对应单个app目录下的models.py, views.py和templates文件夹。它们看似与MVC设计模式不太一致,其实本质是相同的;
实践是检验学习成果的最好方法,完成初级开发人员最熟悉的 CRUD 来练手,实现创建(Create)一个任务,查看(Retrieve)任务清单和单个任务详情,更新(Update)一个任务和删除(Delete)一个任务;
MVC 模型
MVC 模式(Model–view–controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。
MVC 以一种插件式的、松耦合的方式连接在一起。
- 模型(M)- 编写程序应有的功能,负责业务对象与数据库的映射(ORM)。
- 视图(V)- 图形界面,负责与用户的交互(页面)。
- 控制器(C)- 负责转发请求,对请求进行处理。
简易图:
用户操作流程图:
熟悉的 Java MVC 的味道,异曲同工:在MVC框架中创建一个接收所有请求的Servlet,通常我们把它命名为DispatcherServlet,它总是映射到/,然后,根据不同的Controller的方法定义的@Get或@Post的Path决定调用哪个方法,最后,获得方法返回的ModelAndView后,渲染模板,写入HttpServletResponse,即完成了整个MVC的处理。
HTTP Request ┌─────────────────┐
──────────────────>│DispatcherServlet│
└─────────────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
┌───────────┐┌───────────┐┌───────────┐
│Controller1││Controller2││Controller3│
└───────────┘└───────────┘└───────────┘
│ │ │
└────────────┼────────────┘
▼
HTTP Response ┌────────────────────┐
<────────────────│render(ModelAndView)│
└────────────────────┘
MTV 模型
Django 的 MTV 模式本质上和 MVC 是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同,Django 的 MTV 分别是指:
- M 表示模型(Model):编写程序应有的功能,负责业务对象与数据库的映射(ORM)。
- T 表示模板 (Template):负责如何把页面(html)展示给用户。
- V 表示视图(View):负责业务逻辑,并在适当时候调用 Model和 Template。
除了以上三层之外,还需要一个 URL 分发器,它的作用是将一个个 URL 的页面请求分发给不同的 View 处理,View 再调用相应的 Model 和 Template,MTV 的响应模式如下所示:
简易图:
用户操作流程图:
解析:
用户通过浏览器向我们的服务器发起一个请求(request),这个请求会去访问视图函数:
- a.如果不涉及到数据调用,那么这个时候视图函数直接返回一个模板也就是一个网页给用户。
- b.如果涉及到数据调用,那么视图函数调用模型,模型去数据库查找数据,然后逐级返回。
视图函数把返回的数据填充到模板中空格,最后返回网页给用户。
完成CRUD 小应用
1、创建Django项目,tasks应用
在 PyCharm 中 new Project,并创建应用:python manage.py startapp tasks
并把它加入 settings.py
的 INSTALLED_APPS
中;
然后把app下的urls路径添加到项目文件夹的urls.py里去:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('tasks/', include('tasks.urls'))
]
2、创建Task模型及其关联表单
# tasks/models.py
from django.db import models
class Status(models.TextChoices):
UNSTARTED = 'u', "未开始"
ONGOING = 'o', "进行中"
FINISHED = 'f', "已结束"
class Task(models.Model):
name = models.CharField(verbose_name="Task name", max_length=65, unique=True)
status = models.CharField(verbose_name="Task status", max_length=1, choices=Status.choices)
def __str__(self):
return self.name
# tasks/forms.py
from .models import Task
from django import forms
class TaskForm(forms.ModelForm):
class Meta:
model = Task
fields = "__all__"
3、编写路由URLConf及视图
我们需要创建5个urls, 对应5个函数视图。
from django.urls import path, re_path
from . import views
# namespace
app_name = 'tasks'
urlpatterns = [
# Create a task
path('create/', views.task_create, name='task_create'),
# Retrieve task list
path('', views.task_list, name='task_list'),
# Retrieve single task object
re_path(r'^(?P<pk>\d+)/$', views.task_detail, name='task_detail'),
# Update a task
re_path(r'^(?P<pk>\d+)/update/$', views.task_update, name='task_update'),
# Delete a task
re_path(r'^(?P<pk>\d+)/delete/$', views.task_delete, name='task_delete'),
]
下面5个函数视图代码是本应用的核心代码:
from django.shortcuts import render, redirect, get_object_or_404
from django.urls import reverse
from .models import Task
from .forms import TaskForm
# Create a task
def task_create(request):
# 如果用户通过POST提交,通过request.POST获取提交数据
if request.method == "POST":
# 将用户提交数据与TaskForm表单绑定
form = TaskForm(request.POST)
# 表单验证,如果表单有效,将数据存入数据库
if form.is_valid():
form.save()
# 跳转到任务清单
return redirect(reverse("tasks:task_list"))
else:
# 否则空表单
form = TaskForm()
return render(request, "tasks/task_form.html", { "form": form, })
# Retrieve task list
def task_list(request):
# 从数据库获取任务清单
tasks = Task.objects.all()
# 指定渲染模板并传递数据
return render(request, "tasks/task_list.html", { "tasks": tasks,})
# Retrieve a single task
def task_detail(request, pk):
# 从url里获取单个任务的pk值,然后查询数据库获得单个对象
task = get_object_or_404(Task, pk=pk)
return render(request, "tasks/task_detail.html", { "task": task, })
# Update a single task
def task_update(request, pk):
# 从url里获取单个任务的pk值,然后查询数据库获得单个对象实例
task_obj = get_object_or_404(Task, pk=pk)
if request.method == 'POST':
form = TaskForm(instance=task_obj, data=request.POST)
if form.is_valid():
form.save()
return redirect(reverse("tasks:task_detail", args=[pk,]))
else:
form = TaskForm(instance=task_obj)
return render(request, "tasks/task_form.html", { "form": form, "object": task_obj})
# Delete a single task
def task_delete(request, pk):
# 从url里获取单个任务的pk值,然后查询数据库获得单个对象
task_obj = get_object_or_404(Task, pk=pk)
task_obj.delete() # 删除然后跳转
return redirect(reverse("tasks:task_list"))
4、编写模板
# tasks/templates/tasks/task_list.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Task List</title>
</head>
<body>
<h3>Task List</h3>
{% for task in tasks %}
<p>{{ forloop.counter }}. {{ task.name }} - {{ task.get_status_display }}
(<a href="{% url 'tasks:task_update' task.id %}">Update</a> |
<a href="{% url 'tasks:task_delete' task.id %}">Delete</a>)
</p>
{% endfor %}
<p> <a href="{% url 'tasks:task_create' %}"> + Add A New Task</a></p>
</body>
</html>
# tasks/templates/tasks/task_detail.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Task Detail</title>
</head>
<body>
<p> Task Name: {{ task.name }} | <a href="{% url 'tasks:task_update' task.id %}">Update</a> |
<a href="{% url 'tasks:task_delete' task.id %}">Delete</a>
</p>
<p> Task Status: {{ task.get_status_display }} </p>
<p> <a href="{% url 'tasks:task_list' %}">View All Tasks</a> |
<a href="{% url 'tasks:task_create'%}">New Task</a>
</p>
</body>
</html>
# tasks/templates/tasks/task_form.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% if object %}Edit Task {% else %} Create New Task {% endif %}</title>
</head>
<body>
<h3>{% if object %}Edit Task {% else %} Create New Task {% endif %}</h3>
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<p><input type="submit" class="btn btn-success" value="Submit"></p>
</form>
</body>
</html>
第五步:运行项目,查看效果
运行如下命令,访问http://localhost/tasks/就应该看到文初效果了。
参考文档
Django 简介 | 菜鸟教程
Django CRUD小应用
MVC高级开发