1
0
mirror of https://github.com/django/django.git synced 2025-07-04 17:59:13 +00:00

[full-history] Trunk merge from [3577]

git-svn-id: http://code.djangoproject.com/svn/django/branches/full-history@3580 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Uroš Trebec 2006-08-14 00:32:07 +00:00
parent b1f4974bef
commit ca86ceec83
43 changed files with 492 additions and 103 deletions

View File

@ -60,6 +60,7 @@ answer newbie questions, and generally made Django that much better:
Amit Chakradeo <http://amit.chakradeo.net/>
ChaosKCW
Ian Clelland <clelland@gmail.com>
crankycoder@gmail.com
Matt Croydon <http://www.postneo.com/>
Jonathan Daugherty (cygnus) <http://www.cprogrammer.org/>
Jason Davies (Esaj) <http://www.jasondavies.com/>
@ -71,6 +72,7 @@ answer newbie questions, and generally made Django that much better:
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
@ -124,12 +126,14 @@ answer newbie questions, and generally made Django that much better:
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
David Schein
sopel
Thomas Steinacher <tom@eggdrop.ch>
Radek Švarz <http://www.svarz.cz/translate/>
Swaroop C H <http://www.swaroopch.info>
Aaron Swartz <http://www.aaronsw.com/>
Tom Tobin
Tom Insam
Joe Topjian <http://joe.terrarum.net/geek/code/python/django/>
Karen Tracey <graybark@bellsouth.net>
Amit Upadhyay
Geert Vanderkelen
Milton Waddams

View File

@ -14,7 +14,7 @@ def compile_messages():
print "this script should be run from the django svn tree or your project or app tree"
sys.exit(1)
for (dirpath, dirnames, filenames) in os.walk(basedir):
for dirpath, dirnames, filenames in os.walk(basedir):
for f in filenames:
if f.endswith('.po'):
sys.stderr.write('processing file %s in %s\n' % (f, dirpath))

View File

@ -252,6 +252,7 @@ MIDDLEWARE_CLASSES = (
SESSION_COOKIE_NAME = 'sessionid' # Cookie name. This can be whatever you want.
SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2 # Age of cookie, in seconds (default: 2 weeks).
SESSION_COOKIE_DOMAIN = None # A string like ".lawrence.com", or None for standard domain cookie.
SESSION_COOKIE_SECURE = False # Whether the session cookie should be secure (https:// only).
SESSION_SAVE_EVERY_REQUEST = False # Whether to save the session data on every request.
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Whether sessions expire when a user closes his browser.

View File

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

View File

@ -60,8 +60,9 @@ MIDDLEWARE_CLASSES = (
ROOT_URLCONF = '{{ project_name }}.urls'
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates".
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
INSTALLED_APPS = (

View File

@ -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;
}

View File

@ -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 %}

View File

@ -21,7 +21,7 @@
{% if has_absolute_url %}<li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%}
</ul>
{% endif %}{% endif %}
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post">{% block form_top %}{% endblock %}
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form">{% block form_top %}{% endblock %}
<div>
{% if is_popup %}<input type="hidden" name="_popup" value="1" />{% endif %}
{% if opts.admin.save_on_top %}{% submit_row %}{% endif %}

View File

@ -7,6 +7,7 @@
<th{{ fw.header_class_attribute }}>{{ fw.field.verbose_name|capfirst|escape }}</th>
{% endif %}
{% endfor %}
</tr></thead>
{% for fcw in bound_related_object.form_field_collection_wrappers %}
{% if change %}{% if original_row_needed %}
{% if fcw.obj.original %}

View File

@ -21,13 +21,15 @@ urlpatterns = patterns('',
('^doc/tags/$', 'django.contrib.admin.views.doc.template_tag_index'),
('^doc/filters/$', 'django.contrib.admin.views.doc.template_filter_index'),
('^doc/views/$', 'django.contrib.admin.views.doc.view_index'),
('^doc/views/jump/$', 'django.contrib.admin.views.doc.jump_to_view'),
('^doc/views/(?P<view>[^/]+)/$', 'django.contrib.admin.views.doc.view_detail'),
('^doc/models/$', 'django.contrib.admin.views.doc.model_index'),
('^doc/models/(?P<app_label>[^\.]+)\.(?P<model_name>[^/]+)/$', 'django.contrib.admin.views.doc.model_detail'),
# ('^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'),

View File

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

View File

@ -43,11 +43,11 @@ def template_tag_index(request):
for tag_name, tag_func in library.tags.items():
title, body, metadata = utils.parse_docstring(tag_func.__doc__)
if title:
title = utils.parse_rst(title, 'tag', 'tag:' + tag_name)
title = utils.parse_rst(title, 'tag', _('tag:') + tag_name)
if body:
body = utils.parse_rst(body, 'tag', 'tag:' + tag_name)
body = utils.parse_rst(body, 'tag', _('tag:') + tag_name)
for key in metadata:
metadata[key] = utils.parse_rst(metadata[key], 'tag', 'tag:' + tag_name)
metadata[key] = utils.parse_rst(metadata[key], 'tag', _('tag:') + tag_name)
if library in template.builtins:
tag_library = None
else:
@ -74,11 +74,11 @@ def template_filter_index(request):
for filter_name, filter_func in library.filters.items():
title, body, metadata = utils.parse_docstring(filter_func.__doc__)
if title:
title = utils.parse_rst(title, 'filter', 'filter:' + filter_name)
title = utils.parse_rst(title, 'filter', _('filter:') + filter_name)
if body:
body = utils.parse_rst(body, 'filter', 'filter:' + filter_name)
body = utils.parse_rst(body, 'filter', _('filter:') + filter_name)
for key in metadata:
metadata[key] = utils.parse_rst(metadata[key], 'filter', 'filter:' + filter_name)
metadata[key] = utils.parse_rst(metadata[key], 'filter', _('filter:') + filter_name)
if library in template.builtins:
tag_library = None
else:
@ -132,11 +132,11 @@ def view_detail(request, view):
raise Http404
title, body, metadata = utils.parse_docstring(view_func.__doc__)
if title:
title = utils.parse_rst(title, 'view', 'view:' + view)
title = utils.parse_rst(title, 'view', _('view:') + view)
if body:
body = utils.parse_rst(body, 'view', 'view:' + view)
body = utils.parse_rst(body, 'view', _('view:') + view)
for key in metadata:
metadata[key] = utils.parse_rst(metadata[key], 'model', 'view:' + view)
metadata[key] = utils.parse_rst(metadata[key], 'model', _('view:') + view)
return render_to_response('admin_doc/view_detail.html', {
'name': view,
'summary': title,
@ -161,14 +161,14 @@ def model_detail(request, app_label, model_name):
try:
app_mod = models.get_app(app_label)
except ImproperlyConfigured:
raise Http404, "App %r not found" % app_label
raise Http404, _("App %r not found") % app_label
model = None
for m in models.get_models(app_mod):
if m._meta.object_name.lower() == model_name:
model = m
break
if model is None:
raise Http404, "Model %r not found in app %r" % (model_name, app_label)
raise Http404, _("Model %r not found in app %r") % (model_name, app_label)
opts = model._meta
@ -180,7 +180,7 @@ def model_detail(request, app_label, model_name):
if isinstance(field, models.ForeignKey):
data_type = related_object_name = field.rel.to.__name__
app_label = field.rel.to._meta.app_label
verbose = utils.parse_rst(("the related `%s.%s` object" % (app_label, data_type)), 'model', 'model:' + data_type)
verbose = utils.parse_rst((_("the related `%s.%s` object") % (app_label, data_type)), 'model', _('model:') + data_type)
else:
data_type = get_readable_field_data_type(field)
verbose = field.verbose_name
@ -202,7 +202,7 @@ def model_detail(request, app_label, model_name):
continue
verbose = func.__doc__
if verbose:
verbose = utils.parse_rst(utils.trim_docstring(verbose), 'model', 'model:' + opts.module_name)
verbose = utils.parse_rst(utils.trim_docstring(verbose), 'model', _('model:') + opts.module_name)
fields.append({
'name': func_name,
'data_type': get_return_data_type(func_name),
@ -211,17 +211,17 @@ def model_detail(request, app_label, model_name):
# Gather related objects
for rel in opts.get_all_related_objects():
verbose = "related `%s.%s` objects" % (rel.opts.app_label, rel.opts.object_name)
verbose = _("related `%s.%s` objects") % (rel.opts.app_label, rel.opts.object_name)
accessor = rel.get_accessor_name()
fields.append({
'name' : "%s.all" % accessor,
'data_type' : 'List',
'verbose' : utils.parse_rst("all " + verbose , 'model', 'model:' + opts.module_name),
'verbose' : utils.parse_rst(_("all %s") % verbose , 'model', _('model:') + opts.module_name),
})
fields.append({
'name' : "%s.count" % accessor,
'data_type' : 'Integer',
'verbose' : utils.parse_rst("number of " + verbose , 'model', 'model:' + opts.module_name),
'verbose' : utils.parse_rst(_("number of %s") % verbose , 'model', _('model:') + opts.module_name),
})
return render_to_response('admin_doc/model_detail.html', {
@ -336,7 +336,7 @@ def extract_views_from_urlpatterns(urlpatterns, base=''):
elif hasattr(p, '_get_url_patterns'):
views.extend(extract_views_from_urlpatterns(p.url_patterns, base + p.regex.pattern))
else:
raise TypeError, "%s does not appear to be a urlpattern object" % p
raise TypeError, _("%s does not appear to be a urlpattern object") % p
return views
named_group_matcher = re.compile(r'\(\?P(<\w+>).+?\)')

View File

@ -263,7 +263,7 @@ def add_stage(request, app_label, model_name, show_delete=False, form_url='', po
post_url_continue += "?_popup=1"
return HttpResponseRedirect(post_url_continue % pk_value)
if request.POST.has_key("_popup"):
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %s, "%s");</script>' % \
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %r, "%s");</script>' % \
(pk_value, str(new_object).replace('"', '\\"')))
elif request.POST.has_key("_addanother"):
request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))

View File

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

View File

@ -2,7 +2,7 @@ This is an optional add-on app, flatpages.
For full documentation, see either of these:
* The file django/docs/flatpages.txt in the Django distribution
* The file docs/flatpages.txt in the Django distribution
* http://www.djangoproject.com/documentation/flatpages/ on the Web
Both have identical content.
Both have identical content.

View File

@ -88,5 +88,6 @@ class SessionMiddleware(object):
new_session = Session.objects.save(session_key, request.session._session,
datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE))
response.set_cookie(settings.SESSION_COOKIE_NAME, session_key,
max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN)
max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
secure=settings.SESSION_COOKIE_SECURE or None)
return response

View File

@ -94,12 +94,15 @@ def get_sql_create(app):
"Edit your settings file and change DATABASE_ENGINE to something like 'postgresql' or 'mysql'.\n"))
sys.exit(1)
# Get installed models, so we generate REFERENCES right
# Get installed models, so we generate REFERENCES right.
# We trim models from the current app so that the sqlreset command does not
# generate invalid SQL (leaving models out of known_models is harmless, so
# we can be conservative).
app_models = models.get_models(app)
final_output = []
known_models = set(_get_installed_models(_get_table_list()))
known_models = set([model for model in _get_installed_models(_get_table_list()) if model not in app_models])
pending_references = {}
app_models = models.get_models(app)
for model in app_models:
output, references = _get_sql_model_create(model, known_models)
@ -118,10 +121,13 @@ def get_sql_create(app):
# but don't exist physically
not_installed_models = set(pending_references.keys())
if not_installed_models:
final_output.append('-- The following references should be added but depend on non-existant tables:')
alter_sql = []
for model in not_installed_models:
final_output.extend(['-- ' + sql for sql in
alter_sql.extend(['-- ' + sql for sql in
_get_sql_for_pending_references(model, pending_references)])
if alter_sql:
final_output.append('-- The following references should be added but depend on non-existent tables:')
final_output.extend(alter_sql)
return final_output
get_sql_create.help_doc = "Prints the CREATE TABLE SQL statements for the given app name(s)."
@ -295,7 +301,7 @@ def get_sql_delete(app):
(style.SQL_KEYWORD('ALTER TABLE'),
style.SQL_TABLE(backend.quote_name(table)),
style.SQL_KEYWORD(backend.get_drop_foreignkey_sql()),
style.SQL_FIELD(backend.quote_name("%s_referencing_%s_%s" % (col, r_table, r_col)))))
style.SQL_FIELD(backend.quote_name('%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))))))
del references_to_delete[model]
# Output DROP TABLE statements for many-to-many tables.
@ -692,9 +698,7 @@ def inspectdb():
introspection_module = get_introspection_module()
def table2model(table_name):
object_name = table_name.title().replace('_', '')
return object_name.endswith('s') and object_name[:-1] or object_name
table2model = lambda table_name: table_name.title().replace('_', '')
cursor = connection.cursor()
yield "# This is an auto-generated Django model module."
@ -723,6 +727,10 @@ def inspectdb():
comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
extra_params = {} # Holds Field parameters such as 'db_column'.
if ' ' in att_name:
extra_params['db_column'] = att_name
att_name = att_name.replace(' ', '')
comment_notes.append('Field renamed to remove spaces.')
if keyword.iskeyword(att_name):
extra_params['db_column'] = att_name
att_name += '_field'
@ -953,6 +961,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:
@ -1128,7 +1142,14 @@ def dbshell():
dbshell.args = ""
def runfcgi(args):
"""Run this project as a FastCGI application. requires flup."""
"Runs this project as a FastCGI application. Requires flup."
from django.conf import settings
from django.utils import translation
# Activate the current language, because it won't get activated later.
try:
translation.activate(settings.LANGUAGE_CODE)
except AttributeError:
pass
from django.core.servers.fastcgi import runfastcgi
runfastcgi(args)
runfcgi.args = '[various KEY=val options, use `runfcgi help` for help]'
@ -1285,7 +1306,11 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
if action not in NO_SQL_TRANSACTION:
print style.SQL_KEYWORD("COMMIT;")
def execute_manager(settings_mod, argv=None):
def setup_environ(settings_mod):
"""
Configure the runtime environment. This can also be used by external
scripts wanting to set up a similar environment to manage.py.
"""
# Add this project to sys.path so that it's importable in the conventional
# way. For example, if this file (manage.py) lives in a directory
# "myproject", this code would add "/path/to/myproject" to sys.path.
@ -1297,7 +1322,10 @@ def execute_manager(settings_mod, argv=None):
# Set DJANGO_SETTINGS_MODULE appropriately.
os.environ['DJANGO_SETTINGS_MODULE'] = '%s.settings' % project_name
return project_directory
def execute_manager(settings_mod, argv=None):
project_directory = setup_environ(settings_mod)
action_mapping = DEFAULT_ACTION_MAPPING.copy()
# Remove the "startproject" command from the action_mapping, because that's

View File

@ -547,10 +547,6 @@ class WSGIRequestHandler(BaseHTTPRequestHandler):
env['PATH_INFO'] = urllib.unquote(path)
env['QUERY_STRING'] = query
host = self.address_string()
if host != self.client_address[0]:
env['REMOTE_HOST'] = host
env['REMOTE_ADDR'] = self.client_address[0]
if self.headers.typeheader is None:

View File

@ -86,10 +86,15 @@ class MatchChecker(object):
class RegexURLPattern(object):
def __init__(self, regex, callback, default_args=None):
# regex is a string representing a regular expression.
# callback is something like 'foo.views.news.stories.story_detail',
# which represents the path to a module and a view function name.
# callback is either a string like 'foo.views.news.stories.story_detail'
# which represents the path to a module and a view function name, or a
# callable object (view).
self.regex = re.compile(regex)
self.callback = callback
if callable(callback):
self._callback = callback
else:
self._callback = None
self._callback_str = callback
self.default_args = default_args or {}
def resolve(self, path):
@ -106,23 +111,28 @@ class RegexURLPattern(object):
# In both cases, pass any extra_kwargs as **kwargs.
kwargs.update(self.default_args)
try: # Lazily load self.func.
return self.func, args, kwargs
except AttributeError:
self.func = self.get_callback()
return self.func, args, kwargs
return self.callback, args, kwargs
def get_callback(self):
mod_name, func_name = get_mod_func(self.callback)
def _get_callback(self):
if self._callback is not None:
return self._callback
mod_name, func_name = get_mod_func(self._callback_str)
try:
return getattr(__import__(mod_name, '', '', ['']), func_name)
self._callback = getattr(__import__(mod_name, '', '', ['']), func_name)
except ImportError, e:
raise ViewDoesNotExist, "Could not import %s. Error was: %s" % (mod_name, str(e))
except AttributeError, e:
raise ViewDoesNotExist, "Tried %s in module %s. Error was: %s" % (func_name, mod_name, str(e))
return self._callback
callback = property(_get_callback)
def reverse(self, viewname, *args, **kwargs):
if viewname != self.callback:
mod_name, func_name = get_mod_func(viewname)
try:
lookup_view = getattr(__import__(mod_name, '', '', ['']), func_name)
except (ImportError, AttributeError):
raise NoReverseMatch
if lookup_view != self.callback:
raise NoReverseMatch
return self.reverse_helper(*args, **kwargs)
@ -185,22 +195,28 @@ class RegexURLResolver(object):
def resolve500(self):
return self._resolve_special('500')
def reverse(self, viewname, *args, **kwargs):
def reverse(self, lookup_view, *args, **kwargs):
if not callable(lookup_view):
mod_name, func_name = get_mod_func(lookup_view)
try:
lookup_view = getattr(__import__(mod_name, '', '', ['']), func_name)
except (ImportError, AttributeError):
raise NoReverseMatch
for pattern in self.urlconf_module.urlpatterns:
if isinstance(pattern, RegexURLResolver):
try:
return pattern.reverse_helper(viewname, *args, **kwargs)
return pattern.reverse_helper(lookup_view, *args, **kwargs)
except NoReverseMatch:
continue
elif pattern.callback == viewname:
elif pattern.callback == lookup_view:
try:
return pattern.reverse_helper(*args, **kwargs)
except NoReverseMatch:
continue
raise NoReverseMatch
def reverse_helper(self, viewname, *args, **kwargs):
sub_match = self.reverse(viewname, *args, **kwargs)
def reverse_helper(self, lookup_view, *args, **kwargs):
sub_match = self.reverse(lookup_view, *args, **kwargs)
result = reverse_helper(self.regex, *args, **kwargs)
return result + sub_match

View File

@ -11,6 +11,10 @@ except ImportError, e:
from django.core.exceptions import ImproperlyConfigured
raise ImproperlyConfigured, "Error loading psycopg2 module: %s" % e
# Register Unicode conversions
import psycopg2.extensions
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
DatabaseError = Database.DatabaseError
try:

View File

@ -25,7 +25,7 @@ def permalink(func):
def inner(*args, **kwargs):
bits = func(*args, **kwargs)
viewname = bits[0]
return reverse(bits[0], None, *bits[1:2])
return reverse(bits[0], None, *bits[1:3])
return inner
class LazyDate(object):
@ -47,7 +47,7 @@ class LazyDate(object):
return "<LazyDate: %s>" % self.delta
def __get_value__(self):
return datetime.datetime.now() + self.delta
return (datetime.datetime.now() + self.delta).date()
def __getattr__(self, attr):
return getattr(self.__get_value__(), attr)

View File

@ -176,11 +176,12 @@ class Model(object):
# If it does already exist, do an UPDATE.
if cursor.fetchone():
db_values = [f.get_db_prep_save(f.pre_save(self, False)) for f in non_pks]
cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
(backend.quote_name(self._meta.db_table),
','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]),
backend.quote_name(self._meta.pk.column)),
db_values + [pk_val])
if db_values:
cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
(backend.quote_name(self._meta.db_table),
','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]),
backend.quote_name(self._meta.pk.column)),
db_values + [pk_val])
else:
record_exists = False
if not pk_set or not record_exists:

View File

@ -20,7 +20,7 @@ BLANK_CHOICE_DASH = [("", "---------")]
BLANK_CHOICE_NONE = [("", "None")]
# prepares a value for use in a LIKE query
prep_for_like_query = lambda x: str(x).replace("%", "\%").replace("_", "\_")
prep_for_like_query = lambda x: str(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_")
# returns the <ul> class for a given radio_admin value
get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '')

View File

@ -32,7 +32,7 @@ def get_apps():
_app_errors[app_name] = e
return _app_list
def get_app(app_label, emptyOK = False):
def get_app(app_label, emptyOK=False):
"Returns the module containing the models for the given app_label. If the app has no models in it and 'emptyOK' is True, returns None."
get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
for app_name in settings.INSTALLED_APPS:
@ -75,7 +75,7 @@ def get_models(app_mod=None):
model_list.extend(get_models(app_mod))
return model_list
def get_model(app_label, model_name, seed_cache = True):
def get_model(app_label, model_name, seed_cache=True):
"""
Returns the model matching the given app_label and case-insensitive
model_name.

View File

@ -138,7 +138,7 @@ class AutomaticManipulator(forms.Manipulator):
child_follow = self.follow.get(related.name, None)
if child_follow:
obj_list = expanded_data[related.var_name].items()
obj_list = expanded_data.get(related.var_name, {}).items()
if not obj_list:
continue

View File

@ -38,7 +38,7 @@ class HttpRequest(object):
def get_full_path(self):
return ''
def is_secure(self):
return os.environ.get("HTTPS") == "on"
@ -203,11 +203,14 @@ class HttpResponse(object):
if val is not None:
self.cookies[key][var.replace('_', '-')] = val
def delete_cookie(self, key):
try:
self.cookies[key]['max_age'] = 0
except KeyError:
pass
def delete_cookie(self, key, path='/', domain=None):
self.cookies[key] = ''
if path is not None:
self.cookies[key]['path'] = path
if domain is not None:
self.cookies[key]['domain'] = path
self.cookies[key]['expires'] = 0
self.cookies[key]['max-age'] = 0
def _get_content(self):
content = ''.join(self._iterator)

View File

@ -339,7 +339,7 @@ def date(value, arg=None):
def time(value, arg=None):
"Formats a time according to the given format"
from django.utils.dateformat import time_format
if not value:
if value in (None, ''):
return ''
if arg is None:
arg = settings.TIME_FORMAT
@ -437,7 +437,7 @@ def pluralize(value, arg='s'):
is used instead. If the provided argument contains a comma, the text before
the comma is used for the singular case.
"""
if not ',' in arg:
if not ',' in arg:
arg = ',' + arg
bits = arg.split(',')
if len(bits) > 2:

View File

@ -17,7 +17,7 @@ def load_template_source(template_name, template_dirs=None):
return (open(filepath).read(), filepath)
except IOError:
tried.append(filepath)
if template_dirs:
if tried:
error_msg = "Tried %s" % tried
else:
error_msg = "Your TEMPLATE_DIRS setting is empty. Change it to point to at least one template directory."

View File

@ -6,6 +6,7 @@ from django.contrib.auth.views import redirect_to_login
from django.template import RequestContext
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
from django.utils.translation import gettext
def create_object(request, model, template_name=None,
template_loader=loader, extra_context=None, post_save_redirect=None,
@ -39,7 +40,7 @@ def create_object(request, model, template_name=None,
new_object = manipulator.save(new_data)
if request.user.is_authenticated():
request.user.message_set.create(message="The %s was created successfully." % model._meta.verbose_name)
request.user.message_set.create(message=gettext("The %(verbose_name)s was created successfully.") % {"verbose_name": model._meta.verbose_name})
# Redirect to the new object: first by trying post_save_redirect,
# then by obj.get_absolute_url; fail if neither works.
@ -113,7 +114,7 @@ def update_object(request, model, object_id=None, slug=None,
object = manipulator.save(new_data)
if request.user.is_authenticated():
request.user.message_set.create(message="The %s was updated successfully." % model._meta.verbose_name)
request.user.message_set.create(message=gettext("The %(verbose_name)s was updated successfully.") % {"verbose_name": model._meta.verbose_name})
# Do a post-after-redirect so that reload works, etc.
if post_save_redirect:
@ -180,7 +181,7 @@ def delete_object(request, model, post_delete_redirect,
if request.method == 'POST':
object.delete()
if request.user.is_authenticated():
request.user.message_set.create(message="The %s was deleted." % model._meta.verbose_name)
request.user.message_set.create(message=gettext("The %(verbose_name)s was deleted.") % {"verbose_name": model._meta.verbose_name})
return HttpResponseRedirect(post_delete_redirect)
else:
if not template_name:

View File

@ -718,12 +718,12 @@ The ``DoesNotExist`` exception inherits from
A convenience method for creating an object and saving it all in one step. Thus::
p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
and::
p = Person(first_name="Bruce", last_name="Springsteen")
p.save()
are equivalent.
``get_or_create(**kwargs)``
@ -1471,11 +1471,12 @@ the ``ForeignKey`` ``Manager`` has these additional methods:
b.entry_set.remove(e) # Disassociates Entry e from Blog b.
In order to prevent database inconsistency, this method only exists on
``ForeignKey``s where ``null=True``. If the related field can't be set to
``None`` (``NULL``), then an object can't be removed from a relation
without being added to another. In the above example, removing ``e`` from
``b.entry_set()`` is equivalent to doing ``e.blog = None``, and because
the ``blog`` ``ForeignKey`` doesn't have ``null=True``, this is invalid.
``ForeignKey`` objects where ``null=True``. If the related field can't be
set to ``None`` (``NULL``), then an object can't be removed from a
relation without being added to another. In the above example, removing
``e`` from ``b.entry_set()`` is equivalent to doing ``e.blog = None``,
and because the ``blog`` ``ForeignKey`` doesn't have ``null=True``, this
is invalid.
* ``clear()``: Removes all objects from the related object set.
@ -1559,13 +1560,13 @@ Queries over related objects
----------------------------
Queries involving related objects follow the same rules as queries involving
normal value fields. When specifying the the value for a query to match, you
may use either an object instance itself, or the primary key value for the
normal value fields. When specifying the the value for a query to match, you
may use either an object instance itself, or the primary key value for the
object.
For example, if you have a Blog object ``b`` with ``id=5``, the following
three queries would be identical::
Entry.objects.filter(blog=b) # Query using object instance
Entry.objects.filter(blog=b.id) # Query using id from instance
Entry.objects.filter(blog=5) # Query using id directly

148
docs/documentation.txt Normal file
View File

@ -0,0 +1,148 @@
====================================
How to read the Django documentation
====================================
We've put a lot of effort into making Django's documentation useful, easy to
read and as complete as possible. Here are a few tips on how to make the best
of it, along with some style guidelines.
(Yes, this is documentation about documentation. Rest assured we have no plans
to write a document about how to read the document about documentation.)
How documentation is updated
============================
Just as the Django code base is developed and improved on a daily basis, our
documentation is consistently improving. We improve documentation for several
reasons:
* To make content fixes, such as grammar/typo corrections.
* To add information and/or examples to existing sections that need to be
expanded.
* To document Django features that aren't yet documented. (The list of
such features is shrinking but exists nonetheless.)
* To add documentation for new features as new features get added, or as
Django APIs or behaviors change.
Django's documentation is kept in the same source control system as its code.
It lives in the `django/trunk/docs`_ directory of our Subversion repository.
Each document is a separate text file that covers a narrowly focused topic,
such as the "generic views" framework or how to construct a database model.
.. _django/trunk/docs: http://code.djangoproject.com/browser/django/trunk/docs
Where to get it
===============
You can read Django documentation in several ways. They are, in order of
preference:
On the Web
----------
The most recent version of the Django documentation lives at
http://www.djangoproject.com/documentation/ . These HTML pages are generated
automatically from the text files in source control every 15 minutes. That
means they reflect the "latest and greatest" in Django -- they include the very
latest corrections and additions, and they discuss the latest Django features,
which may only be available to users of the Django development version. (See
"Differences between versions" below.)
A key advantage of the Web-based documentation is the comment section at the
bottom of each document. This is an area for anybody to submit changes,
corrections and suggestions about the given document. The Django developers
frequently monitor the comments there and use them to improve the documentation
for everybody.
We encourage you to help improve the docs: it's easy! Note, however, that
comments should explicitly relate to the documentation, rather than asking
broad tech-support questions. If you need help with your particular Django
setup, try the `django-users mailing list`_ instead of posting a comment to the
documentation.
.. _django-users mailing list: http://groups.google.com/group/django-users
In plain text
-------------
For offline reading, or just for convenience, you can read the Django
documentation in plain text.
If you're using an official release of Django, note that the zipped package
(tarball) of the code includes a ``docs/`` directory, which contains all the
documentation for that release.
If you're using the development version of Django (aka the Subversion "trunk"),
note that the ``docs/`` directory contains all of the documentation. You can
``svn update`` it, just as you ``svn update`` the Python code, in order to get
the latest changes.
You can check out the latest Django documentation from Subversion using this
shell command::
svn co http://code.djangoproject.com/svn/django/trunk/docs/ django_docs
One low-tech way of taking advantage of the text documentation is by using the
Unix ``grep`` utility to search for a phrase in all of the documentation. For
example, this will show you each mention of the phrase "edit_inline" in any
Django document::
grep edit_inline /path/to/django/docs/*.txt
Formatting
~~~~~~~~~~
The text documentation is written in ReST (ReStructured Text) format. That
means it's easy to read but is also formatted in a way that makes it easy to
convert into other formats, such as HTML. If you're interested, the script that
converts the ReST text docs into djangoproject.com's HTML lives at
`djangoproject.com/django_website/apps/docs/parts/build_documentation.py`_ in
the Django Subversion repository.
.. _djangoproject.com/django_website/apps/docs/parts/build_documentation.py: http://code.djangoproject.com/browser/djangoproject.com/django_website/apps/docs/parts/build_documentation.py
Differences between versions
============================
As previously mentioned, the text documentation in our Subversion repository
contains the "latest and greatest" changes and additions. These changes often
include documentation of new features added in the Django development version
-- the Subversion ("trunk") version of Django. For that reason, it's worth
pointing out our policy on keeping straight the documentation for various
versions of the framework.
We follow this policy:
* The primary documentation on djangoproject.com is an HTML version of the
latest docs in Subversion. These docs always correspond to the latest
official Django release, plus whatever features we've added/changed in
the framework *since* the latest release.
* As we add features to Django's development version, we try to update the
documentation in the same Subversion commit transaction.
* To distinguish feature changes/additions in the docs, we use the phrase
**New in Django development version**. In practice, this means that the
current documentation on djangoproject.com can be used by users of either
the latest release *or* the development version.
* Documentation for a particular Django release is frozen once the version
has been released officially. It remains a snapshot of the docs as of the
moment of the release. We will make exceptions to this rule in
the case of retroactive security updates or other such retroactive
changes. Once documentation is frozen, we add a note to the top of each
frozen document that says "These docs are frozen for Django version XXX"
and links to the current version of that document.
* Once a document is frozen for a Django release, we remove comments from
that page, in favor of having comments on the latest version of that
document. This is for the sake of maintainability and usability, so that
users have one, and only one, place to leave comments on a particular
document. We realize that some people may be stuck on a previous version
of Django, but we believe the usability problems with multiple versions
of a document the outweigh the benefits.
* The `main documentation Web page`_ includes links to documentation for
all previous versions.
.. _main documentation Web page: http://www.djangoproject.com/documentation/

View File

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

View File

@ -127,7 +127,7 @@ If the given URL is ``None``, Django will return an ``HttpResponseGone`` (410).
This example redirects from ``/foo/<id>/`` to ``/bar/<id>/``::
urlpatterns = patterns('django.views.generic.simple',
('^foo/(?p<id>\d+)/$', 'redirect_to', {'url': '/bar/%(id)s/'}),
('^foo/(?P<id>\d+)/$', 'redirect_to', {'url': '/bar/%(id)s/'}),
)
This example returns a 410 HTTP error for requests to ``/bar/``::

View File

@ -223,6 +223,13 @@ steps:
the absolute URL to your image in a template with ``{{
object.get_mug_shot_url }}``.
For example, say your ``MEDIA_ROOT`` is set to ``'/home/media'``, and
``upload_to`` is set to ``'photos/%Y/%m/%d'``. The ``'%Y/%m/%d'`` part of
``upload_to`` is strftime formatting; ``'%Y'`` is the four-digit year,
``'%m'`` is the two-digit month and ``'%d'`` is the two-digit day. If you
upload a file on Jan. 15, 2007, it will be saved in the directory
``/home/media/photos/2007/01/15``.
.. _`strftime formatting`: http://docs.python.org/lib/module-time.html#l2h-1941
``FilePathField``

View File

@ -149,7 +149,7 @@ Methods
Returns the ``path``, plus an appended query string, if applicable.
Example: ``"/music/bands/the_beatles/?print=true"``
``is_secure()``
Returns ``True`` if the request is secure; that is, if it was made with
HTTPS.
@ -380,10 +380,14 @@ Methods
.. _`cookie Morsel`: http://www.python.org/doc/current/lib/morsel-objects.html
``delete_cookie(key)``
``delete_cookie(key, path='/', domain=None)``
Deletes the cookie with the given key. Fails silently if the key doesn't
exist.
The ``path`` and ``domain`` arguments are new in the Django development version.
Due to the way cookies work, ``path`` and ``domain`` should be the same
values you used in ``set_cookie()`` -- otherwise the cookie may not be deleted.
``content``
Returns the content as a Python string, encoding it from a Unicode object
if necessary. Note this is a property, not a method, so use ``r.content``

View File

@ -245,6 +245,17 @@ Default: ``'sessionid'``
The name of the cookie to use for sessions. This can be whatever you want.
SESSION_COOKIE_SECURE
---------------------
**New in Django development version**
Default: ``False``
Whether to use a secure cookie for the session cookie. If this is set to
``True``, the cookie will be marked as "secure," which means browsers may
ensure that the cookie is only sent under an HTTPS connection.
SESSION_EXPIRE_AT_BROWSER_CLOSE
-------------------------------

View File

@ -647,6 +647,18 @@ Default: ``'sessionid'``
The name of the cookie to use for sessions. This can be whatever you want.
See the `session docs`_.
SESSION_COOKIE_SECURE
---------------------
**New in Django development version**
Default: ``False``
Whether to use a secure cookie for the session cookie. If this is set to
``True``, the cookie will be marked as "secure," which means browsers may
ensure that the cookie is only sent under an HTTPS connection.
See the `session docs`_.
SESSION_EXPIRE_AT_BROWSER_CLOSE
-------------------------------

View File

@ -431,3 +431,48 @@ 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.
Passing callable objects instead of strings
===========================================
**New in the Django development version.**
Some developers find it more natural to pass the actual Python function object
rather than a string containing the path to its module. This alternative is
supported -- you can pass any callable object as the view.
For example, given this URLconf in "string" notation::
urlpatterns = patterns('',
(r'^archive/$', 'mysite.views.archive'),
(r'^about/$', 'mysite.views.about'),
(r'^contact/$', 'mysite.views.contact'),
)
You can accomplish the same thing by passing objects rather than strings. Just
be sure to import the objects::
from mysite.views import archive, about, contact
urlpatterns = patterns('',
(r'^archive/$', archive),
(r'^about/$', about),
(r'^contact/$', contact),
)
The following example is functionally identical. It's just a bit more compact
because it imports the module that contains the views, rather than importing
each view individually::
from mysite import views
urlpatterns = patterns('',
(r'^archive/$', views.archive),
(r'^about/$', views.about),
(r'^contact/$', views.contact),
)
The style you use is up to you.
Note that if you use this technique -- passing objects rather than strings --
the view prefix (as explained in "The view prefix" above) will have no effect.

View File

@ -16,6 +16,7 @@ setup(
'': ['*.TXT'],
'django.conf': ['locale/*/LC_MESSAGES/*'],
'django.contrib.admin': ['templates/admin/*.html',
'templates/admin/auth/user/*.html',
'templates/admin_doc/*.html',
'templates/registration/*.html',
'templates/widget/*.html',

View File

@ -20,5 +20,7 @@ API_TESTS = """
2
>>> m.id is not None
True
>>> existing = Empty(m.id)
>>> existing.save()
"""

View File

@ -15,7 +15,7 @@ class Article(models.Model):
def __str__(self):
return self.headline
API_TESTS = """
API_TESTS = r"""
# Create a couple of Articles.
>>> from datetime import datetime
>>> a1 = Article(headline='Article 1', pub_date=datetime(2005, 7, 26))
@ -161,13 +161,14 @@ DoesNotExist: Article matching query does not exist.
<Article: Article 1>
# Underscores and percent signs have special meaning in the underlying
# database library, but Django handles the quoting of them automatically.
# SQL code, but Django handles the quoting of them automatically.
>>> a8 = Article(headline='Article_ with underscore', pub_date=datetime(2005, 11, 20))
>>> a8.save()
>>> Article.objects.filter(headline__startswith='Article')
[<Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>]
>>> Article.objects.filter(headline__startswith='Article_')
[<Article: Article_ with underscore>]
>>> a9 = Article(headline='Article% with percent sign', pub_date=datetime(2005, 11, 21))
>>> a9.save()
>>> Article.objects.filter(headline__startswith='Article')
@ -182,4 +183,12 @@ DoesNotExist: Article matching query does not exist.
[<Article: Article% with percent sign>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>]
>>> Article.objects.exclude(headline="Article 7")
[<Article: Article% with percent sign>, <Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 1>]
# Backslashes also have special meaning in the underlying SQL code, but Django
# automatically quotes them appropriately.
>>> a10 = Article(headline='Article with \\ backslash', pub_date=datetime(2005, 11, 22))
>>> a10.save()
>>> Article.objects.filter(headline__contains='\\')
[<Article: Article with \ backslash>]
"""

View File

@ -231,6 +231,9 @@ False
>>> time(datetime.time(13), "h")
'01'
>>> time(datetime.time(0), "h")
'12'
# real testing is done in timesince.py, where we can provide our own 'now'
>>> timesince(datetime.datetime.now() - datetime.timedelta(1))
'1 day'