summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Pellerin <jpellerin@gmail.com>2006-08-04 23:27:18 +0000
committerJason Pellerin <jpellerin@gmail.com>2006-08-04 23:27:18 +0000
commit238c6ecd5b10c6c76b8b1db03dcb746bcfe366af (patch)
tree7a29f1cdb8d6c48d44441b98c0ab0a34fb4258e3
parent08c420718200bcb0dcc5237f678d45d10173e81e (diff)
[multi-db] Merge trunk to [3522]
git-svn-id: http://code.djangoproject.com/svn/django/branches/multiple-db-support@3523 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--AUTHORS2
-rw-r--r--django/conf/locale/ru/LC_MESSAGES/django.mobin31822 -> 31773 bytes
-rw-r--r--django/conf/locale/ru/LC_MESSAGES/django.po3
-rw-r--r--django/conf/urls/defaults.py8
-rw-r--r--django/contrib/admin/media/js/admin/DateTimeShortcuts.js66
-rw-r--r--django/contrib/admin/media/js/admin/RelatedObjectLookups.js2
-rw-r--r--django/contrib/admin/templates/admin/auth/user/add_form.html28
-rw-r--r--django/contrib/admin/urls.py3
-rw-r--r--django/contrib/admin/views/auth.py39
-rw-r--r--django/contrib/auth/forms.py22
-rw-r--r--django/core/management.py6
-rw-r--r--django/core/urlresolvers.py6
-rw-r--r--django/db/backends/ansi/sql.py7
-rw-r--r--django/db/models/fields/__init__.py7
-rw-r--r--django/db/models/fields/related.py2
-rw-r--r--django/middleware/gzip.py6
-rw-r--r--docs/add_ons.txt7
-rw-r--r--docs/db-api.txt3
-rw-r--r--docs/faq.txt9
-rw-r--r--docs/url_dispatch.txt52
20 files changed, 227 insertions, 51 deletions
diff --git a/AUTHORS b/AUTHORS
index 6b539e8b6b..9c9e67c50a 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -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
index 562996eee5..d45691bd30 100644
--- a/django/conf/locale/ru/LC_MESSAGES/django.mo
+++ b/django/conf/locale/ru/LC_MESSAGES/django.mo
Binary files differ
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.