mirror of
https://github.com/django/django.git
synced 2025-07-03 17:29:12 +00:00
i18n: merged to [1054] of trunk
git-svn-id: http://code.djangoproject.com/svn/django/branches/i18n@1067 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
commit
e27211a0de
@ -1,16 +1,11 @@
|
||||
"""
|
||||
This is the core database connection.
|
||||
|
||||
All CMS code assumes database SELECT statements cast the resulting values as such:
|
||||
All Django code assumes database SELECT statements cast the resulting values as such:
|
||||
* booleans are mapped to Python booleans
|
||||
* dates are mapped to Python datetime.date objects
|
||||
* times are mapped to Python datetime.time objects
|
||||
* timestamps are mapped to Python datetime.datetime objects
|
||||
|
||||
Right now, we're handling this by using psycopg's custom typecast definitions.
|
||||
If we move to a different database module, we should ensure that it either
|
||||
performs the appropriate typecasting out of the box, or that it has hooks that
|
||||
let us do that.
|
||||
"""
|
||||
|
||||
from django.conf.settings import DATABASE_ENGINE
|
||||
@ -41,6 +36,7 @@ get_limit_offset_sql = dbmod.get_limit_offset_sql
|
||||
get_random_function_sql = dbmod.get_random_function_sql
|
||||
get_table_list = dbmod.get_table_list
|
||||
get_relations = dbmod.get_relations
|
||||
quote_name = dbmod.quote_name
|
||||
OPERATOR_MAPPING = dbmod.OPERATOR_MAPPING
|
||||
DATA_TYPES = dbmod.DATA_TYPES
|
||||
DATA_TYPES_REVERSE = dbmod.DATA_TYPES_REVERSE
|
||||
|
@ -110,6 +110,10 @@ def get_table_list(cursor):
|
||||
def get_relations(cursor, table_name):
|
||||
raise NotImplementedError
|
||||
|
||||
def quote_name(name):
|
||||
# TODO: Figure out how MS-SQL quotes database identifiers.
|
||||
return name
|
||||
|
||||
OPERATOR_MAPPING = {
|
||||
'exact': '=',
|
||||
'iexact': 'LIKE',
|
||||
|
@ -122,18 +122,23 @@ def get_table_list(cursor):
|
||||
def get_relations(cursor, table_name):
|
||||
raise NotImplementedError
|
||||
|
||||
def quote_name(name):
|
||||
if name.startswith("`") and name.endswith("`"):
|
||||
return name # Quoting once is enough.
|
||||
return "`%s`" % name
|
||||
|
||||
OPERATOR_MAPPING = {
|
||||
'exact': '=',
|
||||
'iexact': 'LIKE',
|
||||
'contains': 'LIKE',
|
||||
'contains': 'LIKE BINARY',
|
||||
'icontains': 'LIKE',
|
||||
'ne': '!=',
|
||||
'gt': '>',
|
||||
'gte': '>=',
|
||||
'lt': '<',
|
||||
'lte': '<=',
|
||||
'startswith': 'LIKE',
|
||||
'endswith': 'LIKE',
|
||||
'startswith': 'LIKE BINARY',
|
||||
'endswith': 'LIKE BINARY',
|
||||
'istartswith': 'LIKE',
|
||||
'iendswith': 'LIKE',
|
||||
}
|
||||
|
@ -116,6 +116,11 @@ def get_relations(cursor, table_name):
|
||||
continue
|
||||
return relations
|
||||
|
||||
def quote_name(name):
|
||||
if name.startswith('"') and name.endswith('"'):
|
||||
return name # Quoting once is enough.
|
||||
return '"%s"' % name
|
||||
|
||||
# Register these custom typecasts, because Django expects dates/times to be
|
||||
# in Python's native (standard-library) datetime/time format, whereas psycopg
|
||||
# use mx.DateTime by default.
|
||||
|
@ -124,6 +124,11 @@ def get_table_list(cursor):
|
||||
def get_relations(cursor, table_name):
|
||||
raise NotImplementedError
|
||||
|
||||
def quote_name(name):
|
||||
if name.startswith('"') and name.endswith('"'):
|
||||
return name # Quoting once is enough.
|
||||
return '"%s"' % name
|
||||
|
||||
# Operators and fields ########################################################
|
||||
|
||||
OPERATOR_MAPPING = {
|
||||
|
@ -27,7 +27,10 @@ def floatformat(text, _):
|
||||
Displays a floating point number as 34.2 (with one decimal place) -- but
|
||||
only if there's a point to be displayed
|
||||
"""
|
||||
f = float(text)
|
||||
try:
|
||||
f = float(text)
|
||||
except ValueError:
|
||||
return ''
|
||||
m = f - int(f)
|
||||
if m:
|
||||
return '%.1f' % f
|
||||
|
@ -214,8 +214,12 @@ class SsiNode(Node):
|
||||
self.filepath, self.parsed = filepath, parsed
|
||||
|
||||
def render(self, context):
|
||||
from django.conf.settings import DEBUG
|
||||
if not include_is_allowed(self.filepath):
|
||||
return '' # Fail silently for invalid includes.
|
||||
if DEBUG:
|
||||
return "[Didn't have permission to include file]"
|
||||
else:
|
||||
return '' # Fail silently for invalid includes.
|
||||
try:
|
||||
fp = open(self.filepath, 'r')
|
||||
output = fp.read()
|
||||
@ -226,8 +230,11 @@ class SsiNode(Node):
|
||||
try:
|
||||
t = Template(output)
|
||||
return t.render(context)
|
||||
except TemplateSyntaxError:
|
||||
return '' # Fail silently for invalid included templates.
|
||||
except (TemplateSyntaxError, e):
|
||||
if DEBUG:
|
||||
return "[Included template had syntax error: %s]" % e
|
||||
else:
|
||||
return '' # Fail silently for invalid included templates.
|
||||
return output
|
||||
|
||||
class LoadNode(Node):
|
||||
|
@ -71,6 +71,7 @@ class SessionMiddleware:
|
||||
session_key = request.session.session_key or sessions.get_new_session_key()
|
||||
new_session = sessions.save(session_key, request.session._session,
|
||||
datetime.datetime.now() + datetime.timedelta(seconds=SESSION_COOKIE_AGE))
|
||||
expires = datetime.datetime.strftime(datetime.datetime.utcnow() + datetime.timedelta(seconds=SESSION_COOKIE_AGE), "%a, %d-%b-%Y %H:%M:%S GMT")
|
||||
response.set_cookie(SESSION_COOKIE_NAME, session_key,
|
||||
max_age=SESSION_COOKIE_AGE, domain=SESSION_COOKIE_DOMAIN)
|
||||
max_age=SESSION_COOKIE_AGE, expires=expires, domain=SESSION_COOKIE_DOMAIN)
|
||||
return response
|
||||
|
@ -22,19 +22,19 @@ from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
|
||||
cc_delim_re = re.compile(r'\s*,\s*')
|
||||
|
||||
def patch_cache_control(response, **kwargs):
|
||||
"""
|
||||
This function patches the Cache-Control header by adding all
|
||||
keyword arguments to it. The transformation is as follows:
|
||||
|
||||
- all keyword parameter names are turned to lowercase and
|
||||
all _ will be translated to -
|
||||
- if the value of a parameter is True (exatly True, not just a
|
||||
true value), only the parameter name is added to the header
|
||||
- all other parameters are added with their value, after applying
|
||||
str to it.
|
||||
* All keyword parameter names are turned to lowercase, and underscores
|
||||
are converted to hyphens.
|
||||
* If the value of a parameter is True (exactly True, not just a
|
||||
true value), only the parameter name is added to the header.
|
||||
* All other parameters are added with their value, after applying
|
||||
str() to it.
|
||||
"""
|
||||
|
||||
def dictitem(s):
|
||||
t = s.split('=',1)
|
||||
if len(t) > 1:
|
||||
|
@ -172,9 +172,9 @@ class HttpResponse:
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_cookie(self, key, value='', max_age=None, path='/', domain=None, secure=None):
|
||||
def set_cookie(self, key, value='', max_age=None, expires=None, path='/', domain=None, secure=None):
|
||||
self.cookies[key] = value
|
||||
for var in ('max_age', 'path', 'domain', 'secure'):
|
||||
for var in ('max_age', 'path', 'domain', 'secure', 'expires'):
|
||||
val = locals()[var]
|
||||
if val is not None:
|
||||
self.cookies[key][var.replace('_', '-')] = val
|
||||
|
@ -272,39 +272,64 @@ and a list/tuple of header names as its second argument.
|
||||
|
||||
.. _`HTTP Vary headers`: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44
|
||||
|
||||
Controlling cache: Using Vary headers
|
||||
=====================================
|
||||
Controlling cache: Using other headers
|
||||
======================================
|
||||
|
||||
Another problem with caching is the privacy of data, and the question where data can
|
||||
be stored in a cascade of caches. A user usually faces two kinds of caches: his own
|
||||
browser cache (a private cache) and his providers cache (a public cache). A public cache
|
||||
is used by multiple users and controlled by someone else. This poses problems with private
|
||||
(in the sense of sensitive) data - you don't want your social security number or your
|
||||
banking account numbers stored in some public cache. So web applications need a way
|
||||
to tell the caches what data is private and what is public.
|
||||
Another problem with caching is the privacy of data and the question of where
|
||||
data should be stored in a cascade of caches.
|
||||
|
||||
Other aspects are the definition how long a page should be cached at max, or wether the
|
||||
cache should allways check for newer versions and only deliver the cache content when
|
||||
there were no changes (some caches might deliver cached content even if the server page
|
||||
changed - just because the cache copy isn't yet expired).
|
||||
A user usually faces two kinds of caches: his own browser cache (a private
|
||||
cache) and his provider's cache (a public cache). A public cache is used by
|
||||
multiple users and controlled by someone else. This poses problems with
|
||||
sensitive data: You don't want, say, your banking-account number stored in a
|
||||
public cache. So Web applications need a way to tell caches which data is
|
||||
private and which is public.
|
||||
|
||||
So there are a multitude of options you can control for your pages. This is where the
|
||||
Cache-Control header (more infos in `HTTP Cache-Control headers`_) comes in. The usage
|
||||
is quite simple::
|
||||
The solution is to indicate a page's cache should be "private." To do this in
|
||||
Django, use the ``cache_control`` view decorator. Example::
|
||||
|
||||
@cache_control(private=True, must_revalidate=True, max_age=3600)
|
||||
from django.views.decorators.cache import cache_control
|
||||
@cache_control(private=True)
|
||||
def my_view(request):
|
||||
...
|
||||
|
||||
This would define the view as private, to be revalidated on every access and cache
|
||||
copies will only be stored for 3600 seconds at max.
|
||||
This decorator takes care of sending out the appropriate HTTP header behind the
|
||||
scenes.
|
||||
|
||||
The caching middleware already set's this header up with a max-age of the CACHE_MIDDLEWARE_SETTINGS
|
||||
setting. And the cache_page decorator does the same. The cache_control decorator correctly merges
|
||||
different values into one big header, though. But you should take into account that middlewares
|
||||
might overwrite some of your headers or set their own defaults if you don't give that header yourself.
|
||||
There are a few other ways to control cache parameters. For example, HTTP
|
||||
allows applications to do the following:
|
||||
|
||||
.. _`HTTP Cache-Control headers`: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
|
||||
* Define the maximum time a page should be cached.
|
||||
* Specify whether a cache should always check for newer versions, only
|
||||
delivering the cached content when there are no changes. (Some caches
|
||||
might deliver cached content even if the server page changed -- simply
|
||||
because the cache copy isn't yet expired.)
|
||||
|
||||
In Django, use the ``cache_control`` view decorator to specify these cache
|
||||
parameters. In this example, ``cache_control`` tells caches to revalidate the
|
||||
cache on every access and to store cached versions for, at most, 3600 seconds::
|
||||
|
||||
from django.views.decorators.cache import cache_control
|
||||
@cache_control(must_revalidate=True, max_age=3600)
|
||||
def my_view(request):
|
||||
...
|
||||
|
||||
Any valid ``Cache-Control`` directive is valid in ``cache_control()``. For a
|
||||
full list, see the `Cache-Control spec`_. Just pass the directives as keyword
|
||||
arguments to ``cache_control()``, substituting underscores for hyphens. For
|
||||
directives that don't take an argument, set the argument to ``True``.
|
||||
|
||||
Examples:
|
||||
|
||||
* ``@cache_control(max_age=3600)`` turns into ``max-age=3600``.
|
||||
* ``@cache_control(public=True)`` turns into ``public``.
|
||||
|
||||
(Note that the caching middleware already sets the cache header's max-age with
|
||||
the value of the ``CACHE_MIDDLEWARE_SETTINGS`` setting. If you use a custom
|
||||
``max_age`` in a ``cache_control`` decorator, the decorator will take
|
||||
precedence, and the header values will be merged correctly.)
|
||||
|
||||
.. _`Cache-Control spec`: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
|
||||
|
||||
Other optimizations
|
||||
===================
|
||||
|
@ -161,9 +161,9 @@ The DB API supports the following lookup types:
|
||||
``foo``, ``FOO``, ``fOo``, etc.
|
||||
contains Case-sensitive containment test:
|
||||
``polls.get_list(question__contains="spam")`` returns all polls
|
||||
that contain "spam" in the question. (PostgreSQL only. MySQL
|
||||
doesn't support case-sensitive LIKE statements; ``contains``
|
||||
will act like ``icontains`` for MySQL.)
|
||||
that contain "spam" in the question. (PostgreSQL and MySQL
|
||||
only. SQLite doesn't support case-sensitive LIKE statements;
|
||||
``contains`` will act like ``icontains`` for SQLite.)
|
||||
icontains Case-insensitive containment test.
|
||||
gt Greater than: ``polls.get_list(id__gt=4)``.
|
||||
gte Greater than or equal to.
|
||||
@ -174,11 +174,10 @@ The DB API supports the following lookup types:
|
||||
a list of polls whose IDs are either 1, 3 or 4.
|
||||
startswith Case-sensitive starts-with:
|
||||
``polls.get_list(question_startswith="Would")``. (PostgreSQL
|
||||
only. MySQL doesn't support case-sensitive LIKE statements;
|
||||
``startswith`` will act like ``istartswith`` for MySQL.)
|
||||
endswith Case-sensitive ends-with. (PostgreSQL only. MySQL doesn't
|
||||
support case-sensitive LIKE statements; ``endswith`` will act
|
||||
like ``iendswith`` for MySQL.)
|
||||
and MySQL only. SQLite doesn't support case-sensitive LIKE
|
||||
statements; ``startswith`` will act like ``istartswith`` for
|
||||
SQLite.)
|
||||
endswith Case-sensitive ends-with. (PostgreSQL and MySQL only.)
|
||||
istartswith Case-insensitive starts-with.
|
||||
iendswith Case-insensitive ends-with.
|
||||
range Range test:
|
||||
@ -240,6 +239,10 @@ so::
|
||||
|
||||
polls.get_list(order_by=['?'])
|
||||
|
||||
There's no way to specify whether ordering should be case sensitive. With
|
||||
respect to case-sensitivity, Django will order results however your database
|
||||
backend normally orders them.
|
||||
|
||||
Relationships (joins)
|
||||
=====================
|
||||
|
||||
|
@ -16,17 +16,22 @@ Give Django your database parameters
|
||||
|
||||
You'll need to tell Django what your database connection parameters are, and
|
||||
what the name of the database is. Do that by editing these settings in your
|
||||
settings file:
|
||||
`settings file`_:
|
||||
|
||||
* ``DATABASE_ENGINE``
|
||||
* ``DATABASE_USER``
|
||||
* ``DATABASE_PASSWORD``
|
||||
* ``DATABASE_NAME``
|
||||
* ``DATABASE_HOST``
|
||||
* `DATABASE_ENGINE`_
|
||||
* `DATABASE_USER`_
|
||||
* `DATABASE_PASSWORD`_
|
||||
* `DATABASE_NAME`_
|
||||
* `DATABASE_HOST`_
|
||||
* `DATABASE_PORT`_
|
||||
|
||||
For more information on these settings see `Tutorial 1`_.
|
||||
|
||||
.. _Tutorial 1: http://www.djangoproject.com/documentation/tutorial1/
|
||||
.. _settings file: http://www.djangoproject.com/documentation/settings/
|
||||
.. _DATABASE_ENGINE: http://www.djangoproject.com/documentation/settings/#database-engine
|
||||
.. _DATABASE_USER: http://www.djangoproject.com/documentation/settings/#database-user
|
||||
.. _DATABASE_PASSWORD: http://www.djangoproject.com/documentation/settings/#database-password
|
||||
.. _DATABASE_NAME: http://www.djangoproject.com/documentation/settings/#database-name
|
||||
.. _DATABASE_HOST: http://www.djangoproject.com/documentation/settings/#database-host
|
||||
.. _DATABASE_PORT: http://www.djangoproject.com/documentation/settings/#database-port
|
||||
|
||||
Auto-generate the models
|
||||
========================
|
||||
@ -72,7 +77,6 @@ following names:
|
||||
* ``auth_groups``
|
||||
* ``auth_users``
|
||||
* ``auth_messages``
|
||||
* ``auth_admin_log``
|
||||
* ``auth_groups_permissions``
|
||||
* ``auth_users_groups``
|
||||
* ``auth_users_user_permissions``
|
||||
|
@ -284,12 +284,14 @@ Methods
|
||||
Returns ``True`` or ``False`` based on a case-insensitive check for a
|
||||
header with the given name.
|
||||
|
||||
``set_cookie(key, value='', max_age=None, path='/', domain=None, secure=None)``
|
||||
``set_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=None)``
|
||||
Sets a cookie. The parameters are the same as in the `cookie Morsel`_
|
||||
object in the Python standard library.
|
||||
|
||||
* ``max_age`` should be a number of seconds, or ``None`` (default) if
|
||||
the cookie should last only as long as the client's browser session.
|
||||
* ``expires`` should be a string in the format
|
||||
``"Wdy, DD-Mon-YY HH:MM:SS GMT"``.
|
||||
* Use ``domain`` if you want to set a cross-domain cookie. For example,
|
||||
``domain=".lawrence.com"`` will set a cookie that is readable by
|
||||
the domains www.lawrence.com, blogs.lawrence.com and
|
||||
|
@ -158,6 +158,39 @@ This is necessary because the dictionary is stored in an encoded format::
|
||||
>>> s.get_decoded()
|
||||
{'user_id': 42}
|
||||
|
||||
Session cookies
|
||||
===============
|
||||
|
||||
A few `Django settings`_ give you control over the session cookie:
|
||||
|
||||
SESSION_COOKIE_AGE
|
||||
------------------
|
||||
|
||||
Default: ``1209600`` (2 weeks, in seconds)
|
||||
|
||||
The age of session cookies, in seconds.
|
||||
|
||||
SESSION_COOKIE_DOMAIN
|
||||
---------------------
|
||||
|
||||
Default: ``None``
|
||||
|
||||
The domain to use for session cookies. Set this to a string such as
|
||||
``".lawrence.com"`` for cross-domain cookies, or use ``None`` for a standard
|
||||
domain cookie.
|
||||
|
||||
SESSION_COOKIE_NAME
|
||||
-------------------
|
||||
|
||||
Default: ``'hotclub'``
|
||||
|
||||
The name of the cookie to use for sessions. This can be whatever you want.
|
||||
|
||||
``'hotclub'`` is a reference to the Hot Club of France, the band Django
|
||||
Reinhardt played in.
|
||||
|
||||
.. _Django settings: http://www.djangoproject.com/documentation/settings/
|
||||
|
||||
Technical details
|
||||
=================
|
||||
|
||||
@ -170,3 +203,12 @@ Technical details
|
||||
data, it won't send a session cookie.
|
||||
|
||||
.. _`the pickle module`: http://www.python.org/doc/current/lib/module-pickle.html
|
||||
|
||||
Session IDs in URLs
|
||||
===================
|
||||
|
||||
The Django sessions framework is entirely, and solely, cookie-based. It does
|
||||
not fall back to putting session IDs in URLs as a last resort, as PHP does.
|
||||
This is an intentional design decision. Not only does that behavior make URLs
|
||||
ugly, it makes your site vulnerable to session-ID theft via the "Referer"
|
||||
header.
|
||||
|
@ -213,6 +213,9 @@ The generic views pass ``object`` and ``object_list`` to their templates, so
|
||||
change your templates so that ``latest_poll_list`` becomes ``object_list`` and
|
||||
``poll`` becomes ``object``.
|
||||
|
||||
In the ``vote()`` view, change the template call from ``polls/detail`` to
|
||||
``polls/polls_detail``, and pass ``object`` in the context instead of ``poll``.
|
||||
|
||||
Finally, you can delete the ``index()``, ``detail()`` and ``results()`` views
|
||||
from ``polls/views/polls.py``. We don't need them anymore.
|
||||
|
||||
|
@ -51,6 +51,17 @@ datetime.datetime(2005, 7, 28, 0, 0)
|
||||
<Article object>
|
||||
>>> articles.get_object(pub_date__year=2005)
|
||||
<Article object>
|
||||
>>> articles.get_object(pub_date__year=2005, pub_date__month=7)
|
||||
<Article object>
|
||||
>>> articles.get_object(pub_date__year=2005, pub_date__month=7, pub_date__day=28)
|
||||
<Article object>
|
||||
|
||||
>>> articles.get_list(pub_date__year=2005)
|
||||
[<Article object>]
|
||||
>>> articles.get_list(pub_date__year=2004)
|
||||
[]
|
||||
>>> articles.get_list(pub_date__year=2005, pub_date__month=7)
|
||||
[<Article object>]
|
||||
|
||||
# Django raises an ArticleDoesNotExist exception for get_object()
|
||||
>>> articles.get_object(id__exact=2)
|
||||
@ -58,6 +69,11 @@ Traceback (most recent call last):
|
||||
...
|
||||
ArticleDoesNotExist: Article does not exist for {'id__exact': 2}
|
||||
|
||||
>>> articles.get_object(pub_date__year=2005, pub_date__month=8)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ArticleDoesNotExist: Article does not exist for ...
|
||||
|
||||
# Lookup by a primary key is the most common case, so Django provides a
|
||||
# shortcut for primary-key exact lookups.
|
||||
# The following is identical to articles.get_object(id__exact=1).
|
||||
|
Loading…
x
Reference in New Issue
Block a user