让django像Asp.Net Mvc一样自动匹配Controller和Action

Asp.Net Mvc 中,我们可以通过配置如下路由,允许从Url中匹配每段路径到Area, Controller和Action中,在尝试使用了django之后,发现django的路由系统更加灵活,允许通过正则匹配任意Url到任意View,但如果希望通过在Url路径中指定要访问的app, view,就比较麻烦,我下面的尝试,通过匹配Url,使用python自省(反射)查找特定View方法并返回该方法执行结果,建立了一个简单的python路由规则。

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default", // Route name
        "{controller}/{action}/{id}", // URL with parameters
        new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
    );

}

代码列表-1 Asp.Net Mvc路由配置

为了不影响现有逻辑,我在原django项目中新建了一个routed app,在该app中配置路由,下面是django项目结构

DjangoApp
  |-urls.py
  |-settings.py
  |-manage.py
  |-views.py
  |-routed
      |-urls.py
      |-models.py
      |-tests.py

代码列表-2 django项目结构

首先需要改动的是项目的根urls.py,凡是所有以"routed"开头的url,都交给routedapp下的urls.py来处理

(r'^routed/', include('DjangoApp.routed.urls')),

代码列表-3 项目根urls.py的更改

然后,在routed app的urls.py中,添加对url按照路由进行解析的规则

from django.conf.urls.defaults import *
from DjangoApp.routed.viewstart import start

urlpatterns = patterns('',
	(r'^(?P<controller>\w+)?/(?P<action>\w+)?/(?P<parameter>.+)?$', start),
)

代码列表-4 routed app中urls.py的更改

在这个规则中,将所有类似"/routed/controllerabc/actionxyz/parm123"的url都指向viewstart.py中的start方法处理

import inspect
from util.response import *
from util.common import *


def start(request,controller,action,parameter):
	#initialize controller, execute action with parameter
	prefix = 'DjangoApp.routed.controllers.'

	namespace = prefix + controller
	__import__(namespace)
	module = common.importmodule(namespace)
	
	methods = [k for k,v in inspect.getmembers(module) if k == action]
	if len(methods) <= 0:
		return response.http404()

	return getattr(module,methods[0])(request)

代码列表-5 viewstart.py

在viewstart.py中,根据匹配得到的Controller查找python模块,然后过滤用inspect.getmembers得到的方法,找到对应Action并执行之,python中的反射非常易用,内置方法__import__可动态引入需要的模块,globals方法可以返回传入的字符串代表的对象,getattr方法的返回值直接加上括号即可执行。代码中,util.common中封装了由字符串反射得到对象实例的方法,util.response封装了各种http response的方法,参考代码列表-6、代码列表-7。

import os
import sys

class common:
    @classmethod
    def importmodule(self,namespace):
        components = namespace.split('.')
        if len(components) == 1:
            return globals()[namespace]

        module = __import__(components[0])
        for compent in components[1:]:
            module = getattr(module, compent)

        return module

代码列表-6 common.py

from django.template import Context
from django.template.loader import get_template
from django.shortcuts import render_to_response
from django.http import HttpResponse
from django.core import serializers 


class response:
	@classmethod
	def json(self,object):
		json = serializers.serialize("json", object)
		return HttpResponse(json,'application/json')

	@classmethod
	def xml(self,object):
		xml = serializers.serialize("xml", object)
		return HttpResponse(xml,'application/xml')
	
	@classmethod
	def falt(self,errormessage=''):
		return self.json({"errorcode":"500","message":errormessage if errormessage else ''})

	@classmethod
	def view(self,view,view_model=None):
		view_path = view+'.view'
		return render_to_response(view_path,view_model)

	@classmethod
	def text(self,text):
		return HttpResponse(text)

	@classmethod
	def http404(self):
		return self.view('http404')

代码列表-7 response.py

最后,我们只要在routed app下创建controllers文件夹,然后创建controller即可通过controller名称对应的Url访问,如创建book.py

from util.response import *
from routed.models import Book

def list(request):
	books = Book.objects.all()
	return response.json(books)

代码列表-8 book.py

输入book controller中的list action对应的url http://localhost/routed/book/list 试试看吧。

posted @ 2012-06-04 22:19  傲雪啸风  阅读(2108)  评论(5编辑  收藏  举报