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 試試看吧。