我做了一些谷歌搜索,真的找不到答案。
假设我有以下简单的类:
class dashboard:
def index(self, request):
return HttpResponse("Hello world")
def profile(self, request):
return HttpResponse("Your profile")
def user(self, request, user_id):
usr = User.objects.get(id=user_id)
return HttpResponse("Some info on usr")
我想做的是地图:
mysite.com/dashboard => dashboard.index
mysite.com/dashboard/profile => dashboard.profile
mysite.com/dashboard/user/1 => dashboard.user(1)
无需为每个 URL 设置一个 URL 模式 - 例如:
urlpatterns = patterns('',
url(r'^/dashboard$', views.dashboard, name='dashboard'),
url(r'^/dashboard/profile$', views.profile, name='profile'),
# etc...
)
我想到了这一点,唯一我认为这可行的是:
urlpatterns = patterns('',
url(r'^/(?<root1>\w+)/(?<root2>\w+)/(?<root3>)$', urltrigger, name='trigger'),
# etc...
)
# https://stackoverflow.com/questions/547829/how-to-dynamically-load-a-python-class
def my_import(name):
mod = __import__(name)
components = name.split('.')
for comp in components[1:]:
mod = getattr(mod, comp)
return mod
def urltrigger(request, root1, root2 = None, root3 = None):
try:
cmodule = my_import(root1)
dync = cmodule() # perhaps request is a parameter to the constructor?
if root2 = None:
dync.index(request)
else:
method = getattr(dync, root2)
if root3 == None:
method()
else:
method(root3)
except:
raise Http404
(请原谅快速完成的 Python 代码)这确实不应该引入任何安全问题,因为类模块必须存在于 pythonpath 中 - 如果攻击者确实可以访问 pythonpath 中的文件,他们可以很容易地修改其他视图/代码。
有人对此有任何想法吗?使用这种方法,我可能会失去使用 Django 装饰器的能力——我可以接受,因为我可以在类的构造函数。
编辑:
我得到了一切工作 - 它只有 10 行代码。
编辑2:
对于那些想知道的人:
把它作为一个模式:
(r'^(.+?)/(?:(.+?)/)?$', free_pattern)
这是 free_pattern (从那时起我显然已经修改了它):
def free_pattern(request, view, segments=""):
if segments != None:
segments = segments.split(r'/')
match = re.match("(\.|\\|/)", view)
if match:
raise Http404
dnyc = None
try:
if not segments:
cmodule = __import__(view + ".controllers." + view, globals(), locals(), [view], -1)
dnyc = getattr(cmodule, view)
else:
cmodule = __import__(view + ".controllers." + segments[0], globals(), locals(), [segments[0]], -1)
dnyc = getattr(cmodule, segments[0])
except Exception, e:
return HttpResponse(str(e))
c = dnyc(request)
if segments == None or len(segments) == 1:
return c.index()
else:
lst = segments[2:]
return getattr(c, segments[1])(*lst)
如果你去 /site/ 它会在 site/controllers/site.py 中加载类站点并调用 index 方法:
class site:
def __init__(self, request):
pass # do something with request
def index(self):
pass
如果你去 /site/page 它将加载 site/controllers/page.py 中的类页面并调用 index 方法。转到 /site/page/one 将调用类页面中的 one 方法,最后转到 /site/page/one/1/ 会将 1(以及它之后的任何内容)作为参数作为参数传递给该方法。
如果您认为这行不通,请告诉我原因,而不是“我真的很高兴我永远不必支持它”。后者对我没有帮助,对其他人没有帮助,也没有解释为什么这样的系统不起作用。在我看来 - 单独的评论并不能回答这个问题。
如果您想知道我被困在 Django 1.4 上,因为我必须使用没有 virtualenv/pip/easy_install 的 Python 2.5。我真的很想——但这是没有商量余地的。这也不仅仅是为了我的“个人”使用 - 所以切换网络主机也是不可能的。
我要注意的一件事 - 使用官方 Django CBV 只会引入相同的问题(忽略安全性) - 例如无法应用 Django 装饰器,例如 login_requried。可以查看此 SO 帖子(https://stackoverflow.com/a/11525851/195722)以解决问题。