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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM