Django是MVC吗?
首先说说Web服务器开发领域里著名的MVC模式,所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的、松耦合的方式连接在一起,模型负责业务对象与数据库的映射(ORM),视图负责与用户的交互(页面),控制器接受用户的输入调用模型和视图完成用户的请求,其示意图如下所示:
首先说说Web服务器开发领域里著名的MVC模式,所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的、松耦合的方式连接在一起,模型负责业务对象与数据库的映射(ORM),视图负责与用户的交互(页面),控制器接受用户的输入调用模型和视图完成用户的请求,其示意图如下所示:
![](https://i-blog.csdnimg.cn/blog_migrate/c8d64b42ea3e18174e108088d7dc3bd3.png)
Django的MTV模式本质上和MVC是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同,Django的MTV分别是值:
M 代表模型(Model):负责业务对象和数据库的关系映射(ORM)。
T 代表模板 (Template):负责如何把页面展示给用户(html)。
V 代表视图(View):负责业务逻辑,并在适当时候调用Model和Template。
除了以上三层之外,还需要一个URL分发器,它的作用是将一个个URL的页面请求分发给不同的View处理,View再调用相应的Model和Template,MTV的响应模式如下所示:
![](https://i-blog.csdnimg.cn/blog_migrate/b9d717b8901288620147930768734176.png)
1,Web服务器(中间件)收到一个http请求
2,Django在URLconf里查找对应的视图(View)函数来处理http请求
3,视图函数调用相应的数据模型来存取数据、调用相应的模板向用户展示页面
4,视图函数处理结束后返回一个http的响应给Web服务器
5,Web服务器将响应发送给客户端
这种设计模式关键的优势在于各种组件都是松耦合的。这样,每个由 Django驱动的Web应用都有着明确的目的,并且可独立更改而不影响到其它的部分。
比如,开发者更改一个应用程序中的 URL 而不用影响到这个程序底层的实现。设计师可以改变 HTML页面的样式而不用接触Python代码。
数据库管理员可以重新命名数据表并且只需更改模型,无需从一大堆文件中进行查找和替换。
落到实处,Django的MTV模式相对应的python文件如下:
![](https://i-blog.csdnimg.cn/blog_migrate/f2c5a73a5468e0fb9e239f2bd7e187b5.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3c4488a00ff1386b73fd0c1d6f004b66.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2e01142bd34326a2612bdaf969b066fb.png)
Django是如何工作的?
要真正的欣赏Django,你需要撇开表象来看本质。它启发你得同时也让会让你不知所措。下图显示了在Django应用中一个典型的web请求是如何被处理的。
![](https://i-blog.csdnimg.cn/blog_migrate/d6474ef0244fb88fba027e0f2cdc304e.png)
前面的图片展示了从一个访客的浏览器到Django应用并返回的一个web请求的简单历程。如下是数字标识的路径:
浏览器发送请求(基本上是字节类型的字符串)到web服务器。web服务器(比如,Nginx)把这个请求转交到一个WSGI(比如,uWSGI),或者直接地文件系统能够取出一个文件(比如,一个CSS文件)。不像web服务器那样,WSGI服务器可以直接运行Python应用。请求生成一个被称为environ的Ptyhon字典,而且,可以选择传递过去几个中间件的层,最终,达到Django应用。URLconf中含有属于应用的urls.py选择一个视图处理基于请求的URL的那个请求,这个请求就已经变成了HttpRequest——一个Python字典对象。被选择的那个视图通常要做下面所列出的一件或者更多件事情:
通过模型与数据库对话。使用模板渲染HTML或者任何格式化过的响应。返回一个纯文本响应(不被显示的)。抛出一个异常。HttpResponse对象离开Django后,被渲染为一个字符串。在浏览器见到一个美化的,渲染后的web页面。
虽然某些细节被省略掉,这个解释应该有助于欣赏Django的高级架构。它也展示了关键的组件所扮演的角色,比如模型,视图,和模板。Django的很多组件都基于这几个广为人知设计模式。
浏览器发送请求(基本上是字节类型的字符串)到web服务器。web服务器(比如,Nginx)把这个请求转交到一个WSGI(比如,uWSGI),或者直接地文件系统能够取出一个文件(比如,一个CSS文件)。不像web服务器那样,WSGI服务器可以直接运行Python应用。请求生成一个被称为environ的Ptyhon字典,而且,可以选择传递过去几个中间件的层,最终,达到Django应用。URLconf中含有属于应用的urls.py选择一个视图处理基于请求的URL的那个请求,这个请求就已经变成了HttpRequest——一个Python字典对象。被选择的那个视图通常要做下面所列出的一件或者更多件事情:
通过模型与数据库对话。使用模板渲染HTML或者任何格式化过的响应。返回一个纯文本响应(不被显示的)。抛出一个异常。HttpResponse对象离开Django后,被渲染为一个字符串。在浏览器见到一个美化的,渲染后的web页面。
虽然某些细节被省略掉,这个解释应该有助于欣赏Django的高级架构。它也展示了关键的组件所扮演的角色,比如模型,视图,和模板。Django的很多组件都基于这几个广为人知设计模式。
命令模式
在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二者之间的松耦合,这就是命令模式(Command Pattern)。
命令模式有以下特点:
命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开。每一个命令都是一个操作:请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作。命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。
在Django中,把get和post这些请求的行为抽象成一个HttpRequest类,我们可以通过request实例的method获取行为的类型:
命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开。每一个命令都是一个操作:请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作。命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。
在Django中,把get和post这些请求的行为抽象成一个HttpRequest类,我们可以通过request实例的method获取行为的类型:
if request.method == 'GET': do_something()elif request.method == 'POST': do_something_else()
Django把返回的行为抽象成HttpResponse类,通过调用HttpResponse的方法
from django.http import HttpResponse>>> response = HttpResponse("Here's the text of the Web page.")>>> response = HttpResponse("Text only, please.", content_type="text/plain")
此外,对于不同的数据,Django还分别抽象了相应的类来处理。
Json数据:
from django.http import JsonResponse>>> response = JsonResponse({'foo': 'bar'})>>> response.contentb'{"foo": "bar"}'
File数据:
from django.http import FileResponse>>> response = FileResponse(open('myfile.png', 'rb'))
观察者模式
观察者模式(有时又被称为发布(publish)-订阅(Subscribe)模式、模型-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。
Django中,存在Singal与dispatch类,分别用来发送和接受信号,实现被观察与观察者的角色。
首先,我们可以定义一个观察者,接收一种特定的信号:
import django.dispatch pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])
然后我们可以发送信号,使观察者接收相应的信息:
class PizzaStore(object): ... def send_pizza(self, toppings, size): pizza_done.send(sender=self.__class__, toppings=toppings, size=size) ...
此外,Django中也有很多built in的signal类,实现不同的功能。
django.db.models.signals.pre_save & django.db.models.signals.post_save
当一个model执行save()方法,即在model对应的数据库中的一张表插入一条数据的前后发送信号。
django.db.models.signals.pre_delete & django.db.models.signals.post_delete
当一个model执行delete()方法,即在model对应的数据库中的一张表删除一条数据的前后发送信号。
django.db.models.signals.m2m_changed
当model中的一个多对多的关系发生改变时发送信号。
django.core.signals.request_started & django.core.signals.request_finished
当Django开始或者完成一个HTTP请求的时候发送信号。
Django RestframWork中的REST设计
在使用Django框架的时候,也许有些追求ROA的码农们可能会吐槽没有REST化支持。在Django Restframework框架中的APIView类中,提供了put(), delete(), patch()方法的支持。
比如,如果你想上传一个文件,对应的view就可以这样写:
class FileUploadView(views.APIView): parser_classes = (FileUploadParser,) def put(self, request, filename, format=None): file_obj = request.data['file'] # ... # do some stuff with uploaded file # ... return Response(status=204)
此外,如果你想再服务器端发送请求,Django Restframework中APIClient类提供了各种方法,get(), post(), put(), patch(), delete(), head() and options()。
from rest_framework.test import APIClient client = APIClient()client.post('/notes/', {'title': 'new idea'}, format='json')
总的来说,Django提供的框架使得代码量减少了很多,使得程序员只需关注核心的业务逻辑。更多关于Django的设计原则与最佳实践,在以后的学习中逐渐添加吧。