Django是MVC模式吗?
首先说说Web服务器开发领域里著名的MVC模式,所谓MVC就是把Web应用分为 模型(M)、控制器(C)和试图(V)三层,他们之间以一种插件式的、松耦合的方式连接在一起,模型负责业务对象与数据库的映射(ORM),试图负责与用户的交互(页面),控制器接受用户的输入调用模型和试图完成用户的请求。
Django的MTV模式本质上和MVC是一样的,也是为了各自组建保持一个松耦合关系,只是定义上有些许的不同,Django的MTV分别是:
M 代表模型(model):负责业务对象和数据库的关系映射(ORM)
T 代表模板(Templates) : 负责如何把页面展示给用户(HTML)
V 代表试图(View) :负责业务逻辑,并在适当的时候调用Model和Template
除了以上三层之外,还需要一个URL分离器,他的作用是将一个个URL的页面请求分发给不同的View处理,View在调用相应的Model和Template
1、Web服务器(中间件)收到一个http请求
2、Django在URLconf里查找相对应的试图(View)函数来处理http请求
3、试图函数调用相应的数据模型来存取数据、调用相应的模板展示页面
4、试图函数处理结束后返回一个http的响应给Web服务器
5、Web服务器将响应发送给客户端
这种设计模式关键的优势在于各种组件都是的松耦合的,这样的话,每个由Django驱动的Web应用都有着明确的目的,并且可以独立更改而不影响到其他的部分
比如,开发者更改一个应用程序中的URL,而不用影响这个程序底层的实现,设计师可以改变HTML页面的样式而不用接触Python代码
数据管理员可以重新命名数据库,并且只需要更改模型,无需从一大堆文件中查找和替换
Django 是如何工作的?
下图显示了在Django应用中一个典型的web请求是如何被处理的
前面的图片展示了一个从访客的浏览器到Django应用并返回的一个Web请求的简单历程,如下是数字标识的路径:
1、浏览器发送请求(基本上是字节类型的字符串)到web服务器
2、Web服务器(比如,Nginx)把这个请求转交到一个WSGI(比如,uWSGI),或者直接的文件系统能够取出一个文件(比如,一个CSS文件)。
3、不像Web服务器那样,WSGI服务器可以直接运行Python应用,请求生成一个被称为environ的Python字典,而且,可以选择传递过去几个中间件的层,最终达到Django应用
4、URLconf中含有属于应用的urls.py选择一个试图处理汲取请求的URL的那个请求,这个请求就已经变成了HttpRequest——一个Python字典对象。
5、被选择的那个试图通常要做下面所列出的一件或多件事情:
- 通过模型与数据库对话
- 使用模板渲染HTML或者任何格式化过的响应
- 返回一个纯文本响应(不被显示的)
- 抛出一个异常
6、HttpResponse对象离开Django后,被渲染为一个字符串
7、在浏览器见到一个美化的,渲染后的web页面。
虽然某些细节被省略掉,这个解释应该有助于欣赏Django的高级架构,他也展示了关键的组件所扮演的角色,比如模型,试图和模板,Django的很多组件都基于这几个广为人知的设计模式
命令模式
在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二者之间的松耦合,这就是命令模式(Command Pattern)。
命令模式有以下特点:
1、命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开。
2、每一个命令都是一个操作:请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作。
3、命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。
4、命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。
5、命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。
在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提供的框架使得代码量减少了很多,使得程序员只需关注核心的业务逻辑。