Django

Code

Ticket #5034 (new)

Opened 1 year ago

Last modified 3 weeks ago

request.urlconf does not get used in URL template tag

Reported by: Trey Assigned to: SmileyChris
Milestone: Component: Core framework
Version: SVN Keywords: url, urlconf, override
Cc: justin2@fagnani.com, eallik@gmail.com, joesaccount@gmail.com Triage Stage: Design decision needed
Has patch: 1 Needs documentation: 0
Needs tests: 0 Patch needs improvement: 0

Description

When you override the ROOT_URLCONF in a middleware by setting request.urlconf the URL template tag fails to resolve urls according to the new URL module. I have done quite a bit of searching on this topic and haven't found any definitive answers.

Based on #3187 this seems to be the correct thing to do. The request dict appears to be a poor way to transmit the data but without some sort of integrated threadlocals system and per the previously mentioned tag this patch seems appropriate.

Attachments

url_templatetag_urlconf.patch (1.1 kB) - added by Trey <trey@ktrl.com> on 07/31/07 21:10:13.
This patch will modify the URLNode class in template/defaulttags.py to use the urlconf in the request context if available.
request_aware_reversing.diff (10.1 kB) - added by SmileyChris on 01/22/08 21:21:15.
request_aware_reversing.2.diff (11.1 kB) - added by SmileyChris on 01/23/08 21:31:55.
forgot to add some test files
set_urlconf.diff (9.3 kB) - added by SmileyChris on 07/22/08 22:36:57.

Change History

07/31/07 21:10:13 changed by Trey <trey@ktrl.com>

  • attachment url_templatetag_urlconf.patch added.

This patch will modify the URLNode class in template/defaulttags.py to use the urlconf in the request context if available.

07/31/07 21:11:55 changed by Trey <trey@ktrl.com>

  • needs_better_patch changed.
  • needs_tests changed.
  • needs_docs changed.

I forgot to mention, for this to work you will need to use the REQUEST context. http://www.djangoproject.com/documentation/templates_python/#django-core-context-processors-request

07/31/07 21:52:44 changed by SmileyChris

  • needs_docs set to 1.
  • stage changed from Unreviewed to Design decision needed.

Thanks Trey, very timely since we have been discussing the future need to couple reverse with request somehow recently in Django devs.

As you have stated, currently this looks like the best solution (introducing the prerequisite of the request context processor of you require changing the URLconf). Perhaps some documentation could be provided to explain this.

For now, I'll pass to Design Decision for another set of eyes.

09/16/07 16:41:27 changed by ubernostrum

  • status changed from new to closed.
  • resolution set to duplicate.

I'd be inclined to accept it on its own, but it really ought to be rolled in with #3530 which does the same to permalink, and so kill two birds with one stone by fixing the underlying problem with reverse. Closing this in favor of #3530 somewhat arbitrarily, since that's the older ticket.

09/16/07 16:58:12 changed by Trey <trey@ktrl.com>

I would tend to agree with you normally. However, I see no reason to close the ticket since there doesn't seem to be an actual solution to this problem in the code or currently proposed. I don't think ignoring the problem in hopes that a better way will be proposed in the future is an answer.

From what I can tell there isn't a solution proposed or even considered in #3530 that would blanket these problems. I would be very disappointed for this patch to be ignored simply because it branches from a deeper rooted problem.

09/16/07 20:04:10 changed by ubernostrum

Trey, I'm not saying "give up on your patch, it's rejected". I'm saying "this other ticket is working on very similar stuff, let's merge into one ticket and get all the work done there".

09/16/07 21:55:12 changed by Trey <trey@ktrl.com>

I didn't think you were saying that, at least not like that. I just don't see the relationship between this ticket and #3530 that's all. I can see how they are similar, but the real problem is that request isn't portable to all pieces of the app. Unless some sort of threadlocal or, if I were in Java, a singleton style of class were introduced the problem will remain.

Anyway, I guess my point is that the over arching issue is much larger than either of these two tickets originally and seems like it would be a major change to the core of django which would require a lot of design decisions. I would like to see a ticket or topic discussing what the long term plan is if you know of one. Otherwise, should you or I move my patch over to #3530 so that I don't have to patch every instance of django?

01/22/08 21:21:15 changed by SmileyChris

  • attachment request_aware_reversing.diff added.

01/22/08 21:25:07 changed by SmileyChris

  • status changed from closed to reopened.
  • needs_docs deleted.
  • resolution deleted.

I agree with Trey that this ticket isn't that closely related to the other that they need a merge.

My patch comes with tests and documentation.

01/22/08 21:33:05 changed by SmileyChris

  • owner changed from nobody to SmileyChris.
  • status changed from reopened to new.

Hope you don't mind Trey, but I'll take ownership of the ticket. If you could give some feedback on my patch it'd be appreciated.

(follow-up: ↓ 10 ) 01/23/08 08:53:30 changed by trey

I think that this patch covers a lot of the instances where you would want to override the URLconf instead of my original patch which just updated the {% url %} tag. This is how J2EE stuff solves the problem and it looks very clean to me. Short of using threadlocals or some other black magic this is as good as it's gonna get :)

However, weighing in on the URL block tag specifically. It seems that you assume request will always be available in the context if it's a Request Context. Since there is a built-in django.core.context_processors.request template context processor is request always available or does that context need to be present?

01/23/08 21:31:55 changed by SmileyChris

  • attachment request_aware_reversing.2.diff added.

forgot to add some test files

(in reply to: ↑ 9 ) 01/23/08 21:38:04 changed by SmileyChris

Replying to trey:

I think that this patch covers a lot of the instances where you would want to override the URLconf instead of my original patch which just updated the {% url %} tag. This is how J2EE stuff solves the problem and it looks very clean to me. Short of using threadlocals or some other black magic this is as good as it's gonna get :)

Yep, I think this is a good interim. Even if the other patch gets in, it's up to the individual to implement where as this patch will at least cover most cases for people who need it (at least it clearly documents where it won't).

However, weighing in on the URL block tag specifically. It seems that you assume request will always be available in the context if it's a Request Context. Since there is a built-in django.core.context_processors.request template context processor is request always available or does that context need to be present?

It's not actually getting it from the context itself (because, as you noted, it would depend on the request context processor). I've made a small change to RequestContext -- it now stores request as an attribute. So rather than looking for a context variable, we can just look directly at the context.request attribute.

01/24/08 07:57:35 changed by trey

Ah, very nice. I missed that small line.

I will test this patch out on my installs and see if I can root out any other issues.

06/27/08 20:52:01 changed by justinf

I think there may be a little too much use of isinstance() in this patch.

Specifically on lines 362-365 of defaulttags.py

        if isinstance(context, RequestContext): 
            urlconf = context.request 
        else: 
            urlconf = None 

should probably be replaced with something like

        urlconf = getattr(context, 'request', None) or context.get('request', None)

I ran into a case where I couldn't pass a RequestContext? to a template, but I could set contextrequest?, and this change allowed {% url %} to still work. Of course, there could be issues with assuming that contextrequest? is a HttpRequest, but it's probably very rare that it isn't.

I'm not sure how the other uses of isinstance() might effect things, but line 305 of urlresolver.py seems like it could be removed:

if urlconf is not None and isinstance(urlconf, HttpRequest): 
        urlconf = getattr(urlconf, 'urlconf', None) 

to leave

urlconf = getattr(urlconf, 'urlconf', urlconf) 

06/28/08 17:26:46 changed by anonymous

  • cc set to jannis@leidel.info.

06/28/08 17:30:57 changed by jezdez

  • cc deleted.

Just in case you need help during the coming sprintsfor docs and tests, I'm here to help :)

07/22/08 14:13:57 changed by anonymous

  • cc set to justin2@fagnani.com.

I'm sure most of us who pay attention to this ticket are aware of this, but the patch here no longer works with trunk.

It looks like Malcolm might be working on this, but if you need to have request aware reversing and want to use trunk, a simple addition to get_resolver() in urlresolvers.py and some middleware will make it work. This uses threading.local rather than explicitly passing the request.

First, there's this middleware that I put in django/middleware/request.py:

try:
    from threading import local
except ImportError:
    from django.utils._threading_local import local

_thread_locals = local()
def get_request():
    return getattr(_thread_locals, 'request', None)

class RequestMiddleware(object):
    """Middleware that saves the current request in thread local storage."""
    def process_request(self, request):
        _thread_locals.request = request

Then the change to get_resolver():

from django.middleware.request import get_request

def get_resolver(urlconf):
    if urlconf is None:
        request = get_request()
        if request:
            urlconf = request.urlconf
    if urlconf is None:
        from django.conf import settings
        urlconf = settings.ROOT_URLCONF
    return RegexURLResolver(r'^/', urlconf)

I've only done minimal testing, but I figured someone looking here might want to try this.

07/22/08 22:30:20 changed by SmileyChris

After talking with Malcolm today on IRC, here's a new take on this. Less leaky.

07/22/08 22:36:57 changed by SmileyChris

  • attachment set_urlconf.diff added.

10/05/08 10:07:19 changed by anonymous

  • cc changed from justin2@fagnani.com to justin2@fagnani.com, eallik@gmail.com.

10/31/08 19:00:36 changed by jos3ph

  • cc changed from justin2@fagnani.com, eallik@gmail.com to justin2@fagnani.com, eallik@gmail.com, joesaccount@gmail.com.

Add/Change #5034 (request.urlconf does not get used in URL template tag)




Change Properties
Action