Hi all,

Full disclosure: I’m one of the authors of django-hosts. But I’ve thought about 
this problem a lot and maybe that’s useful for this discussion, maybe not :)

# Passing the request to reverse

I'm not convinced that reverse should be directly passed the request to build a 
full URL since it removes the separation of concern between request parameter 
handling and URL reversal and therefore be a step in the wrong direction. 
Having to hand around the request on application level is basically a waste of 
CPU cycles since that information is already be known to Django on the URL 
resolver level.

Of course I acknowledge that the use case of generating full URLs on 
application level exists and that there are multiple ways to achieve this goal. 
E.g. django-hosts has been designed to mimic the URL pattern system to follow a 
recognizable and well-established pattern outside of Django’s core, and does 
more than just single-host reversal.

# django-hosts

It allows a single Django project to respond to requests with different 
HTTP_HOST headers (e.g. docs.example.com, api.example.com, admin.example.com) 
and maps each host to different URL configurations if configured so in "host 
patterns”, conventionally defined in hosts.py next to a project’s urls.py.

Since it was developed as a 3rd party app it obviously had to implement its own 
reverse method to take the host into account when doing the reversal, since the 
actual lookup happens with the predefined host patterns, while the URL path 
reversal happens with Django’s own reverse. It uses a ROOT_HOSTCONF setting to 
locate the host patterns (similar to ROOT_URL) and defaults to the host that is 
defined by the DEFAULT_HOST setting if not provided during the reversal. That 
way it is API-compatible when used via its reverse function or template tag.

I wasn't around when the inclusion of django-hosts or similar ideas was 
discussed at the DuTH sprint so I’m not sure how much of django-hosts can and 
should be ported to Django. I let Tim elaborate on that.

# Hosts in Django

What I personally would see as the right direction is to find a common ground 
for apps like django-hosts and simpler use cases such as generating the full 
URL when reversing a URL. From a user perspective I like where the DEP 
(https://github.com/django/deps/pull/27) for simpler URL patterns goes, e.g. it 
proposes something like this:

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    path('articles/<int:year>/', views.year_archive),
    path('articles/<int:year>/<int:month>/', views.month_archive),
    path('articles/<int:year>/<int:month>/<int:day>/', views.article_detail),
]

So what we could do is allow optionally wrapping some paths with a new, 
optional host function:

from django.urls import path, host

urlpatterns = [
    host('blog.example.com', [
        path('articles/2003/', views.special_case_2003, 
name='blog-special-2003'),
        path('articles/<int:year>/', views.year_archive, name='blog-year'),
        path('articles/<int:year>/<int:month>/', views.month_archive, 
name='blog-month'),
        path('articles/<int:year>/<int:month>/<int:day>/', 
views.article_detail, name='blog-day'),
    ], scheme='//'),
    host('api.example.com', [
        path('v1/', include(api.urls), namespace='api'),
    ], scheme='https://')
]

The host function adds the given host and optional scheme to each URL pattern 
so it's available in the URL resolver reverse function as an optional parameter 
when constructing the URL. Of course that also means that the URL resolver 
requires the request host when it resolves the URL pattern callback and not 
only the request path. But since that’s an internal API I don’t see any 
backward-compatibility issues with that.

Both the main reverse function and the URL tag would simply get new parameters 
whether or not to return the full URL (defaulting to False for backward 
compatibility) and maybe an optional scheme parameter. All those would be 
possible calls:

reverse('blog-year', kwargs={'year': 2016}) -> /articles/2016/
reverse('blog-year', kwargs={'year': 2016}, host=True) -> 
//blog.example.com/articles/2016/
reverse('blog-year', kwargs={'year': 2016}, host=True, scheme='https://') -> 
https://blog.example.com/articles/2016/

reverse('api:user-list') -> /v1/users/
reverse('api:user-list', host=True) -> https://api.example.com/v1/users/
reverse('api:user-list', host=True, scheme='//') -> //api.example.com/v1/users/

{% url 'blog-year' year=2016 %} -> /articles/2016/
{% url 'blog-year' year=2016 with host=True %} -> 
//blog.example.com/articles/2016/
{% url 'blog-year' year=2016 with host=True scheme='https://' %} -> 
https://blog.example.com/articles/2016/

{% url 'api:user-list' %} -> /articles/2016/
{% url 'api:user-list' with host=True %} -> https://api.example.com/v1/users/
{% url 'api:user-list' with host=True scheme='//' %} -> 
//api.example.com/v1/users/

Tim, does that follow your ideas about adding django-hosts like features to 
Django?

Jannis


> On 11 Nov 2016, at 09:14, Mislav Cimperšak <mislav.cimper...@gmail.com> wrote:
> 
> Thinking about url tag and threadlocals is a step in the wrong direction.
> 
> The original PR is just a simple addition (that is still backwards 
> compatible) to the `reverse` method; how people choose to use it (and when) 
> is up to them. Adding something to the `url` tag is almost bound to brake 
> something.
> This implementation does not brake anything regarding `url` tag and can stand 
> on it's own.
> 
> I've talked to several people on sprints in Amsterdam before submitting a PR 
> and it sounded like a good idea to them and reassured with DRF implementation 
> I went with it :)
> 
> On Sat, Nov 5, 2016 at 11:04 PM, Florian Apolloner <f.apollo...@gmail.com> 
> wrote:
> On Saturday, November 5, 2016 at 6:56:29 PM UTC+1, Sjoerd Job Postmus wrote:
> If you go with storing the base domain in the threadlocals, why not go full 
> in and store the request itself in the locals? [1]
> 
> 
> Because that opens a whole new can of worms, if possible we want less 
> threadlocals, not more…
>  
> As far as using it in the templates... We have a RequestContext right? So in 
> most cases that should not be an issue I presume.
> 
> 
> Still leaves the question of how to nicely pass this to the url tag.
> 
> But yes, Celery would be a problem, unless we push the request object to 
> celery as well, but I presume that makes mostly no sense except for this.
> 
> 
> Yeah, I didn't think that through :) 
> 
> -- 
> You received this message because you are subscribed to a topic in the Google 
> Groups "Django developers (Contributions to Django itself)" group.
> To unsubscribe from this topic, visit 
> https://groups.google.com/d/topic/django-developers/-rbLcdJkIpk/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to 
> django-developers+unsubscr...@googlegroups.com.
> To post to this group, send email to django-developers@googlegroups.com.
> Visit this group at https://groups.google.com/group/django-developers.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/django-developers/84fc3b7a-4263-46bb-a292-e27215952e63%40googlegroups.com.
> 
> For more options, visit https://groups.google.com/d/optout.
> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "Django developers (Contributions to Django itself)" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to django-developers+unsubscr...@googlegroups.com.
> To post to this group, send email to django-developers@googlegroups.com.
> Visit this group at https://groups.google.com/group/django-developers.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/django-developers/CACcAD09g-yCWw6U5WS-ykKJRG5poWnrBCEOTGFO6YrQKgCKePQ%40mail.gmail.com.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/C508621B-9931-463D-86F3-205824A366CE%40gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to