Re: Issue with CsrfViewMiddleware and "referer" checking for trusted and secure subdomains

2015-05-28 Thread Troy Grosfield
Don't want to do csrf_exempt because I need csrf protection since I'm 
posting data to the api. This works in cases where the site isn't secure 
(https), but once the code is moved to prod (secure site) it fails.


On Thursday, May 28, 2015 at 11:09:04 PM UTC-6, Josh Smeaton wrote:
>
> Forgive me, but wouldn't you just declare those views as csrf_exempt? A 
> csrf token at one site isn't going to be valid at another, right?
>
> On Friday, 29 May 2015 13:44:42 UTC+10, Troy Grosfield wrote:
>>
>> I have the following domain and subdomains both are trusted and both are 
>> secure (https):
>>
>>- https://example.com
>>- https://api.example.com
>>
>> When making POST ajax request from *https://example.com 
>> * to *https://api.example.com 
>> * I see the following error message:
>>
>>
>>1. detail: "CSRF Failed: Referer checking failed - 
>>https://example.com/path/to/some/url does not match 
>>https://api.example.com/.;
>>
>>
>> Which takes me to the *CsrfViewMiddleware* where I see *same_origin* 
>> checking:
>>
>> # Note that request.get_host() includes the port.
>> good_referer = 'https://%s/' % request.get_host()
>> if not same_origin(referer, good_referer):
>> reason = REASON_BAD_REFERER % (referer, good_referer)
>> return self._reject(request, reason)
>>
>> I trust my subdomain, but there's no way for this code to actually pass 
>> this validation.  Am I just missing something?  Why would trusted 
>> subdomains fail validation here?  Can't this at least be a setting 
>> something like *TRUSTED_SUBDOMAINS* that's also checked?
>>
>> The other option I see here it to override the *CsrfViewMiddleware's* 
>> *process_view* method as others have done 
>> . 
>>   However, it ends up being a rather extensive rewrite for only the few 
>> lines, that are mentioned above, that need to change.  Can we rewrite the 
>> *CsrfViewMiddleware 
>> *to be more modular so it's easy to subclass and overwrite pieces of the 
>> csrf vallidation?  Something along the lines of:
>>
>> class CsrfViewMiddleware(object):
>>
>> def process_view(self, request, callback, callback_args, 
>> callback_kwargs):
>>
>> [...]
>> 
>> # Assume that anything not defined as 'safe' by RFC2616 needs 
>> protection
>> if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
>> [...]
>> if request.is_secure():
>> [...]
>> 
>> # Note that request.get_host() includes the port.
>> good_referer = 'https://%s/' % request.get_host()
>> if not self.is_same_origin(referer, good_referer):
>> reason = REASON_BAD_REFERER % (referer, good_referer)
>> return self._reject(request, reason)
>>
>> [...]
>> return self._accept(request)
>>
>> def is_same_origin(self, referer, good_referer):
>> return same_origin(referer, good_referer):
>>
>>
>>  This at least gives the ability to override the *is_same_origin* method 
>> which would allow us to also check for legit subdomains (in this case 
>> https://api.example.com).
>>
>> Thoughts?
>>
>

-- 
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 http://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/8ca9b82f-80d5-405d-862f-d8a87de118da%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Issue with CsrfViewMiddleware and "referer" checking for trusted and secure subdomains

2015-05-28 Thread Josh Smeaton
Forgive me, but wouldn't you just declare those views as csrf_exempt? A 
csrf token at one site isn't going to be valid at another, right?

On Friday, 29 May 2015 13:44:42 UTC+10, Troy Grosfield wrote:
>
> I have the following domain and subdomains both are trusted and both are 
> secure (https):
>
>- https://example.com
>- https://api.example.com
>
> When making POST ajax request from *https://example.com 
> * to *https://api.example.com 
> * I see the following error message:
>
>
>1. detail: "CSRF Failed: Referer checking failed - 
>https://example.com/path/to/some/url does not match 
>https://api.example.com/.;
>
>
> Which takes me to the *CsrfViewMiddleware* where I see *same_origin* 
> checking:
>
> # Note that request.get_host() includes the port.
> good_referer = 'https://%s/' % request.get_host()
> if not same_origin(referer, good_referer):
> reason = REASON_BAD_REFERER % (referer, good_referer)
> return self._reject(request, reason)
>
> I trust my subdomain, but there's no way for this code to actually pass 
> this validation.  Am I just missing something?  Why would trusted 
> subdomains fail validation here?  Can't this at least be a setting 
> something like *TRUSTED_SUBDOMAINS* that's also checked?
>
> The other option I see here it to override the *CsrfViewMiddleware's* 
> *process_view* method as others have done 
> . 
>   However, it ends up being a rather extensive rewrite for only the few 
> lines, that are mentioned above, that need to change.  Can we rewrite the 
> *CsrfViewMiddleware 
> *to be more modular so it's easy to subclass and overwrite pieces of the 
> csrf vallidation?  Something along the lines of:
>
> class CsrfViewMiddleware(object):
>
> def process_view(self, request, callback, callback_args, 
> callback_kwargs):
>
> [...]
> 
> # Assume that anything not defined as 'safe' by RFC2616 needs 
> protection
> if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
> [...]
> if request.is_secure():
> [...]
> 
> # Note that request.get_host() includes the port.
> good_referer = 'https://%s/' % request.get_host()
> if not self.is_same_origin(referer, good_referer):
> reason = REASON_BAD_REFERER % (referer, good_referer)
> return self._reject(request, reason)
>
> [...]
> return self._accept(request)
>
> def is_same_origin(self, referer, good_referer):
> return same_origin(referer, good_referer):
>
>
>  This at least gives the ability to override the *is_same_origin* method 
> which would allow us to also check for legit subdomains (in this case 
> https://api.example.com).
>
> Thoughts?
>

-- 
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 http://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/07797a9c-343f-4d30-8875-143aed56bd4f%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Issue with CsrfViewMiddleware and "referer" checking for trusted and secure subdomains

2015-05-28 Thread Troy Grosfield
I have the following domain and subdomains both are trusted and both are 
secure (https):

   - https://example.com
   - https://api.example.com

When making POST ajax request from *https://example.com* to 
*https://api.example.com* I see the following error message:


   1. detail: "CSRF Failed: Referer checking failed - 
   https://example.com/path/to/some/url does not match 
   https://api.example.com/.;


Which takes me to the *CsrfViewMiddleware* where I see *same_origin* 
checking:

# Note that request.get_host() includes the port.
good_referer = 'https://%s/' % request.get_host()
if not same_origin(referer, good_referer):
reason = REASON_BAD_REFERER % (referer, good_referer)
return self._reject(request, reason)

I trust my subdomain, but there's no way for this code to actually pass 
this validation.  Am I just missing something?  Why would trusted 
subdomains fail validation here?  Can't this at least be a setting 
something like *TRUSTED_SUBDOMAINS* that's also checked?

The other option I see here it to override the *CsrfViewMiddleware's* 
*process_view* method as others have done 
. 
  However, it ends up being a rather extensive rewrite for only the few 
lines, that are mentioned above, that need to change.  Can we rewrite the 
*CsrfViewMiddleware 
*to be more modular so it's easy to subclass and overwrite pieces of the 
csrf vallidation?  Something along the lines of:

class CsrfViewMiddleware(object):

def process_view(self, request, callback, callback_args, 
callback_kwargs):

[...]

# Assume that anything not defined as 'safe' by RFC2616 needs 
protection
if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
[...]
if request.is_secure():
[...]

# Note that request.get_host() includes the port.
good_referer = 'https://%s/' % request.get_host()
if not self.is_same_origin(referer, good_referer):
reason = REASON_BAD_REFERER % (referer, good_referer)
return self._reject(request, reason)

[...]
return self._accept(request)

def is_same_origin(self, referer, good_referer):
return same_origin(referer, good_referer):


 This at least gives the ability to override the *is_same_origin* method 
which would allow us to also check for legit subdomains (in this case 
https://api.example.com).

Thoughts?

-- 
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 http://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/de9c2aca-c307-4715-b5e0-334a42bd6c2f%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Fellow Report - April 24, 2015

2015-05-28 Thread Chris Moirano
Hey Tim,

Sorry if this may be an unnecessary question but the ticket 24704 
(Development server does not restart on syntax errors) seems to be a 
regression and not a fix. I was previously on version 1.6.x and the 
development server would continue to run if there were syntax errors. The 
only change with this ticket was the docs were updated to remove the line "but 
it won't stop the server"(commit 
)
 
from the docs.  Is this development server change intentional in 1.8? 

On Saturday, April 25, 2015 at 7:09:27 PM UTC-5, Tim Graham wrote:
>
> I am thinking that if all goes well, we will probably release a 1.8.1 bug 
> fix release by next Friday. Currently we have about 20 fixes for that 
> release.
>
> Report for week ending April 24, 2015:
>
> Triaged
>
> ---
>
> https://code.djangoproject.com/ticket/24668 - Update docs example code 
> for ModelAdmin.save_formset() (fixed)
>
> https://code.djangoproject.com/ticket/24676 - Regression on ManytoMany 
> representation in the admin interface (accepted)
>
> https://code.djangoproject.com/ticket/24675 - Skip "SET SQL_AUTO_IS_NULL 
> = 0" on versions of MySQL that don't need it (accepted)
>
> https://code.djangoproject.com/ticket/24630 - Misleading/incorrect docs 
> about RunPython and transactions (accepted)
>
> https://code.djangoproject.com/ticket/24686 - Support for Moving a model 
> between two Django apps (accepted)
>
> https://code.djangoproject.com/ticket/24690 - ArrayField data bleeds 
> between instances when using field.append(item) (accepted)
>
> https://code.djangoproject.com/ticket/24689 - DetailView & ListView 
> get_template_name and get_context_object_name fail with deferred QuerySet 
> (accepted)
>
> https://code.djangoproject.com/ticket/24691 - Document 
> model._state.adding (since UUIDField sets value before save) (accepted)
>
> https://code.djangoproject.com/ticket/24698 - Relation clear fails 
> silently when using OneToOneField+UUIDField (accepted)
>
> https://code.djangoproject.com/ticket/24704 - Development server does not 
> restart on SynaxError (fixed)
>
> Authored
>
> 
>
> https://github.com/django/djangoproject.com/pull/458 - Fixed #445 -- 
> Fixed NotADirectory exception in docs app.
>
> https://github.com/django/django/pull/4389 - Fixed #24526 -- Combined 
> django.request/security loggers with the root logger.
>
> https://github.com/django/django/pull/4548 - Fixed #24649 -- Allowed 
> using Avg aggregate on non-numeric field types.
>
> Reviewed/committed
>
> --
>
> https://github.com/django/django/pull/4534 - Refactored 
> PasswordResetTokenGenerator to be a bit more extensible.
>
> https://github.com/django/django/pull/4458 - Refs #24397 -- Sped up model 
> reloading in ProjectState.
>
> https://github.com/django/django/pull/4393 - Fixed #22394 -- Refactored 
> built-in datetime lookups to transforms.
>
> https://github.com/django/django/pull/4533 - Refs #24591 -- Optimized 
> cloning of ModelState objects.
>
> https://github.com/django/django/pull/4460 - Fixed #24591 -- Optimized 
> cloning of ModelState objects.
>
> https://github.com/django/django/pull/4539 - Fixed #24613 -- Added 
> example to QuerySet.defer() documentation
>
> https://github.com/django/django/pull/4512 - Fixed #24643 -- Added 
> get_context_data() method to FormMixin
>
> https://github.com/django/django/pull/4546 - Fixed #24689 -- Fixed 
> DetailView methods with deferred QuerySet
>
> Reviews of core dev work
>
> 
>
> https://github.com/django/django/pull/4447 - Fixed #24573 -- Considered 
> new related models for reloading
>
> https://github.com/django/django/pull/4529 - Fixed #24654 -- Based 
> ordering circular references detection on columns.
>
> https://github.com/django/django/pull/4416 - Fixed #22598 -- Allowed 
> make_aware to work with ambiguous datetime
>
> https://github.com/django/django/pull/4558 - Fixed #24701 -- Converted 
> model manager names to unicode in migrations
> https://github.com/django/django/pull/4555 - Added lazyness to 
> contrib.gis imports
>

-- 
 

Confidentiality Notice: This message and any files transmitted with it are 
confidential and intended solely for the use of the individual or entity to 
whom they are addressed. If you are not the intended recipient, you are 
hereby notified that review, disclosure, dissemination, distribution, or 
copying of it or its contents is prohibited. If you have received this 
message in error, please notify the sender immediately and permanently 
delete this message and any attachments.

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

Re: URL namespaces

2015-05-28 Thread Tai Lee
Thanks for taking the time to write up this proposal. I agree on pretty 
much all counts, but I do have a few comments:

1)

If an app has templates and view code that are reversing 
:, then changing the app name (e.g. by an undocumented 
feature, passing a (patterns, app_name) tuple), then all those URLs will 
break. Unless I'm missing something, an app *must always* be installed with 
the app name that is hard coded in its templates and view code, so there is 
no workaround for app namespace conflicts?

Does or would it work to allow two apps with the same app namespace, as 
long as they both are installed with customised instance names, so that the 
"default app" namespace lookup doesn't return anything, and Django must 
fallback to the `current_app` to determine which app is being reversed?

2)

I'd rather see the "app name, period" (as opposed to a default app name) 
defined as a variable in an app's URLconf as per #11642 or as an attribute 
of the `urlpatterns` object, that Django looks at when a URLconf is 
included with a dotted path string, instead of requiring users to import 
and then include a `(patterns, app_name)` tuple. Basically, the app name 
defined by the app should be used for both of:

include(r^foo/', 'foo.urls')

and

from foo.urls import some_tuple
include(r'^foo/', some_tuple),

3)

Not exactly related to the issue at hand, but if we are reworking URL 
namespaces it might be worth some consideration. One reason why I always 
avoid using URL namespaces these days is that it becomes impossible to 
override an app URL at the project level. Project authors are stuck with 
the exact URLs defined by the app author, all located below the same root 
path where the URLs are included and with the same view behaviour.

Without namespaced URLs, the project author can include their own version 
of a URL at any location (as long as it comes before the app's included 
URLs) and change the view behaviour. For namespaced URLs, I'd like to be 
able to do something like:

urlpatterns = patterns('',
url(r'^my_foo_login/$', 'myapp.views.my_foo_login', name='login', 
app='foo', namespace='foo'),
url(r'^foo/', include('foo.urls', app='foo', namespace='foo')),
)

Then when templates or view code in the `foo` app does reverse('foo:login') 
they will get `/my_foo_login/` instead of `/foo/login/` and I can change 
the behaviour of the view.

Cheers.
Tai.


On Friday, May 29, 2015 at 1:21:58 AM UTC+10, Marten Kenbeek wrote:
>
> Sure, I'll go through the list of url tickets on Trac. 
>
> The key difference with #11642 is "default". What I propose is that 
> urls.py specifies the app_name, period. The only reason to change app_name 
> is conflicting app names, and there are easy workarounds that I feel 
> shouldn't be part of the API itself. The namespace would be specified in 
> include(), and default to the app_name. 
>
> Op donderdag 28 mei 2015 15:37:20 UTC+2 schreef Tim Graham:
>>
>> Point 1 sounds like https://code.djangoproject.com/ticket/11642 -- and 
>> that ticket says it may be superseded by 
>> https://code.djangoproject.com/ticket/21927. Could you review those 
>> tickets as well as the others in the "Core (URLs)" component of Trac? It 
>> would be good if you could assign yourself any tickets that your project 
>> will address.
>>
>> On Wednesday, May 27, 2015 at 5:58:00 PM UTC-4, Marten Kenbeek wrote:
>>>
>>> Hi all,
>>>
>>> URL namespaces have a few quirks that make them a bit difficult to use 
>>> and understand. I hope to create a patch that clears up these issues. 
>>>
>>> First up: the distinction between an application namespace and an 
>>> instance namespace. The docs say on the application namespace:
>>>
>>> This describes the name of the application that is being deployed. Every 
 instance of a single application will have the same application namespace.
>>>
>>>
>>> And on the instance namespace: 
>>>
>>> This identifies a specific instance of an application. Instance 
 namespaces should be unique across your entire project. However, an 
 instance namespace can be the same as the application namespace. This is 
 used to specify a default instance of an application. 
>>>
>>>
>>> The current implementation requires that both are specified in the same 
>>> place: either in the included url configuration by returning a 3-tuple, or 
>>> in the including url configuration through the arguments to include(). The 
>>> first case generally does not allow multiple deployments of the same app, 
>>> unless the included url configuration contains specific logic to return 
>>> different instance namespaces. The second case does not in any way enforce 
>>> that multiple deployments in fact have the same application namespace. 
>>>
>>> I'd like to get the semantics and the implementation in line, and 
>>> provide one obvious way to specify namespaces. Including a set of url 
>>> patterns under a namespace involves two parts: the including urlconf that 
>>> calls include(), and 

Re: URL namespaces

2015-05-28 Thread Tim Graham
I think it's an unlikely case anyway, but out of curiosity what are the 
workarounds? Working up a patch for the first issue sounds good to me. In 
the meantime, I'll continue refreshing myself of the rest of namespaces so 
I can reply to your other points.

On Thursday, May 28, 2015 at 11:21:58 AM UTC-4, Marten Kenbeek wrote:
>
> Sure, I'll go through the list of url tickets on Trac. 
>
> The key difference with #11642 is "default". What I propose is that 
> urls.py specifies the app_name, period. The only reason to change app_name 
> is conflicting app names, and there are easy workarounds that I feel 
> shouldn't be part of the API itself. The namespace would be specified in 
> include(), and default to the app_name. 
>
> Op donderdag 28 mei 2015 15:37:20 UTC+2 schreef Tim Graham:
>>
>> Point 1 sounds like https://code.djangoproject.com/ticket/11642 -- and 
>> that ticket says it may be superseded by 
>> https://code.djangoproject.com/ticket/21927. Could you review those 
>> tickets as well as the others in the "Core (URLs)" component of Trac? It 
>> would be good if you could assign yourself any tickets that your project 
>> will address.
>>
>> On Wednesday, May 27, 2015 at 5:58:00 PM UTC-4, Marten Kenbeek wrote:
>>>
>>> Hi all,
>>>
>>> URL namespaces have a few quirks that make them a bit difficult to use 
>>> and understand. I hope to create a patch that clears up these issues. 
>>>
>>> First up: the distinction between an application namespace and an 
>>> instance namespace. The docs say on the application namespace:
>>>
>>> This describes the name of the application that is being deployed. Every 
 instance of a single application will have the same application namespace.
>>>
>>>
>>> And on the instance namespace: 
>>>
>>> This identifies a specific instance of an application. Instance 
 namespaces should be unique across your entire project. However, an 
 instance namespace can be the same as the application namespace. This is 
 used to specify a default instance of an application. 
>>>
>>>
>>> The current implementation requires that both are specified in the same 
>>> place: either in the included url configuration by returning a 3-tuple, or 
>>> in the including url configuration through the arguments to include(). The 
>>> first case generally does not allow multiple deployments of the same app, 
>>> unless the included url configuration contains specific logic to return 
>>> different instance namespaces. The second case does not in any way enforce 
>>> that multiple deployments in fact have the same application namespace. 
>>>
>>> I'd like to get the semantics and the implementation in line, and 
>>> provide one obvious way to specify namespaces. Including a set of url 
>>> patterns under a namespace involves two parts: the including urlconf that 
>>> calls include(), and the included urlconf that is imported by include(). 
>>> The first is a specific deployment of the imported urlconf; the second is a 
>>> single app. 
>>>
>>> The obvious way as I see it would be to specify the application 
>>> namespace in the app, and specify the instance namespace as a parameter to 
>>> include(). This enforces the single application namespace for a single set 
>>> of patterns, and allows any end-user to specify the instance namespace on a 
>>> per-instance basis. To take the admin as an example:
>>>
>>> admin.site.urls would return a 2-tuple: (patterns, 'admin'), where 
>>> 'admin' is the application namespace. (An alternative to a 2-tuple could be 
>>> an object with urlpatterns and app_name attributes.)
>>> To include the admin instance, use include(admin.site.urls, 
>>> namespace='admin'). This is the instance namespace. If left out, it could 
>>> default to be the same as the app name.
>>>
>>> After a deprecation period, it would be an error to specify an instance 
>>> namespace if there is no application namespace. This is to ensure that the 
>>> app can always reverse its own urls using : if it 
>>> specifies an application namespace, and using  if it doesn't. 
>>> (Setting and app_name would technically still be possible by passing a 
>>> hardcoded (patterns, app_name) tuple, just not as an advertised feature.)
>>>
>>> The second point is about nested namespace handling and current_app. 
>>>
>>> At the moment, current_app is looking for an exact namespace match. 
>>> Unlike the namespaced view path, it is not split into namespace parts using 
>>> current_app.split(':'). Take the following (fictional) urlpatterns:
>>>
>>> blog_patterns = [
>>> url(r'^comments-one/', include('comments.urls', 'comments-one', 
>>> 'comments')),
>>> url(r'^comments-two/', include('comments.urls', 'comments-two', 
>>> 'comments')),
>>> ]
>>>
>>> urlpatterns = [
>>> url(r'^blog-one/', include(blog_patterns, 'blog-one', 'blog')),
>>> url(r'^blog-two/', include(blog_patterns, 'blog-two', 'blog')),
>>> ]
>>>
>>> Because of how current_app is handled, it is now impossible to reverse 
>>> 

Re: URL namespaces

2015-05-28 Thread Marten Kenbeek
Sure, I'll go through the list of url tickets on Trac. 

The key difference with #11642 is "default". What I propose is that urls.py 
specifies the app_name, period. The only reason to change app_name is 
conflicting app names, and there are easy workarounds that I feel shouldn't 
be part of the API itself. The namespace would be specified in include(), 
and default to the app_name. 

Op donderdag 28 mei 2015 15:37:20 UTC+2 schreef Tim Graham:
>
> Point 1 sounds like https://code.djangoproject.com/ticket/11642 -- and 
> that ticket says it may be superseded by 
> https://code.djangoproject.com/ticket/21927. Could you review those 
> tickets as well as the others in the "Core (URLs)" component of Trac? It 
> would be good if you could assign yourself any tickets that your project 
> will address.
>
> On Wednesday, May 27, 2015 at 5:58:00 PM UTC-4, Marten Kenbeek wrote:
>>
>> Hi all,
>>
>> URL namespaces have a few quirks that make them a bit difficult to use 
>> and understand. I hope to create a patch that clears up these issues. 
>>
>> First up: the distinction between an application namespace and an 
>> instance namespace. The docs say on the application namespace:
>>
>> This describes the name of the application that is being deployed. Every 
>>> instance of a single application will have the same application namespace.
>>
>>
>> And on the instance namespace: 
>>
>> This identifies a specific instance of an application. Instance 
>>> namespaces should be unique across your entire project. However, an 
>>> instance namespace can be the same as the application namespace. This is 
>>> used to specify a default instance of an application. 
>>
>>
>> The current implementation requires that both are specified in the same 
>> place: either in the included url configuration by returning a 3-tuple, or 
>> in the including url configuration through the arguments to include(). The 
>> first case generally does not allow multiple deployments of the same app, 
>> unless the included url configuration contains specific logic to return 
>> different instance namespaces. The second case does not in any way enforce 
>> that multiple deployments in fact have the same application namespace. 
>>
>> I'd like to get the semantics and the implementation in line, and provide 
>> one obvious way to specify namespaces. Including a set of url patterns 
>> under a namespace involves two parts: the including urlconf that calls 
>> include(), and the included urlconf that is imported by include(). The 
>> first is a specific deployment of the imported urlconf; the second is a 
>> single app. 
>>
>> The obvious way as I see it would be to specify the application namespace 
>> in the app, and specify the instance namespace as a parameter to include(). 
>> This enforces the single application namespace for a single set of 
>> patterns, and allows any end-user to specify the instance namespace on a 
>> per-instance basis. To take the admin as an example:
>>
>> admin.site.urls would return a 2-tuple: (patterns, 'admin'), where 
>> 'admin' is the application namespace. (An alternative to a 2-tuple could be 
>> an object with urlpatterns and app_name attributes.)
>> To include the admin instance, use include(admin.site.urls, 
>> namespace='admin'). This is the instance namespace. If left out, it could 
>> default to be the same as the app name.
>>
>> After a deprecation period, it would be an error to specify an instance 
>> namespace if there is no application namespace. This is to ensure that the 
>> app can always reverse its own urls using : if it 
>> specifies an application namespace, and using  if it doesn't. 
>> (Setting and app_name would technically still be possible by passing a 
>> hardcoded (patterns, app_name) tuple, just not as an advertised feature.)
>>
>> The second point is about nested namespace handling and current_app. 
>>
>> At the moment, current_app is looking for an exact namespace match. 
>> Unlike the namespaced view path, it is not split into namespace parts using 
>> current_app.split(':'). Take the following (fictional) urlpatterns:
>>
>> blog_patterns = [
>> url(r'^comments-one/', include('comments.urls', 'comments-one', 
>> 'comments')),
>> url(r'^comments-two/', include('comments.urls', 'comments-two', 
>> 'comments')),
>> ]
>>
>> urlpatterns = [
>> url(r'^blog-one/', include(blog_patterns, 'blog-one', 'blog')),
>> url(r'^blog-two/', include(blog_patterns, 'blog-two', 'blog')),
>> ]
>>
>> Because of how current_app is handled, it is now impossible to reverse 
>> patterns in 'blog-one:comments-one:' using current_app. To select 
>> 'blog-one', the current app needs to be the string 'blog-one', but to 
>> select 'comments-one', it needs to be 'comments-one'. The only solution is 
>> to hardcode at least one of the instance namespaces in the namespaced view 
>> path. This also means that setting request.current_app to 
>> request.resolver_match.namespace, as recommended in the docs, does not 

Re: URL namespaces

2015-05-28 Thread Tim Graham
Point 1 sounds like https://code.djangoproject.com/ticket/11642 -- and that 
ticket says it may be superseded by 
https://code.djangoproject.com/ticket/21927. Could you review those tickets 
as well as the others in the "Core (URLs)" component of Trac? It would be 
good if you could assign yourself any tickets that your project will 
address.

On Wednesday, May 27, 2015 at 5:58:00 PM UTC-4, Marten Kenbeek wrote:
>
> Hi all,
>
> URL namespaces have a few quirks that make them a bit difficult to use and 
> understand. I hope to create a patch that clears up these issues. 
>
> First up: the distinction between an application namespace and an instance 
> namespace. The docs say on the application namespace:
>
> This describes the name of the application that is being deployed. Every 
>> instance of a single application will have the same application namespace.
>
>
> And on the instance namespace: 
>
> This identifies a specific instance of an application. Instance namespaces 
>> should be unique across your entire project. However, an instance namespace 
>> can be the same as the application namespace. This is used to specify a 
>> default instance of an application. 
>
>
> The current implementation requires that both are specified in the same 
> place: either in the included url configuration by returning a 3-tuple, or 
> in the including url configuration through the arguments to include(). The 
> first case generally does not allow multiple deployments of the same app, 
> unless the included url configuration contains specific logic to return 
> different instance namespaces. The second case does not in any way enforce 
> that multiple deployments in fact have the same application namespace. 
>
> I'd like to get the semantics and the implementation in line, and provide 
> one obvious way to specify namespaces. Including a set of url patterns 
> under a namespace involves two parts: the including urlconf that calls 
> include(), and the included urlconf that is imported by include(). The 
> first is a specific deployment of the imported urlconf; the second is a 
> single app. 
>
> The obvious way as I see it would be to specify the application namespace 
> in the app, and specify the instance namespace as a parameter to include(). 
> This enforces the single application namespace for a single set of 
> patterns, and allows any end-user to specify the instance namespace on a 
> per-instance basis. To take the admin as an example:
>
> admin.site.urls would return a 2-tuple: (patterns, 'admin'), where 'admin' 
> is the application namespace. (An alternative to a 2-tuple could be an 
> object with urlpatterns and app_name attributes.)
> To include the admin instance, use include(admin.site.urls, 
> namespace='admin'). This is the instance namespace. If left out, it could 
> default to be the same as the app name.
>
> After a deprecation period, it would be an error to specify an instance 
> namespace if there is no application namespace. This is to ensure that the 
> app can always reverse its own urls using : if it 
> specifies an application namespace, and using  if it doesn't. 
> (Setting and app_name would technically still be possible by passing a 
> hardcoded (patterns, app_name) tuple, just not as an advertised feature.)
>
> The second point is about nested namespace handling and current_app. 
>
> At the moment, current_app is looking for an exact namespace match. Unlike 
> the namespaced view path, it is not split into namespace parts using 
> current_app.split(':'). Take the following (fictional) urlpatterns:
>
> blog_patterns = [
> url(r'^comments-one/', include('comments.urls', 'comments-one', 
> 'comments')),
> url(r'^comments-two/', include('comments.urls', 'comments-two', 
> 'comments')),
> ]
>
> urlpatterns = [
> url(r'^blog-one/', include(blog_patterns, 'blog-one', 'blog')),
> url(r'^blog-two/', include(blog_patterns, 'blog-two', 'blog')),
> ]
>
> Because of how current_app is handled, it is now impossible to reverse 
> patterns in 'blog-one:comments-one:' using current_app. To select 
> 'blog-one', the current app needs to be the string 'blog-one', but to 
> select 'comments-one', it needs to be 'comments-one'. The only solution is 
> to hardcode at least one of the instance namespaces in the namespaced view 
> path. This also means that setting request.current_app to 
> request.resolver_match.namespace, as recommended in the docs, does not work 
> if you have nested namespaces. 
>
> The ResolverMatch object also has some inconsistent behaviour for 
> app_name. resolver_match.namespace is the full namespace path, i.e. 
> 'blog-one:comments-one' (with resolver_match.namespaces a list of 
> individual namespaces, i.e. ['blog-one', 'comments-one']), but 
> resolver_match.app_name is the outer-most app_name, in this case 
> 'blog-one', with no trace whatsoever of the full app_name path. 
>
> To illustrate how I would see it end up eventually (after the deprecation 
> cycle), I've