让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 试试看吧。

浙公网安备 33010602011771号