mirror of
https://github.com/django/django.git
synced 2025-07-04 09:49:12 +00:00
[multi-db] Merge trunk to [3578]
git-svn-id: http://code.djangoproject.com/svn/django/branches/multiple-db-support@3581 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
238c6ecd5b
commit
bec235deef
3
AUTHORS
3
AUTHORS
@ -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/>
|
||||
@ -125,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
|
||||
|
@ -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))
|
||||
|
@ -255,6 +255,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.
|
||||
|
||||
|
@ -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 = (
|
||||
|
@ -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 %}
|
||||
|
@ -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 %}
|
||||
|
@ -21,7 +21,6 @@ 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'),
|
||||
|
@ -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+>).+?\)')
|
||||
|
@ -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))
|
||||
|
@ -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.
|
@ -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
|
||||
|
@ -110,9 +110,14 @@ def get_sql_create(app):
|
||||
sys.exit(1)
|
||||
|
||||
# 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).
|
||||
manager = model._default_manager
|
||||
tables = manager.get_table_list()
|
||||
installed_models = manager.get_installed_models(tables)
|
||||
installed_models = [ model for model in
|
||||
manager.get_installed_models(tables)
|
||||
if model not in app_models ]
|
||||
models_output = set(installed_models)
|
||||
builder = creation.builder
|
||||
builder.models_already_seen.update(models_output)
|
||||
@ -136,11 +141,14 @@ 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 pending_references.pop(model)])
|
||||
|
||||
alter_sql.extend(['-- ' + sql
|
||||
for sql in pending_references.pop(model)])
|
||||
if alter_sql:
|
||||
final_output.append('-- The following references should be added '
|
||||
'but depend on non-existent tables:')
|
||||
final_output.extend(alter_sql)
|
||||
# convert BoundStatements into strings
|
||||
final_output = map(str, final_output)
|
||||
return final_output
|
||||
@ -563,9 +571,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."
|
||||
@ -594,6 +600,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'
|
||||
@ -1010,7 +1020,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]'
|
||||
@ -1167,7 +1184,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.
|
||||
@ -1179,7 +1200,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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
@ -139,7 +139,7 @@ class SchemaBuilder(object):
|
||||
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,
|
||||
r_name = '%s_refs_%s_%x' % (col, r_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(r_name),
|
||||
@ -262,8 +262,10 @@ class SchemaBuilder(object):
|
||||
style.SQL_TABLE(qn(table)),
|
||||
style.SQL_KEYWORD(
|
||||
backend.get_drop_foreignkey_sql()),
|
||||
style.SQL_FIELD(qn("%s_referencing_%s_%s" %
|
||||
(col, r_table, r_col)))),
|
||||
style.SQL_FIELD(qn("%s_refs_%s_%x" %
|
||||
(col, r_col,
|
||||
abs(hash((table, r_table)))))
|
||||
)),
|
||||
db.connection))
|
||||
del references_to_delete[model]
|
||||
# many to many: drop any many-many tables that are my
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -180,11 +180,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" % \
|
||||
(qn(self._meta.db_table),
|
||||
','.join(['%s=%%s' % qn(f.column) for f in non_pks]),
|
||||
qn(self._meta.pk.column)),
|
||||
db_values + [pk_val])
|
||||
if db_values:
|
||||
cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
|
||||
(qn(self._meta.db_table),
|
||||
','.join(['%s=%%s' % qn(f.column) for f in non_pks]),
|
||||
qn(self._meta.pk.column)),
|
||||
db_values + [pk_val])
|
||||
else:
|
||||
record_exists = False
|
||||
if not pk_set or not record_exists:
|
||||
|
@ -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 '')
|
||||
|
@ -35,7 +35,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:
|
||||
@ -83,7 +83,7 @@ def get_models(app_mod=None, creation_order=False):
|
||||
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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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."
|
||||
|
@ -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:
|
||||
|
@ -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.
|
||||
|
||||
|
148
docs/documentation.txt
Normal file
148
docs/documentation.txt
Normal 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/
|
@ -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/``::
|
||||
|
@ -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``
|
||||
|
@ -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``
|
||||
|
@ -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
|
||||
-------------------------------
|
||||
|
||||
|
@ -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
|
||||
-------------------------------
|
||||
|
||||
|
@ -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.
|
||||
|
1
setup.py
1
setup.py
@ -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',
|
||||
|
@ -20,5 +20,7 @@ API_TESTS = """
|
||||
2
|
||||
>>> m.id is not None
|
||||
True
|
||||
>>> existing = Empty(m.id)
|
||||
>>> existing.save()
|
||||
|
||||
"""
|
||||
|
@ -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>]
|
||||
|
||||
"""
|
||||
|
@ -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'
|
||||
|
Loading…
x
Reference in New Issue
Block a user