diff options
| -rw-r--r-- | AUTHORS | 2 | ||||
| -rw-r--r-- | django/conf/locale/ru/LC_MESSAGES/django.mo | bin | 31822 -> 31773 bytes | |||
| -rw-r--r-- | django/conf/locale/ru/LC_MESSAGES/django.po | 3 | ||||
| -rw-r--r-- | django/conf/urls/defaults.py | 8 | ||||
| -rw-r--r-- | django/contrib/admin/media/js/admin/DateTimeShortcuts.js | 66 | ||||
| -rw-r--r-- | django/contrib/admin/media/js/admin/RelatedObjectLookups.js | 2 | ||||
| -rw-r--r-- | django/contrib/admin/templates/admin/auth/user/add_form.html | 28 | ||||
| -rw-r--r-- | django/contrib/admin/urls.py | 3 | ||||
| -rw-r--r-- | django/contrib/admin/views/auth.py | 39 | ||||
| -rw-r--r-- | django/contrib/auth/forms.py | 22 | ||||
| -rw-r--r-- | django/core/management.py | 6 | ||||
| -rw-r--r-- | django/core/urlresolvers.py | 6 | ||||
| -rw-r--r-- | django/db/backends/ansi/sql.py | 7 | ||||
| -rw-r--r-- | django/db/models/fields/__init__.py | 7 | ||||
| -rw-r--r-- | django/db/models/fields/related.py | 2 | ||||
| -rw-r--r-- | django/middleware/gzip.py | 6 | ||||
| -rw-r--r-- | docs/add_ons.txt | 7 | ||||
| -rw-r--r-- | docs/db-api.txt | 3 | ||||
| -rw-r--r-- | docs/faq.txt | 9 | ||||
| -rw-r--r-- | docs/url_dispatch.txt | 52 |
20 files changed, 227 insertions, 51 deletions
@@ -70,6 +70,8 @@ answer newbie questions, and generally made Django that much better: Clint Ecker gandalf@owca.info Baishampayan Ghose + martin.glueck@gmail.com + Simon Greenhill <dev@simon.net.nz> Espen Grindhaug <http://grindhaug.org/> Brant Harris hipertracker@gmail.com diff --git a/django/conf/locale/ru/LC_MESSAGES/django.mo b/django/conf/locale/ru/LC_MESSAGES/django.mo Binary files differindex 562996eee5..d45691bd30 100644 --- a/django/conf/locale/ru/LC_MESSAGES/django.mo +++ b/django/conf/locale/ru/LC_MESSAGES/django.mo diff --git a/django/conf/locale/ru/LC_MESSAGES/django.po b/django/conf/locale/ru/LC_MESSAGES/django.po index 024b2bfc12..4e5ff239f8 100644 --- a/django/conf/locale/ru/LC_MESSAGES/django.po +++ b/django/conf/locale/ru/LC_MESSAGES/django.po @@ -141,6 +141,7 @@ msgid "score date" msgstr "счёт времени" #: contrib/comments/models.py:237 +#, fuzzy msgid "karma score" msgstr "Карма счёт" @@ -735,7 +736,7 @@ msgstr "К сожалению, запрашиваемая вами страни #: contrib/admin/templates/admin/index.html:17 #, python-format msgid "Models available in the %(name)s application." -msgstr "Модели доступны в %(name)s приложении." +msgstr "Модели доступны в %(name) приложении." #: contrib/admin/templates/admin/index.html:28 #: contrib/admin/templates/admin/change_form.html:15 diff --git a/django/conf/urls/defaults.py b/django/conf/urls/defaults.py index 07611c5147..17fe603d96 100644 --- a/django/conf/urls/defaults.py +++ b/django/conf/urls/defaults.py @@ -10,8 +10,10 @@ include = lambda urlconf_module: [urlconf_module] def patterns(prefix, *tuples): pattern_list = [] for t in tuples: - if type(t[1]) == list: - pattern_list.append(RegexURLResolver(t[0], t[1][0])) + regex, view_or_include = t[:2] + default_kwargs = t[2:] + if type(view_or_include) == list: + pattern_list.append(RegexURLResolver(regex, view_or_include[0], *default_kwargs)) else: - pattern_list.append(RegexURLPattern(t[0], prefix and (prefix + '.' + t[1]) or t[1], *t[2:])) + pattern_list.append(RegexURLPattern(regex, prefix and (prefix + '.' + view_or_include) or view_or_include, *default_kwargs)) return pattern_list diff --git a/django/contrib/admin/media/js/admin/DateTimeShortcuts.js b/django/contrib/admin/media/js/admin/DateTimeShortcuts.js index 35199baf84..3f6fb67bc7 100644 --- a/django/contrib/admin/media/js/admin/DateTimeShortcuts.js +++ b/django/contrib/admin/media/js/admin/DateTimeShortcuts.js @@ -8,7 +8,9 @@ var DateTimeShortcuts = { clockInputs: [], calendarDivName1: 'calendarbox', // name of calendar <div> that gets toggled calendarDivName2: 'calendarin', // name of <div> that contains calendar + calendarLinkName: 'calendarlink',// name of the link that is used to toggle clockDivName: 'clockbox', // name of clock <div> that gets toggled + clockLinkName: 'clocklink', // name of the link that is used to toggle admin_media_prefix: '', init: function() { // Deduce admin_media_prefix by looking at the <script>s in the @@ -46,6 +48,7 @@ var DateTimeShortcuts = { now_link.appendChild(document.createTextNode(gettext('Now'))); var clock_link = document.createElement('a'); clock_link.setAttribute('href', 'javascript:DateTimeShortcuts.openClock(' + num + ');'); + clock_link.id = DateTimeShortcuts.clockLinkName + num; quickElement('img', clock_link, '', 'src', DateTimeShortcuts.admin_media_prefix + 'img/admin/icon_clock.gif', 'alt', gettext('Clock')); shortcuts_span.appendChild(document.createTextNode('\240')); shortcuts_span.appendChild(now_link); @@ -69,17 +72,6 @@ var DateTimeShortcuts = { var clock_box = document.createElement('div'); clock_box.style.display = 'none'; clock_box.style.position = 'absolute'; - if (getStyle(document.body,'direction')!='rtl') { - clock_box.style.left = findPosX(clock_link) + 17 + 'px'; - } - else { - // since style's width is in em, it'd be tough to calculate - // px value of it. let's use an estimated px for now - // TODO: IE returns wrong value for findPosX when in rtl mode - // (it returns as it was left aligned), needs to be fixed. - clock_box.style.left = findPosX(clock_link) - 110 + 'px'; - } - clock_box.style.top = findPosY(clock_link) - 30 + 'px'; clock_box.className = 'clockbox module'; clock_box.setAttribute('id', DateTimeShortcuts.clockDivName + num); document.body.appendChild(clock_box); @@ -98,7 +90,25 @@ var DateTimeShortcuts = { quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissClock(' + num + ');'); }, openClock: function(num) { - document.getElementById(DateTimeShortcuts.clockDivName + num).style.display = 'block'; + var clock_box = document.getElementById(DateTimeShortcuts.clockDivName+num) + var clock_link = document.getElementById(DateTimeShortcuts.clockLinkName+num) + + // Recalculate the clockbox position + // is it left-to-right or right-to-left layout ? + if (getStyle(document.body,'direction')!='rtl') { + clock_box.style.left = findPosX(clock_link) + 17 + 'px'; + } + else { + // since style's width is in em, it'd be tough to calculate + // px value of it. let's use an estimated px for now + // TODO: IE returns wrong value for findPosX when in rtl mode + // (it returns as it was left aligned), needs to be fixed. + clock_box.style.left = findPosX(clock_link) - 110 + 'px'; + } + clock_box.style.top = findPosY(clock_link) - 30 + 'px'; + + // Show the clock box + clock_box.style.display = 'block'; addEvent(window, 'click', function() { DateTimeShortcuts.dismissClock(num); return true; }); }, dismissClock: function(num) { @@ -123,6 +133,7 @@ var DateTimeShortcuts = { today_link.appendChild(document.createTextNode(gettext('Today'))); var cal_link = document.createElement('a'); cal_link.setAttribute('href', 'javascript:DateTimeShortcuts.openCalendar(' + num + ');'); + cal_link.id = DateTimeShortcuts.calendarLinkName + num; quickElement('img', cal_link, '', 'src', DateTimeShortcuts.admin_media_prefix + 'img/admin/icon_calendar.gif', 'alt', gettext('Calendar')); shortcuts_span.appendChild(document.createTextNode('\240')); shortcuts_span.appendChild(today_link); @@ -149,18 +160,6 @@ var DateTimeShortcuts = { var cal_box = document.createElement('div'); cal_box.style.display = 'none'; cal_box.style.position = 'absolute'; - // is it left-to-right or right-to-left layout ? - if (getStyle(document.body,'direction')!='rtl') { - cal_box.style.left = findPosX(cal_link) + 17 + 'px'; - } - else { - // since style's width is in em, it'd be tough to calculate - // px value of it. let's use an estimated px for now - // TODO: IE returns wrong value for findPosX when in rtl mode - // (it returns as it was left aligned), needs to be fixed. - cal_box.style.left = findPosX(cal_link) - 180 + 'px'; - } - cal_box.style.top = findPosY(cal_link) - 75 + 'px'; cal_box.className = 'calendarbox module'; cal_box.setAttribute('id', DateTimeShortcuts.calendarDivName1 + num); document.body.appendChild(cal_box); @@ -195,7 +194,24 @@ var DateTimeShortcuts = { quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissCalendar(' + num + ');'); }, openCalendar: function(num) { - document.getElementById(DateTimeShortcuts.calendarDivName1+num).style.display = 'block'; + var cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1+num) + var cal_link = document.getElementById(DateTimeShortcuts.calendarLinkName+num) + + // Recalculate the clockbox position + // is it left-to-right or right-to-left layout ? + if (getStyle(document.body,'direction')!='rtl') { + cal_box.style.left = findPosX(cal_link) + 17 + 'px'; + } + else { + // since style's width is in em, it'd be tough to calculate + // px value of it. let's use an estimated px for now + // TODO: IE returns wrong value for findPosX when in rtl mode + // (it returns as it was left aligned), needs to be fixed. + cal_box.style.left = findPosX(cal_link) - 180 + 'px'; + } + cal_box.style.top = findPosY(cal_link) - 75 + 'px'; + + cal_box.style.display = 'block'; addEvent(window, 'click', function() { DateTimeShortcuts.dismissCalendar(num); return true; }); }, dismissCalendar: function(num) { diff --git a/django/contrib/admin/media/js/admin/RelatedObjectLookups.js b/django/contrib/admin/media/js/admin/RelatedObjectLookups.js index cf57fc4dfb..db4ed1a9d1 100644 --- a/django/contrib/admin/media/js/admin/RelatedObjectLookups.js +++ b/django/contrib/admin/media/js/admin/RelatedObjectLookups.js @@ -11,7 +11,7 @@ function showRelatedObjectLookupPopup(triggeringLink) { } else { href = triggeringLink.href + '?pop=1'; } - var win = window.open(href, name, 'height=500,width=740,resizable=yes,scrollbars=yes'); + var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes'); win.focus(); return false; } diff --git a/django/contrib/admin/templates/admin/auth/user/add_form.html b/django/contrib/admin/templates/admin/auth/user/add_form.html new file mode 100644 index 0000000000..139fa6a75e --- /dev/null +++ b/django/contrib/admin/templates/admin/auth/user/add_form.html @@ -0,0 +1,28 @@ +{% extends "admin/change_form.html" %} +{% load i18n %} + +{% block after_field_sets %} + +<p>{% trans "First, enter a username and password. Then, you'll be able to edit more user options." %}</p> + +<fieldset class="module aligned"> + +<div class="form-row"> + {{ form.username.html_error_list }} + <label for="id_username" class="required">{% trans 'Username' %}:</label> {{ form.username }} + <p class="help">{{ username_help_text }}</p> +</div> + +<div class="form-row"> + {{ form.password1.html_error_list }} + <label for="id_password1" class="required">{% trans 'Password' %}:</label> {{ form.password1 }} +</div> + +<div class="form-row"> + {{ form.password2.html_error_list }} + <label for="id_password2" class="required">{% trans 'Password (again)' %}:</label> {{ form.password2 }} + <p class="help">{% trans 'Enter the same password as above, for verification.' %}</p> +</div> + +</fieldset> +{% endblock %} diff --git a/django/contrib/admin/urls.py b/django/contrib/admin/urls.py index bd894d8de1..88cf8306a3 100644 --- a/django/contrib/admin/urls.py +++ b/django/contrib/admin/urls.py @@ -28,6 +28,9 @@ urlpatterns = patterns('', # ('^doc/templates/$', 'django.views.admin.doc.template_index'), ('^doc/templates/(?P<template>.*)/$', 'django.contrib.admin.views.doc.template_detail'), + # "Add user" -- a special-case view + ('^auth/user/add/$', 'django.contrib.admin.views.auth.user_add_stage'), + # Add/change/delete/history ('^([^/]+)/([^/]+)/$', 'django.contrib.admin.views.main.change_list'), ('^([^/]+)/([^/]+)/add/$', 'django.contrib.admin.views.main.add_stage'), diff --git a/django/contrib/admin/views/auth.py b/django/contrib/admin/views/auth.py new file mode 100644 index 0000000000..d09075c2a1 --- /dev/null +++ b/django/contrib/admin/views/auth.py @@ -0,0 +1,39 @@ +from django.contrib.auth.forms import UserCreationForm +from django.contrib.auth.models import User +from django import forms, template +from django.shortcuts import render_to_response +from django.http import HttpResponseRedirect + +def user_add_stage(request): + manipulator = UserCreationForm() + if request.method == 'POST': + new_data = request.POST.copy() + errors = manipulator.get_validation_errors(new_data) + if not errors: + new_user = manipulator.save(new_data) + msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': 'user', 'obj': new_user} + if request.POST.has_key("_addanother"): + request.user.message_set.create(message=msg) + return HttpResponseRedirect(request.path) + else: + request.user.message_set.create(message=msg + ' ' + _("You may edit it again below.")) + return HttpResponseRedirect('../%s/' % new_user.id) + else: + errors = new_data = {} + form = forms.FormWrapper(manipulator, new_data, errors) + return render_to_response('admin/auth/user/add_form.html', { + 'title': _('Add user'), + 'form': form, + 'is_popup': request.REQUEST.has_key('_popup'), + 'add': True, + 'change': False, + 'has_delete_permission': False, + 'has_change_permission': True, + 'has_file_field': False, + 'has_absolute_url': False, + 'auto_populated_fields': (), + 'bound_field_sets': (), + 'first_form_field_id': 'id_username', + 'opts': User._meta, + 'username_help_text': User._meta.get_field('username').help_text, + }, context_instance=template.RequestContext(request)) diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py index 8bd9fa44c4..ad8d423ebf 100644 --- a/django/contrib/auth/forms.py +++ b/django/contrib/auth/forms.py @@ -5,6 +5,28 @@ from django.template import Context, loader from django.core import validators from django import forms +class UserCreationForm(forms.Manipulator): + "A form that creates a user, with no privileges, from the given username and password." + def __init__(self): + self.fields = ( + forms.TextField(field_name='username', length=30, maxlength=30, is_required=True, + validator_list=[validators.isAlphaNumeric, self.isValidUsername]), + forms.PasswordField(field_name='password1', length=30, maxlength=60, is_required=True), + forms.PasswordField(field_name='password2', length=30, maxlength=60, is_required=True, + validator_list=[validators.AlwaysMatchesOtherField('password1', "The two password fields didn't match.")]), + ) + + def isValidUsername(self, field_data, all_data): + try: + User.objects.get(username=field_data) + except User.DoesNotExist: + return + raise validators.ValidationError, 'A user with that username already exists.' + + def save(self, new_data): + "Creates the user." + return User.objects.create_user(new_data['username'], '', new_data['password1']) + class AuthenticationForm(forms.Manipulator): """ Base class for authenticating users. Extend this to get a form that accepts diff --git a/django/core/management.py b/django/core/management.py index a653196679..c910c15589 100644 --- a/django/core/management.py +++ b/django/core/management.py @@ -829,6 +829,12 @@ def get_validation_errors(outfile, app=None): f = opts.get_field(fn) except models.FieldDoesNotExist: e.add(opts, '"admin.list_filter" refers to %r, which isn\'t a field.' % fn) + # date_hierarchy + if opts.admin.date_hierarchy: + try: + f = opts.get_field(opts.admin.date_hierarchy) + except models.FieldDoesNotExist: + e.add(opts, '"admin.date_hierarchy" refers to %r, which isn\'t a field.' % opts.admin.date_hierarchy) # Check ordering attribute. if opts.ordering: diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py index f4817dd4c9..1da25c9f83 100644 --- a/django/core/urlresolvers.py +++ b/django/core/urlresolvers.py @@ -130,12 +130,13 @@ class RegexURLPattern(object): return reverse_helper(self.regex, *args, **kwargs) class RegexURLResolver(object): - def __init__(self, regex, urlconf_name): + def __init__(self, regex, urlconf_name, default_kwargs=None): # regex is a string representing a regular expression. # urlconf_name is a string representing the module containing urlconfs. self.regex = re.compile(regex) self.urlconf_name = urlconf_name self.callback = None + self.default_kwargs = default_kwargs or {} def resolve(self, path): tried = [] @@ -149,7 +150,8 @@ class RegexURLResolver(object): tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0]['tried']]) else: if sub_match: - return sub_match[0], sub_match[1], dict(match.groupdict(), **sub_match[2]) + sub_match_dict = dict(self.default_kwargs, **sub_match[2]) + return sub_match[0], sub_match[1], dict(match.groupdict(), **sub_match_dict) tried.append(pattern.regex.pattern) raise Resolver404, {'tried': tried, 'path': new_path} diff --git a/django/db/backends/ansi/sql.py b/django/db/backends/ansi/sql.py index f0d7f84562..70928d3560 100644 --- a/django/db/backends/ansi/sql.py +++ b/django/db/backends/ansi/sql.py @@ -137,9 +137,12 @@ class SchemaBuilder(object): r_col = f.column table = opts.db_table col = opts.get_field(f.rel.field_name).column + # For MySQL, r_name must be unique in the first 64 + # characters. So we are careful with character usage here. + r_name = '%s_refs_%s_%x' % (r_col, col, + abs(hash((r_table, table)))) sql = style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s);' % \ - (quote_name(table), - quote_name('%s_referencing_%s_%s' % (r_col, r_table, col)), + (quote_name(table), quote_name(r_name), quote_name(r_col), quote_name(r_table), quote_name(col)) pending.setdefault(rel_class, []).append( BoundStatement(sql, db.connection)) diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 952ab17ecc..35c0f375a1 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -289,8 +289,11 @@ class Field(object): if self.choices: return first_choice + list(self.choices) rel_model = self.rel.to - return first_choice + [(x._get_pk_val(), str(x)) - for x in rel_model._default_manager.complex_filter(self.rel.limit_choices_to)] + if hasattr(self.rel, 'get_related_field'): + lst = [(getattr(x, self.rel.get_related_field().attname), str(x)) for x in rel_model._default_manager.complex_filter(self.rel.limit_choices_to)] + else: + lst = [(x._get_pk_val(), str(x)) for x in rel_model._default_manager.complex_filter(self.rel.limit_choices_to)] + return first_choice + lst def get_choices_default(self): if self.radio_admin: diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index c32aa8c0d4..6276c55f69 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -25,7 +25,7 @@ def add_lookup(rel_cls, field): key = (module, name) # Has the model already been loaded? # If so, resolve the string reference right away - model = get_model(rel_cls._meta.app_label,field.rel.to) + model = get_model(rel_cls._meta.app_label, field.rel.to, False) if model: field.rel.to = model field.do_related_class(model, rel_cls) diff --git a/django/middleware/gzip.py b/django/middleware/gzip.py index cc8a68406c..7d860abdb1 100644 --- a/django/middleware/gzip.py +++ b/django/middleware/gzip.py @@ -12,7 +12,11 @@ class GZipMiddleware(object): """ def process_response(self, request, response): patch_vary_headers(response, ('Accept-Encoding',)) - if response.has_header('Content-Encoding'): + + # Avoid gzipping if we've already got a content-encoding or if the + # content-type is Javascript (silly IE...) + is_js = "javascript" in response.headers.get('Content-Type', '').lower() + if response.has_header('Content-Encoding') or is_js: return response ae = request.META.get('HTTP_ACCEPT_ENCODING', '') diff --git a/docs/add_ons.txt b/docs/add_ons.txt index 90c98b7176..6507f3b139 100644 --- a/docs/add_ons.txt +++ b/docs/add_ons.txt @@ -2,12 +2,15 @@ The "contrib" add-ons ===================== -Django aims to follow Python's "batteries included" philosophy. It ships with a -variety of extra, optional tools that solve common Web-development problems. +Django aims to follow Python's `"batteries included" philosophy`_. It ships +with a variety of extra, optional tools that solve common Web-development +problems. This code lives in ``django/contrib`` in the Django distribution. Here's a rundown of the packages in ``contrib``: +.. _"batteries included" philosophy: http://docs.python.org/tut/node12.html#batteries-included + admin ===== diff --git a/docs/db-api.txt b/docs/db-api.txt index ce6bb0ab3b..a7cf30813d 100644 --- a/docs/db-api.txt +++ b/docs/db-api.txt @@ -578,6 +578,9 @@ related ``Person`` *and* the related ``City``:: p = b.author # Hits the database. c = p.hometown # Hits the database. +Note that ``select_related()`` does not follow foreign keys that have +``null=True``. + ``extra(select=None, where=None, params=None, tables=None)`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/faq.txt b/docs/faq.txt index 36fb547cf1..3cd7090583 100644 --- a/docs/faq.txt +++ b/docs/faq.txt @@ -620,13 +620,10 @@ like to make should be possible by editing the stylesheet. We've got a How do I create users without having to edit password hashes? ------------------------------------------------------------- -We don't recommend you create users via the admin interface, because at the -moment it requires you to edit password hashes manually. (Passwords are hashed -using one-way hash algorithms for security; there's currently no Web interface -for changing passwords by entering the actual password rather than the hash.) +If you'd like to use the admin site to create users, upgrade to the Django +development version, where this problem was fixed on Aug. 4, 2006. -To create a user, you'll have to use the Python API. See `creating users`_ for -full info. +You can also use the Python API. See `creating users`_ for full info. .. _creating users: http://www.djangoproject.com/documentation/authentication/#creating-users diff --git a/docs/url_dispatch.txt b/docs/url_dispatch.txt index 498a906d5e..6158014fc8 100644 --- a/docs/url_dispatch.txt +++ b/docs/url_dispatch.txt @@ -263,12 +263,12 @@ Here's the example URLconf from the `Django overview`_:: from django.conf.urls.defaults import * urlpatterns = patterns('', - (r'^articles/(\d{4})/$', 'myproject.news.views.year_archive'), - (r'^articles/(\d{4})/(\d{2})/$', 'myproject.news.views.month_archive'), - (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'myproject.news.views.article_detail'), + (r'^articles/(\d{4})/$', 'mysite.news.views.year_archive'), + (r'^articles/(\d{4})/(\d{2})/$', 'mysite.news.views.month_archive'), + (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'mysite.news.views.article_detail'), ) -In this example, each view has a common prefix -- ``'myproject.news.views'``. +In this example, each view has a common prefix -- ``'mysite.news.views'``. Instead of typing that out for each entry in ``urlpatterns``, you can use the first argument to the ``patterns()`` function to specify a prefix to apply to each view function. @@ -277,7 +277,7 @@ With this in mind, the above example can be written more concisely as:: from django.conf.urls.defaults import * - urlpatterns = patterns('myproject.news.views', + urlpatterns = patterns('mysite.news.views', (r'^articles/(\d{4})/$', 'year_archive'), (r'^articles/(\d{4})/(\d{2})/$', 'month_archive'), (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'article_detail'), @@ -389,3 +389,45 @@ to pass metadata and options to views. .. _generic views: http://www.djangoproject.com/documentation/generic_views/ .. _syndication framework: http://www.djangoproject.com/documentation/syndication/ + +Passing extra options to ``include()`` +-------------------------------------- + +**New in the Django development version.** + +Similarly, you can pass extra options to ``include()``. When you pass extra +options to ``include()``, *each* line in the included URLconf will be passed +the extra options. + +For example, these two URLconf sets are functionally identical: + +Set one:: + + # main.py + urlpatterns = patterns('', + (r'^blog/', include('inner'), {'blogid': 3}), + ) + + # inner.py + urlpatterns = patterns('', + (r'^archive/$', 'mysite.views.archive'), + (r'^about/$', 'mysite.views.about'), + ) + +Set two:: + + # main.py + urlpatterns = patterns('', + (r'^blog/', include('inner')), + ) + + # inner.py + urlpatterns = patterns('', + (r'^archive/$', 'mysite.views.archive', {'blogid': 3}), + (r'^about/$', 'mysite.views.about', {'blogid': 3}), + ) + +Note that extra options will *always* be passed to *every* line in the included +URLconf, regardless of whether the line's view actually accepts those options +as valid. For this reason, this technique is only useful if you're certain that +every view in the the included URLconf accepts the extra options you're passing. |
