Author: kkubasik
Date: 2009-07-22 07:43:04 -0500 (Wed, 22 Jul 2009)
New Revision: 11292

Added:
   
django/branches/soc2009/test-improvements/tests/regressiontests/urlpatterns_reverse/included_namespace_urls.py
   
django/branches/soc2009/test-improvements/tests/regressiontests/urlpatterns_reverse/namespace_urls.py
Modified:
   django/branches/soc2009/test-improvements/
   django/branches/soc2009/test-improvements/django/conf/urls/defaults.py
   django/branches/soc2009/test-improvements/django/contrib/admin/options.py
   django/branches/soc2009/test-improvements/django/contrib/admin/sites.py
   
django/branches/soc2009/test-improvements/django/contrib/admin/templates/admin/base.html
   django/branches/soc2009/test-improvements/django/contrib/admin/widgets.py
   
django/branches/soc2009/test-improvements/django/contrib/admindocs/templates/admin_doc/index.html
   django/branches/soc2009/test-improvements/django/contrib/admindocs/views.py
   
django/branches/soc2009/test-improvements/django/contrib/gis/db/models/manager.py
   
django/branches/soc2009/test-improvements/django/contrib/gis/db/models/sql/query.py
   
django/branches/soc2009/test-improvements/django/contrib/gis/tests/relatedapp/tests.py
   django/branches/soc2009/test-improvements/django/core/urlresolvers.py
   django/branches/soc2009/test-improvements/django/template/context.py
   django/branches/soc2009/test-improvements/django/template/defaulttags.py
   django/branches/soc2009/test-improvements/docs/howto/deployment/modwsgi.txt
   django/branches/soc2009/test-improvements/docs/intro/tutorial03.txt
   
django/branches/soc2009/test-improvements/docs/ref/contrib/admin/_images/article_actions.png
   django/branches/soc2009/test-improvements/docs/ref/contrib/admin/index.txt
   django/branches/soc2009/test-improvements/docs/ref/forms/fields.txt
   django/branches/soc2009/test-improvements/docs/ref/models/querysets.txt
   django/branches/soc2009/test-improvements/docs/ref/templates/api.txt
   django/branches/soc2009/test-improvements/docs/ref/templates/builtins.txt
   django/branches/soc2009/test-improvements/docs/topics/forms/formsets.txt
   django/branches/soc2009/test-improvements/docs/topics/http/urls.txt
   django/branches/soc2009/test-improvements/docs/topics/i18n.txt
   django/branches/soc2009/test-improvements/docs/topics/testing.txt
   
django/branches/soc2009/test-improvements/tests/regressiontests/admin_views/customadmin.py
   
django/branches/soc2009/test-improvements/tests/regressiontests/admin_views/tests.py
   
django/branches/soc2009/test-improvements/tests/regressiontests/admin_widgets/widgetadmin.py
   
django/branches/soc2009/test-improvements/tests/regressiontests/urlpatterns_reverse/tests.py
Log:
[gsoc2009-testing] Upstream merge



Property changes on: django/branches/soc2009/test-improvements
___________________________________________________________________
Name: svk:merge
   - 23ef3597-c209-482b-90c0-ea6045f15f7f:/local/django-gsoc:11062
23ef3597-c209-482b-90c0-ea6045f15f7f:/local/django/trunk:10927
bcc190cf-cafb-0310-a4f2-bffc1f526a37:/django/trunk:11227
   + 23ef3597-c209-482b-90c0-ea6045f15f7f:/local/django-gsoc:11094
23ef3597-c209-482b-90c0-ea6045f15f7f:/local/django/trunk:10927
bcc190cf-cafb-0310-a4f2-bffc1f526a37:/django/trunk:11258

Modified: django/branches/soc2009/test-improvements/django/conf/urls/defaults.py
===================================================================
--- django/branches/soc2009/test-improvements/django/conf/urls/defaults.py      
2009-07-22 08:59:57 UTC (rev 11291)
+++ django/branches/soc2009/test-improvements/django/conf/urls/defaults.py      
2009-07-22 12:43:04 UTC (rev 11292)
@@ -6,7 +6,16 @@
 handler404 = 'django.views.defaults.page_not_found'
 handler500 = 'django.views.defaults.server_error'
 
-include = lambda urlconf_module: [urlconf_module]
+def include(arg, namespace=None, app_name=None):
+    if isinstance(arg, tuple):
+        # callable returning a namespace hint
+        if namespace:
+            raise ImproperlyConfigured('Cannot override the namespace for a 
dynamic module that provides a namespace')
+        urlconf_module, app_name, namespace = arg
+    else:
+        # No namespace hint - use manually provided namespace
+        urlconf_module = arg
+    return (urlconf_module, app_name, namespace)
 
 def patterns(prefix, *args):
     pattern_list = []
@@ -19,9 +28,10 @@
     return pattern_list
 
 def url(regex, view, kwargs=None, name=None, prefix=''):
-    if type(view) == list:
+    if isinstance(view, (list,tuple)):
         # For include(...) processing.
-        return RegexURLResolver(regex, view[0], kwargs)
+        urlconf_module, app_name, namespace = view
+        return RegexURLResolver(regex, urlconf_module, kwargs, 
app_name=app_name, namespace=namespace)
     else:
         if isinstance(view, basestring):
             if not view:

Modified: 
django/branches/soc2009/test-improvements/django/contrib/admin/options.py
===================================================================
--- django/branches/soc2009/test-improvements/django/contrib/admin/options.py   
2009-07-22 08:59:57 UTC (rev 11291)
+++ django/branches/soc2009/test-improvements/django/contrib/admin/options.py   
2009-07-22 12:43:04 UTC (rev 11292)
@@ -226,24 +226,24 @@
                 return self.admin_site.admin_view(view)(*args, **kwargs)
             return update_wrapper(wrapper, view)
 
-        info = self.admin_site.name, self.model._meta.app_label, 
self.model._meta.module_name
+        info = self.model._meta.app_label, self.model._meta.module_name
 
         urlpatterns = patterns('',
             url(r'^$',
                 wrap(self.changelist_view),
-                name='%sadmin_%s_%s_changelist' % info),
+                name='%s_%s_changelist' % info),
             url(r'^add/$',
                 wrap(self.add_view),
-                name='%sadmin_%s_%s_add' % info),
+                name='%s_%s_add' % info),
             url(r'^(.+)/history/$',
                 wrap(self.history_view),
-                name='%sadmin_%s_%s_history' % info),
+                name='%s_%s_history' % info),
             url(r'^(.+)/delete/$',
                 wrap(self.delete_view),
-                name='%sadmin_%s_%s_delete' % info),
+                name='%s_%s_delete' % info),
             url(r'^(.+)/$',
                 wrap(self.change_view),
-                name='%sadmin_%s_%s_change' % info),
+                name='%s_%s_change' % info),
         )
         return urlpatterns
 
@@ -582,11 +582,12 @@
             'save_on_top': self.save_on_top,
             'root_path': self.admin_site.root_path,
         })
+        context_instance = template.RequestContext(request, 
current_app=self.admin_site.name)
         return render_to_response(self.change_form_template or [
             "admin/%s/%s/change_form.html" % (app_label, 
opts.object_name.lower()),
             "admin/%s/change_form.html" % app_label,
             "admin/change_form.html"
-        ], context, context_instance=template.RequestContext(request))
+        ], context, context_instance=context_instance)
 
     def response_add(self, request, obj, post_url_continue='../%s/'):
         """
@@ -977,11 +978,12 @@
             'actions_on_bottom': self.actions_on_bottom,
         }
         context.update(extra_context or {})
+        context_instance = template.RequestContext(request, 
current_app=self.admin_site.name)
         return render_to_response(self.change_list_template or [
             'admin/%s/%s/change_list.html' % (app_label, 
opts.object_name.lower()),
             'admin/%s/change_list.html' % app_label,
             'admin/change_list.html'
-        ], context, context_instance=template.RequestContext(request))
+        ], context, context_instance=context_instance)
 
     def delete_view(self, request, object_id, extra_context=None):
         "The 'delete' admin view for this model."
@@ -1032,11 +1034,12 @@
             "app_label": app_label,
         }
         context.update(extra_context or {})
+        context_instance = template.RequestContext(request, 
current_app=self.admin_site.name)
         return render_to_response(self.delete_confirmation_template or [
             "admin/%s/%s/delete_confirmation.html" % (app_label, 
opts.object_name.lower()),
             "admin/%s/delete_confirmation.html" % app_label,
             "admin/delete_confirmation.html"
-        ], context, context_instance=template.RequestContext(request))
+        ], context, context_instance=context_instance)
 
     def history_view(self, request, object_id, extra_context=None):
         "The 'history' admin view for this model."
@@ -1059,11 +1062,12 @@
             'app_label': app_label,
         }
         context.update(extra_context or {})
+        context_instance = template.RequestContext(request, 
current_app=self.admin_site.name)
         return render_to_response(self.object_history_template or [
             "admin/%s/%s/object_history.html" % (app_label, 
opts.object_name.lower()),
             "admin/%s/object_history.html" % app_label,
             "admin/object_history.html"
-        ], context, context_instance=template.RequestContext(request))
+        ], context, context_instance=context_instance)
 
     #
     # DEPRECATED methods.

Modified: 
django/branches/soc2009/test-improvements/django/contrib/admin/sites.py
===================================================================
--- django/branches/soc2009/test-improvements/django/contrib/admin/sites.py     
2009-07-22 08:59:57 UTC (rev 11291)
+++ django/branches/soc2009/test-improvements/django/contrib/admin/sites.py     
2009-07-22 12:43:04 UTC (rev 11292)
@@ -5,6 +5,7 @@
 from django.contrib.auth import authenticate, login
 from django.db.models.base import ModelBase
 from django.core.exceptions import ImproperlyConfigured
+from django.core.urlresolvers import reverse
 from django.shortcuts import render_to_response
 from django.utils.functional import update_wrapper
 from django.utils.safestring import mark_safe
@@ -38,17 +39,14 @@
     login_template = None
     app_index_template = None
 
-    def __init__(self, name=None):
+    def __init__(self, name=None, app_name='admin'):
         self._registry = {} # model_class class -> admin_class instance
-        # TODO Root path is used to calculate urls under the old root() method
-        # in order to maintain backwards compatibility we are leaving that in
-        # so root_path isn't needed, not sure what to do about this.
-        self.root_path = 'admin/'
+        self.root_path = None
         if name is None:
-            name = ''
+            self.name = 'admin'
         else:
-            name += '_'
-        self.name = name
+            self.name = name
+        self.app_name = app_name
         self._actions = {'delete_selected': actions.delete_selected}
         self._global_actions = self._actions.copy()
 
@@ -114,20 +112,20 @@
         name = name or action.__name__
         self._actions[name] = action
         self._global_actions[name] = action
-        
+
     def disable_action(self, name):
         """
         Disable a globally-registered action. Raises KeyError for invalid 
names.
         """
         del self._actions[name]
-        
+
     def get_action(self, name):
         """
         Explicitally get a registered global action wheather it's enabled or
         not. Raises KeyError for invalid names.
         """
         return self._global_actions[name]
-    
+
     def actions(self):
         """
         Get all the enabled actions as an iterable of (name, func).
@@ -159,9 +157,9 @@
         if 'django.core.context_processors.auth' not in 
settings.TEMPLATE_CONTEXT_PROCESSORS:
             raise ImproperlyConfigured("Put 
'django.core.context_processors.auth' in your TEMPLATE_CONTEXT_PROCESSORS 
setting in order to use the admin application.")
 
-    def admin_view(self, view):
+    def admin_view(self, view, cacheable=False):
         """
-        Decorator to create an "admin view attached to this ``AdminSite``. This
+        Decorator to create an admin view attached to this ``AdminSite``. This
         wraps the view and provides permission checking by calling
         ``self.has_permission``.
 
@@ -177,43 +175,49 @@
                         url(r'^my_view/$', self.admin_view(some_view))
                     )
                     return urls
+
+        By default, admin_views are marked non-cacheable using the
+        ``never_cache`` decorator. If the view can be safely cached, set
+        cacheable=True.
         """
         def inner(request, *args, **kwargs):
             if not self.has_permission(request):
                 return self.login(request)
             return view(request, *args, **kwargs)
+        if not cacheable:
+            inner = never_cache(inner)
         return update_wrapper(inner, view)
 
     def get_urls(self):
         from django.conf.urls.defaults import patterns, url, include
 
-        def wrap(view):
+        def wrap(view, cacheable=False):
             def wrapper(*args, **kwargs):
-                return self.admin_view(view)(*args, **kwargs)
+                return self.admin_view(view, cacheable)(*args, **kwargs)
             return update_wrapper(wrapper, view)
 
         # Admin-site-wide views.
         urlpatterns = patterns('',
             url(r'^$',
                 wrap(self.index),
-                name='%sadmin_index' % self.name),
+                name='index'),
             url(r'^logout/$',
                 wrap(self.logout),
-                name='%sadmin_logout'),
+                name='logout'),
             url(r'^password_change/$',
-                wrap(self.password_change),
-                name='%sadmin_password_change' % self.name),
+                wrap(self.password_change, cacheable=True),
+                name='password_change'),
             url(r'^password_change/done/$',
-                wrap(self.password_change_done),
-                name='%sadmin_password_change_done' % self.name),
+                wrap(self.password_change_done, cacheable=True),
+                name='password_change_done'),
             url(r'^jsi18n/$',
-                wrap(self.i18n_javascript),
-                name='%sadmin_jsi18n' % self.name),
+                wrap(self.i18n_javascript, cacheable=True),
+                name='jsi18n'),
             url(r'^r/(?P<content_type_id>\d+)/(?P<object_id>.+)/$',
                 'django.views.defaults.shortcut'),
             url(r'^(?P<app_label>\w+)/$',
                 wrap(self.app_index),
-                name='%sadmin_app_list' % self.name),
+                name='app_list')
         )
 
         # Add in each model's views.
@@ -225,7 +229,7 @@
         return urlpatterns
 
     def urls(self):
-        return self.get_urls()
+        return self.get_urls(), self.app_name, self.name
     urls = property(urls)
 
     def password_change(self, request):
@@ -233,8 +237,11 @@
         Handles the "change password" task -- both form display and validation.
         """
         from django.contrib.auth.views import password_change
-        return password_change(request,
-            post_change_redirect='%spassword_change/done/' % self.root_path)
+        if self.root_path is not None:
+            url = '%spassword_change/done/' % self.root_path
+        else:
+            url = reverse('admin:password_change_done', current_app=self.name)
+        return password_change(request, post_change_redirect=url)
 
     def password_change_done(self, request):
         """
@@ -362,8 +369,9 @@
             'root_path': self.root_path,
         }
         context.update(extra_context or {})
+        context_instance = template.RequestContext(request, 
current_app=self.name)
         return render_to_response(self.index_template or 'admin/index.html', 
context,
-            context_instance=template.RequestContext(request)
+            context_instance=context_instance
         )
     index = never_cache(index)
 
@@ -376,8 +384,9 @@
             'root_path': self.root_path,
         }
         context.update(extra_context or {})
+        context_instance = template.RequestContext(request, 
current_app=self.name)
         return render_to_response(self.login_template or 'admin/login.html', 
context,
-            context_instance=template.RequestContext(request)
+            context_instance=context_instance
         )
 
     def app_index(self, request, app_label, extra_context=None):
@@ -419,9 +428,10 @@
             'root_path': self.root_path,
         }
         context.update(extra_context or {})
+        context_instance = template.RequestContext(request, 
current_app=self.name)
         return render_to_response(self.app_index_template or 
('admin/%s/app_index.html' % app_label,
             'admin/app_index.html'), context,
-            context_instance=template.RequestContext(request)
+            context_instance=context_instance
         )
 
     def root(self, request, url):

Modified: 
django/branches/soc2009/test-improvements/django/contrib/admin/templates/admin/base.html
===================================================================
--- 
django/branches/soc2009/test-improvements/django/contrib/admin/templates/admin/base.html
    2009-07-22 08:59:57 UTC (rev 11291)
+++ 
django/branches/soc2009/test-improvements/django/contrib/admin/templates/admin/base.html
    2009-07-22 12:43:04 UTC (rev 11292)
@@ -23,7 +23,30 @@
         {% block branding %}{% endblock %}
         </div>
         {% if user.is_authenticated and user.is_staff %}
-        <div id="user-tools">{% trans 'Welcome,' %} <strong>{% firstof 
user.first_name user.username %}</strong>. {% block userlinks %}{% url 
django-admindocs-docroot as docsroot %}{% if docsroot %}<a href="{{ docsroot 
}}">{% trans 'Documentation' %}</a> / {% endif %}<a href="{{ root_path 
}}password_change/">{% trans 'Change password' %}</a> / <a href="{{ root_path 
}}logout/">{% trans 'Log out' %}</a>{% endblock %}</div>
+        <div id="user-tools">
+            {% trans 'Welcome,' %}
+            <strong>{% firstof user.first_name user.username %}</strong>.
+            {% block userlinks %}
+                {% url django-admindocs-docroot as docsroot %}
+                {% if docsroot %}
+                    <a href="{{ docsroot }}">{% trans 'Documentation' %}</a> /
+                {% endif %}
+                {% url admin:password_change as password_change_url %}
+                {% if password_change_url %}
+                    <a href="{{ password_change_url }}">
+                {% else %}
+                    <a href="{{ root_path }}password_change/">
+                {% endif %}
+                {% trans 'Change password' %}</a> /
+                {% url admin:logout as logout_url %}
+                {% if logout_url %}
+                    <a href="{{ logout_url }}">
+                {% else %}
+                    <a href="{{ root_path }}logout/">
+                {% endif %}
+                {% trans 'Log out' %}</a>
+            {% endblock %}
+        </div>
         {% endif %}
         {% block nav-global %}{% endblock %}
     </div>

Modified: 
django/branches/soc2009/test-improvements/django/contrib/admin/widgets.py
===================================================================
--- django/branches/soc2009/test-improvements/django/contrib/admin/widgets.py   
2009-07-22 08:59:57 UTC (rev 11291)
+++ django/branches/soc2009/test-improvements/django/contrib/admin/widgets.py   
2009-07-22 12:43:04 UTC (rev 11292)
@@ -125,7 +125,7 @@
         if value:
             output.append(self.label_for_value(value))
         return mark_safe(u''.join(output))
-    
+
     def base_url_parameters(self):
         params = {}
         if self.rel.limit_choices_to:
@@ -137,14 +137,14 @@
                     v = str(v)
                 items.append((k, v))
             params.update(dict(items))
-        return params    
-    
+        return params
+
     def url_parameters(self):
         from django.contrib.admin.views.main import TO_FIELD_VAR
         params = self.base_url_parameters()
         params.update({TO_FIELD_VAR: self.rel.get_related_field().name})
         return params
-            
+
     def label_for_value(self, value):
         key = self.rel.get_related_field().name
         obj = self.rel.to._default_manager.get(**{key: value})
@@ -165,10 +165,10 @@
         else:
             value = ''
         return super(ManyToManyRawIdWidget, self).render(name, value, attrs)
-    
+
     def url_parameters(self):
         return self.base_url_parameters()
-    
+
     def label_for_value(self, value):
         return ''
 
@@ -222,8 +222,7 @@
         rel_to = self.rel.to
         info = (rel_to._meta.app_label, rel_to._meta.object_name.lower())
         try:
-            related_info = (self.admin_site.name,) + info
-            related_url = reverse('%sadmin_%s_%s_add' % related_info)
+            related_url = reverse('admin:%s_%s_add' % info, 
current_app=self.admin_site.name)
         except NoReverseMatch:
             related_url = '../../../%s/%s/add/' % info
         self.widget.choices = self.choices

Modified: 
django/branches/soc2009/test-improvements/django/contrib/admindocs/templates/admin_doc/index.html
===================================================================
--- 
django/branches/soc2009/test-improvements/django/contrib/admindocs/templates/admin_doc/index.html
   2009-07-22 08:59:57 UTC (rev 11291)
+++ 
django/branches/soc2009/test-improvements/django/contrib/admindocs/templates/admin_doc/index.html
   2009-07-22 12:43:04 UTC (rev 11292)
@@ -1,6 +1,6 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> 
&rsaquo; Documentation</div>{% endblock %}
+{% block breadcrumbs %}<div class="breadcrumbs"><a href="{{ root_path 
}}">Home</a> &rsaquo; Documentation</div>{% endblock %}
 {% block title %}Documentation{% endblock %}
 
 {% block content %}

Modified: 
django/branches/soc2009/test-improvements/django/contrib/admindocs/views.py
===================================================================
--- django/branches/soc2009/test-improvements/django/contrib/admindocs/views.py 
2009-07-22 08:59:57 UTC (rev 11291)
+++ django/branches/soc2009/test-improvements/django/contrib/admindocs/views.py 
2009-07-22 12:43:04 UTC (rev 11292)
@@ -22,11 +22,14 @@
     name = 'my site'
 
 def get_root_path():
-    from django.contrib import admin
     try:
-        return urlresolvers.reverse(admin.site.root, args=[''])
+        return urlresolvers.reverse('admin:index')
     except urlresolvers.NoReverseMatch:
-        return getattr(settings, "ADMIN_SITE_ROOT_URL", "/admin/")
+        from django.contrib import admin
+        try:
+            return urlresolvers.reverse(admin.site.root, args=[''])
+        except urlresolvers.NoReverseMatch:
+            return getattr(settings, "ADMIN_SITE_ROOT_URL", "/admin/")
 
 def doc_index(request):
     if not utils.docutils_is_available:
@@ -179,7 +182,7 @@
 def model_detail(request, app_label, model_name):
     if not utils.docutils_is_available:
         return missing_docutils_page(request)
-        
+
     # Get the model class.
     try:
         app_mod = models.get_app(app_label)

Modified: 
django/branches/soc2009/test-improvements/django/contrib/gis/db/models/manager.py
===================================================================
--- 
django/branches/soc2009/test-improvements/django/contrib/gis/db/models/manager.py
   2009-07-22 08:59:57 UTC (rev 11291)
+++ 
django/branches/soc2009/test-improvements/django/contrib/gis/db/models/manager.py
   2009-07-22 12:43:04 UTC (rev 11292)
@@ -19,6 +19,9 @@
     def centroid(self, *args, **kwargs):
         return self.get_query_set().centroid(*args, **kwargs)
 
+    def collect(self, *args, **kwargs):
+        return self.get_query_set().collect(*args, **kwargs)
+
     def difference(self, *args, **kwargs):
         return self.get_query_set().difference(*args, **kwargs)
 

Modified: 
django/branches/soc2009/test-improvements/django/contrib/gis/db/models/sql/query.py
===================================================================
--- 
django/branches/soc2009/test-improvements/django/contrib/gis/db/models/sql/query.py
 2009-07-22 08:59:57 UTC (rev 11291)
+++ 
django/branches/soc2009/test-improvements/django/contrib/gis/db/models/sql/query.py
 2009-07-22 12:43:04 UTC (rev 11292)
@@ -13,7 +13,9 @@
 ALL_TERMS = sql.constants.QUERY_TERMS.copy()
 ALL_TERMS.update(SpatialBackend.gis_terms)
 
+# Pulling out other needed constants/routines to avoid attribute lookups.
 TABLE_NAME = sql.constants.TABLE_NAME
+get_proxied_model = sql.query.get_proxied_model
 
 class GeoQuery(sql.Query):
     """
@@ -153,7 +155,9 @@
             opts = self.model._meta
         aliases = set()
         only_load = self.deferred_to_columns()
-        proxied_model = opts.proxy and opts.proxy_for_model or 0
+        # Skip all proxy to the root proxied model
+        proxied_model = get_proxied_model(opts)
+
         if start_alias:
             seen = {None: start_alias}
         for field, model in opts.get_fields_with_model():
@@ -205,6 +209,10 @@
         """
         values = []
         aliases = self.extra_select.keys()
+        if self.aggregates:
+            # If we have an aggregate annotation, must extend the aliases
+            # so their corresponding row values are included.
+            aliases.extend([None for i in xrange(len(self.aggregates))])
 
         # Have to set a starting row number offset that is used for
         # determining the correct starting row index -- needed for

Modified: 
django/branches/soc2009/test-improvements/django/contrib/gis/tests/relatedapp/tests.py
===================================================================
--- 
django/branches/soc2009/test-improvements/django/contrib/gis/tests/relatedapp/tests.py
      2009-07-22 08:59:57 UTC (rev 11291)
+++ 
django/branches/soc2009/test-improvements/django/contrib/gis/tests/relatedapp/tests.py
      2009-07-22 12:43:04 UTC (rev 11292)
@@ -231,8 +231,12 @@
         q = pickle.loads(q_str)
         self.assertEqual(GeoQuery, q.__class__)
 
-    def test12_count(self):
-        "Testing `Count` aggregate use with the `GeoManager`. See #11087."
+    # TODO: fix on Oracle -- get the following error because the SQL is ordered
+    # by a geometry object, which Oracle apparently doesn't like:
+    #  ORA-22901: cannot compare nested table or VARRAY or LOB attributes of 
an object type
+    @no_oracle
+    def test12a_count(self):
+        "Testing `Count` aggregate use with the `GeoManager` on geo-fields."
         # Creating a new City, 'Fort Worth', that uses the same location
         # as Dallas.
         dallas = City.objects.get(name='Dallas')
@@ -242,6 +246,8 @@
         loc = 
Location.objects.annotate(num_cities=Count('city')).get(id=dallas.location.id)
         self.assertEqual(2, loc.num_cities)
 
+    def test12b_count(self):
+        "Testing `Count` aggregate use with the `GeoManager` on non 
geo-fields. See #11087."
         # Creating some data for the Book/Author non-geo models that
         # use GeoManager.  See #11087.
         tp = Author.objects.create(name='Trevor Paglen')
@@ -250,13 +256,19 @@
         Book.objects.create(title='Blank Spots on the Map', author=tp)
         wp = Author.objects.create(name='William Patry')
         Book.objects.create(title='Patry on Copyright', author=wp)
-        
+
         # Should only be one author (Trevor Paglen) returned by this query, and
-        # the annotation should have 3 for the number of books.
+        # the annotation should have 3 for the number of books.  Also testing
+        # with a `GeoValuesQuerySet` (see #11489).
         qs = 
Author.objects.annotate(num_books=Count('books')).filter(num_books__gt=1)
+        vqs = 
Author.objects.values('name').annotate(num_books=Count('books')).filter(num_books__gt=1)
         self.assertEqual(1, len(qs))
         self.assertEqual(3, qs[0].num_books)
+        self.assertEqual(1, len(vqs))
+        self.assertEqual(3, vqs[0]['num_books'])
 
+    # TODO: The phantom model does appear on Oracle.
+    @no_oracle
     def test13_select_related_null_fk(self):
         "Testing `select_related` on a nullable ForeignKey via `GeoManager`. 
See #11381."
         no_author = Book.objects.create(title='Without Author')

Modified: django/branches/soc2009/test-improvements/django/core/urlresolvers.py
===================================================================
--- django/branches/soc2009/test-improvements/django/core/urlresolvers.py       
2009-07-22 08:59:57 UTC (rev 11291)
+++ django/branches/soc2009/test-improvements/django/core/urlresolvers.py       
2009-07-22 12:43:04 UTC (rev 11292)
@@ -139,7 +139,7 @@
     callback = property(_get_callback)
 
 class RegexURLResolver(object):
-    def __init__(self, regex, urlconf_name, default_kwargs=None):
+    def __init__(self, regex, urlconf_name, default_kwargs=None, 
app_name=None, namespace=None):
         # regex is a string representing a regular expression.
         # urlconf_name is a string representing the module containing URLconfs.
         self.regex = re.compile(regex, re.UNICODE)
@@ -148,19 +148,29 @@
             self._urlconf_module = self.urlconf_name
         self.callback = None
         self.default_kwargs = default_kwargs or {}
-        self._reverse_dict = MultiValueDict()
+        self.namespace = namespace
+        self.app_name = app_name
+        self._reverse_dict = None
+        self._namespace_dict = None
+        self._app_dict = None
 
     def __repr__(self):
-        return '<%s %s %s>' % (self.__class__.__name__, self.urlconf_name, 
self.regex.pattern)
+        return '<%s %s (%s:%s) %s>' % (self.__class__.__name__, 
self.urlconf_name, self.app_name, self.namespace, self.regex.pattern)
 
-    def _get_reverse_dict(self):
-        if not self._reverse_dict:
-            lookups = MultiValueDict()
-            for pattern in reversed(self.url_patterns):
-                p_pattern = pattern.regex.pattern
-                if p_pattern.startswith('^'):
-                    p_pattern = p_pattern[1:]
-                if isinstance(pattern, RegexURLResolver):
+    def _populate(self):
+        lookups = MultiValueDict()
+        namespaces = {}
+        apps = {}
+        for pattern in reversed(self.url_patterns):
+            p_pattern = pattern.regex.pattern
+            if p_pattern.startswith('^'):
+                p_pattern = p_pattern[1:]
+            if isinstance(pattern, RegexURLResolver):
+                if pattern.namespace:
+                    namespaces[pattern.namespace] = (p_pattern, pattern)
+                    if pattern.app_name:
+                        apps.setdefault(pattern.app_name, 
[]).append(pattern.namespace)
+                else:
                     parent = normalize(pattern.regex.pattern)
                     for name in pattern.reverse_dict:
                         for matches, pat in pattern.reverse_dict.getlist(name):
@@ -168,14 +178,36 @@
                             for piece, p_args in parent:
                                 new_matches.extend([(piece + suffix, p_args + 
args) for (suffix, args) in matches])
                             lookups.appendlist(name, (new_matches, p_pattern + 
pat))
-                else:
-                    bits = normalize(p_pattern)
-                    lookups.appendlist(pattern.callback, (bits, p_pattern))
-                    lookups.appendlist(pattern.name, (bits, p_pattern))
-            self._reverse_dict = lookups
+                    for namespace, (prefix, sub_pattern) in 
pattern.namespace_dict.items():
+                        namespaces[namespace] = (p_pattern + prefix, 
sub_pattern)
+                    for app_name, namespace_list in pattern.app_dict.items():
+                        apps.setdefault(app_name, []).extend(namespace_list)
+            else:
+                bits = normalize(p_pattern)
+                lookups.appendlist(pattern.callback, (bits, p_pattern))
+                lookups.appendlist(pattern.name, (bits, p_pattern))
+        self._reverse_dict = lookups
+        self._namespace_dict = namespaces
+        self._app_dict = apps
+
+    def _get_reverse_dict(self):
+        if self._reverse_dict is None:
+            self._populate()
         return self._reverse_dict
     reverse_dict = property(_get_reverse_dict)
 
+    def _get_namespace_dict(self):
+        if self._namespace_dict is None:
+            self._populate()
+        return self._namespace_dict
+    namespace_dict = property(_get_namespace_dict)
+
+    def _get_app_dict(self):
+        if self._app_dict is None:
+            self._populate()
+        return self._app_dict
+    app_dict = property(_get_app_dict)
+
     def resolve(self, path):
         tried = []
         match = self.regex.search(path)
@@ -261,12 +293,51 @@
 def resolve(path, urlconf=None):
     return get_resolver(urlconf).resolve(path)
 
-def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None):
+def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, 
current_app=None):
+    resolver = get_resolver(urlconf)
     args = args or []
     kwargs = kwargs or {}
+
     if prefix is None:
         prefix = get_script_prefix()
-    return iri_to_uri(u'%s%s' % (prefix, 
get_resolver(urlconf).reverse(viewname,
+
+    if not isinstance(viewname, basestring):
+        view = viewname
+    else:
+        parts = viewname.split(':')
+        parts.reverse()
+        view = parts[0]
+        path = parts[1:]
+
+        resolved_path = []
+        while path:
+            ns = path.pop()
+
+            # Lookup the name to see if it could be an app identifier
+            try:
+                app_list = resolver.app_dict[ns]
+                # Yes! Path part matches an app in the current Resolver
+                if current_app and current_app in app_list:
+                    # If we are reversing for a particular app, use that 
namespace
+                    ns = current_app
+                elif ns not in app_list:
+                    # The name isn't shared by one of the instances (i.e., the 
default)
+                    # so just pick the first instance as the default.
+                    ns = app_list[0]
+            except KeyError:
+                pass
+
+            try:
+                extra, resolver = resolver.namespace_dict[ns]
+                resolved_path.append(ns)
+                prefix = prefix + extra
+            except KeyError, key:
+                if resolved_path:
+                    raise NoReverseMatch("%s is not a registered namespace 
inside '%s'" % (key, ':'.join(resolved_path)))
+                else:
+                    raise NoReverseMatch("%s is not a registered namespace" % 
key)
+
+    return iri_to_uri(u'%s%s' % (prefix, resolver.reverse(view,
             *args, **kwargs)))
 
 def clear_url_caches():

Modified: django/branches/soc2009/test-improvements/django/template/context.py
===================================================================
--- django/branches/soc2009/test-improvements/django/template/context.py        
2009-07-22 08:59:57 UTC (rev 11291)
+++ django/branches/soc2009/test-improvements/django/template/context.py        
2009-07-22 12:43:04 UTC (rev 11292)
@@ -9,10 +9,11 @@
 
 class Context(object):
     "A stack container for variable context"
-    def __init__(self, dict_=None, autoescape=True):
+    def __init__(self, dict_=None, autoescape=True, current_app=None):
         dict_ = dict_ or {}
         self.dicts = [dict_]
         self.autoescape = autoescape
+        self.current_app = current_app
 
     def __repr__(self):
         return repr(self.dicts)
@@ -96,8 +97,8 @@
     Additional processors can be specified as a list of callables
     using the "processors" keyword argument.
     """
-    def __init__(self, request, dict=None, processors=None):
-        Context.__init__(self, dict)
+    def __init__(self, request, dict=None, processors=None, current_app=None):
+        Context.__init__(self, dict, current_app=current_app)
         if processors is None:
             processors = ()
         else:

Modified: 
django/branches/soc2009/test-improvements/django/template/defaulttags.py
===================================================================
--- django/branches/soc2009/test-improvements/django/template/defaulttags.py    
2009-07-22 08:59:57 UTC (rev 11291)
+++ django/branches/soc2009/test-improvements/django/template/defaulttags.py    
2009-07-22 12:43:04 UTC (rev 11292)
@@ -367,17 +367,17 @@
         # {% url ... as var %} construct in which cause return nothing.
         url = ''
         try:
-            url = reverse(self.view_name, args=args, kwargs=kwargs)
+            url = reverse(self.view_name, args=args, kwargs=kwargs, 
current_app=context.current_app)
         except NoReverseMatch, e:
             if settings.SETTINGS_MODULE:
                 project_name = settings.SETTINGS_MODULE.split('.')[0]
                 try:
                     url = reverse(project_name + '.' + self.view_name,
-                              args=args, kwargs=kwargs)
+                              args=args, kwargs=kwargs, 
current_app=context.current_app)
                 except NoReverseMatch:
                     if self.asvar is None:
                         # Re-raise the original exception, not the one with
-                        # the path relative to the project. This makes a 
+                        # the path relative to the project. This makes a
                         # better error message.
                         raise e
             else:

Modified: 
django/branches/soc2009/test-improvements/docs/howto/deployment/modwsgi.txt
===================================================================
--- django/branches/soc2009/test-improvements/docs/howto/deployment/modwsgi.txt 
2009-07-22 08:59:57 UTC (rev 11291)
+++ django/branches/soc2009/test-improvements/docs/howto/deployment/modwsgi.txt 
2009-07-22 12:43:04 UTC (rev 11292)
@@ -1,69 +1,118 @@
-.. _howto-deployment-modwsgi:
-
-==========================================
-How to use Django with Apache and mod_wsgi
-==========================================
-
-Deploying Django with Apache_ and `mod_wsgi`_ is the recommended way to get
-Django into production.
-
-.. _Apache: http://httpd.apache.org/
-.. _mod_wsgi: http://code.google.com/p/modwsgi/
-
-mod_wsgi is an Apache module which can be used to host any Python application
-which supports the `Python WSGI interface`_, including Django. Django will work
-with any version of Apache which supports mod_wsgi.
-
-.. _python wsgi interface: http://www.python.org/dev/peps/pep-0333/
-
-The `official mod_wsgi documentation`_ is fantastic; it's your source for all
-the details about how to use mod_wsgi. You'll probably want to start with the
-`installation and configuration documentation`_.
-
-.. _official mod_wsgi documentation: http://code.google.com/p/modwsgi/
-.. _installation and configuration documentation: 
http://code.google.com/p/modwsgi/wiki/InstallationInstructions
-
-Basic Configuration
-===================
-
-Once you've got mod_wsgi installed and activated, edit your ``httpd.conf`` file
-and add::
-
-    WSGIScriptAlias / /path/to/mysite/apache/django.wsgi
-
-The first bit above is the url you want to be serving your application at 
(``/``
-indicates the root url), and the second is the location of a "WSGI file" -- see
-below -- on your system, usually inside of your project. This tells Apache
-to serve any request below the given URL using the WSGI application defined by 
that file.
-
-Next we'll need to actually create this WSGI application, so create the file
-mentioned in the second part of ``WSGIScriptAlias`` and add::
-
-    import os
-    import sys
-
-    os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
-
-    import django.core.handlers.wsgi
-    application = django.core.handlers.wsgi.WSGIHandler()
-
-If your project is not on your ``PYTHONPATH`` by default you can add::
-
-    sys.path.append('/usr/local/django')
-
-just above the final ``import`` line to place your project on the path. 
Remember to
-replace 'mysite.settings' with your correct settings file, and 
'/usr/local/django'
-with your own project's location.
-
-See the :ref:`Apache/mod_python documentation<howto-deployment-modpython>` for 
-directions on serving static media, and the `mod_wsgi documentation`_ for an 
-explanation of other directives and configuration options you can use.
-
-Details
-=======
-
-For more details, see the `mod_wsgi documentation`_, which explains the above 
in
-more detail, and walks through all the various options you've got when 
deploying
-under mod_wsgi.
-
-.. _mod_wsgi documentation: 
http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango
+.. _howto-deployment-modwsgi:
+
+==========================================
+How to use Django with Apache and mod_wsgi
+==========================================
+
+Deploying Django with Apache_ and `mod_wsgi`_ is the recommended way to get
+Django into production.
+
+.. _Apache: http://httpd.apache.org/
+.. _mod_wsgi: http://code.google.com/p/modwsgi/
+
+mod_wsgi is an Apache module which can be used to host any Python application
+which supports the `Python WSGI interface`_, including Django. Django will work
+with any version of Apache which supports mod_wsgi.
+
+.. _python wsgi interface: http://www.python.org/dev/peps/pep-0333/
+
+The `official mod_wsgi documentation`_ is fantastic; it's your source for all
+the details about how to use mod_wsgi. You'll probably want to start with the
+`installation and configuration documentation`_.
+
+.. _official mod_wsgi documentation: http://code.google.com/p/modwsgi/
+.. _installation and configuration documentation: 
http://code.google.com/p/modwsgi/wiki/InstallationInstructions
+
+Basic Configuration
+===================
+
+Once you've got mod_wsgi installed and activated, edit your ``httpd.conf`` file
+and add::
+
+    WSGIScriptAlias / /path/to/mysite/apache/django.wsgi
+
+The first bit above is the url you want to be serving your application at 
(``/``
+indicates the root url), and the second is the location of a "WSGI file" -- see
+below -- on your system, usually inside of your project. This tells Apache
+to serve any request below the given URL using the WSGI application defined by 
that file.
+
+Next we'll need to actually create this WSGI application, so create the file
+mentioned in the second part of ``WSGIScriptAlias`` and add::
+
+    import os
+    import sys
+
+    os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
+
+    import django.core.handlers.wsgi
+    application = django.core.handlers.wsgi.WSGIHandler()
+
+If your project is not on your ``PYTHONPATH`` by default you can add::
+
+    sys.path.append('/usr/local/django')
+
+just above the final ``import`` line to place your project on the path. 
Remember to
+replace 'mysite.settings' with your correct settings file, and 
'/usr/local/django'
+with your own project's location.
+
+Serving media files
+===================
+
+Django doesn't serve media files itself; it leaves that job to whichever Web
+server you choose.
+
+We recommend using a separate Web server -- i.e., one that's not also running
+Django -- for serving media. Here are some good choices:
+
+    * lighttpd_
+    * Nginx_
+    * TUX_
+    * A stripped-down version of Apache_
+    * Cherokee_
+
+If, however, you have no option but to serve media files on the same Apache
+``VirtualHost`` as Django, you can set up Apache to serve some URLs as
+static media, and others using the mod_wsgi interface to Django.
+
+This example sets up Django at the site root, but explicitly serves 
``robots.txt``,
+``favicon.ico``, any CSS file, and anything in the ``/media/`` URL space as a 
static
+file. All other URLs will be served using mod_wsgi::
+
+    Alias /robots.txt /usr/local/wsgi/static/robots.txt
+    Alias /favicon.ico /usr/local/wsgi/static/favicon.ico
+
+    AliasMatch /([^/]*\.css) /usr/local/wsgi/static/styles/$1
+
+    Alias /media/ /usr/local/wsgi/static/media/
+
+    <Directory /usr/local/wsgi/static>
+    Order deny,allow
+    Allow from all
+    </Directory>
+
+    WSGIScriptAlias / /usr/local/wsgi/scripts/django.wsgi
+
+    <Directory /usr/local/wsgi/scripts>
+    Order allow,deny
+    Allow from all
+    </Directory>
+
+.. _lighttpd: http://www.lighttpd.net/
+.. _Nginx: http://wiki.codemongers.com/Main
+.. _TUX: http://en.wikipedia.org/wiki/TUX_web_server
+.. _Apache: http://httpd.apache.org/
+.. _Cherokee: http://www.cherokee-project.com/
+
+More details on configuring a mod_wsgi site to serve static files can be found
+in the mod_wsgi documentation on `hosting static files`_.
+
+.. _hosting static files: 
http://code.google.com/p/modwsgi/wiki/ConfigurationGuidelines#Hosting_Of_Static_Files
+
+Details
+=======
+
+For more details, see the `mod_wsgi documentation on Django integration`_,
+which explains the above in more detail, and walks through all the various
+options you've got when deploying under mod_wsgi.
+
+.. _mod_wsgi documentation on Django integration: 
http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango

Modified: django/branches/soc2009/test-improvements/docs/intro/tutorial03.txt
===================================================================
--- django/branches/soc2009/test-improvements/docs/intro/tutorial03.txt 
2009-07-22 08:59:57 UTC (rev 11291)
+++ django/branches/soc2009/test-improvements/docs/intro/tutorial03.txt 
2009-07-22 12:43:04 UTC (rev 11292)
@@ -365,7 +365,7 @@
 in ``django/conf/urls/defaults.py``, ``handler404`` is set to
 :func:`django.views.defaults.page_not_found` by default.
 
-Three more things to note about 404 views:
+Four more things to note about 404 views:
 
     * If :setting:`DEBUG` is set to ``True`` (in your settings module) then 
your
       404 view will never be used (and thus the ``404.html`` template will 
never

Modified: 
django/branches/soc2009/test-improvements/docs/ref/contrib/admin/_images/article_actions.png
===================================================================
--- 
django/branches/soc2009/test-improvements/docs/ref/contrib/admin/_images/article_actions.png
        2009-07-22 08:59:57 UTC (rev 11291)
+++ 
django/branches/soc2009/test-improvements/docs/ref/contrib/admin/_images/article_actions.png
        2009-07-22 12:43:04 UTC (rev 11292)
@@ -1,218 +1,124 @@
 ‰PNG
  
 
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-updates@googlegroups.com
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to