1
0
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:
Georg Bauer 2005-11-03 21:29:48 +00:00
commit e27211a0de
17 changed files with 187 additions and 66 deletions

View File

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

View File

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

View File

@ -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',
}

View File

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

View File

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

View File

@ -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
"""
try:
f = float(text)
except ValueError:
return ''
m = f - int(f)
if m:
return '%.1f' % f

View File

@ -214,7 +214,11 @@ 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):
if DEBUG:
return "[Didn't have permission to include file]"
else:
return '' # Fail silently for invalid includes.
try:
fp = open(self.filepath, 'r')
@ -226,7 +230,10 @@ class SsiNode(Node):
try:
t = Template(output)
return t.render(context)
except TemplateSyntaxError:
except (TemplateSyntaxError, e):
if DEBUG:
return "[Included template had syntax error: %s]" % e
else:
return '' # Fail silently for invalid included templates.
return output

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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