Django 中的设计模式

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 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提供的框架使得代码量减少了很多,使得程序员只需关注核心的业务逻辑。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,980评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,422评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,130评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,553评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,408评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,326评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,720评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,373评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,678评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,722评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,486评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,335评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,738评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,283评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,692评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,893评论 2 335

推荐阅读更多精彩内容