2

I did some googling and really couldn't find an answer to this.

Let's say I have the following simple class:

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")

What I want to do is map:

mysite.com/dashboard => dashboard.index

mysite.com/dashboard/profile => dashboard.profile

mysite.com/dashboard/user/1 => dashboard.user(1)

Without having to have a URL pattern for each URL - such that:

urlpatterns = patterns('',
    url(r'^/dashboard$', views.dashboard, name='dashboard'),
    url(r'^/dashboard/profile$', views.profile, name='profile'),
    # etc...
)

I thought about this and the only I could think this could work is:

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

(Excuse the quickly done Python code) This really shouldn't introduce any security issues as the class module has to exist in pythonpath - and if an attacker does have access to files in pythonpath they could just as easily modify the other views/code.

Does anyone have any thoughts on this? Using this approach I would probably lose the ability to use Django decorators - which I'm ok with as I could mimic the behavior of decorators I would want (such as ensuring a person is logged in and/or is in specific groups) in the constructor of the class.

Edit:

I got it all working - it was only like 10 lines of code.

Edit2:

For those wondering:

Put this as a pattern:

(r'^(.+?)/(?:(.+?)/)?$', free_pattern)

And here is free_pattern (I've obviously modified it since then):

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)

What that will do is if you go to /site/ it will load the class site in site/controllers/site.py and call the index method:

class site:
    def __init__(self, request):
        pass # do something with request
    def index(self):
        pass

if you go to /site/page it will load the class page in site/controllers/page.py and call the index method. Going to /site/page/one will invoke the one method in class page, and finally going to /site/page/one/1/ will pass the 1 (and anything after it) as a parameter as parameters to the method.

If you don't think this would work - tell me why, not "I'm really glad I would never have to support that". The later doesn't help me, doesn't help other people and doesn't explain why such as a system wouldn't work. In my opinion - a comment alone will not answer that.

If you are wondering I'm stuck on Django 1.4 because I must use Python 2.5 without virtualenv/pip/easy_install. I really want to - but it's non-negotiable. This isn't just for my "personal" use either - so switching a web host is also out of the question.

One thing I want to note - using official Django CBV is only introducing the same problems (ignoring security) - such as inability to apply Django decorators such as login_requried. One can see this SO post ( https://stackoverflow.com/a/11525851/195722 ) for a work around.

Community
  • 1
  • 1
Natalie Adams
  • 1,841
  • 22
  • 27
  • 6
    You're creating an inner platform in my opinion. Django already has class-based views to do pretty much anything you need, and you can always extend those or make your own. As John stated, God help the person who has to maintain that inner platform, instead of being able to reference the Django CBV documentation. – Brandon Taylor Oct 16 '13 at 03:06
  • Adding to Brandon's comment, you probably want to do this comming from a different framework; thing is, django has it's own way of doing things. If you like doing things that way, I recommend you stay on your other framework or look for something else that fits your needs. A more viable approach in my opinion (if all you want is to "organize" your views in some way), is making your `views` module a package instead, and make multiples modules to manage each aspect of your site; then reference all the modules from the `__init__.py` on the `views` package. – asermax Oct 18 '13 at 02:14

0 Answers0