mirror of
https://github.com/django/django.git
synced 2025-07-05 02:09:13 +00:00
i18n: merged to [1025] from trunk
git-svn-id: http://code.djangoproject.com/svn/django/branches/i18n@1027 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
commit
63651e8a81
@ -19,6 +19,7 @@ ACTION_MAPPING = {
|
|||||||
'init': management.init,
|
'init': management.init,
|
||||||
'inspectdb': management.inspectdb,
|
'inspectdb': management.inspectdb,
|
||||||
'install': management.install,
|
'install': management.install,
|
||||||
|
'installperms': management.installperms,
|
||||||
'runserver': management.runserver,
|
'runserver': management.runserver,
|
||||||
'sql': management.get_sql_create,
|
'sql': management.get_sql_create,
|
||||||
'sqlall': management.get_sql_all,
|
'sqlall': management.get_sql_all,
|
||||||
@ -32,7 +33,7 @@ ACTION_MAPPING = {
|
|||||||
'validate': management.validate,
|
'validate': management.validate,
|
||||||
}
|
}
|
||||||
|
|
||||||
NO_SQL_TRANSACTION = ('adminindex', 'createcachetable', 'dbcheck', 'install', 'sqlindexes')
|
NO_SQL_TRANSACTION = ('adminindex', 'createcachetable', 'dbcheck', 'install', 'installperms', 'sqlindexes')
|
||||||
|
|
||||||
def get_usage():
|
def get_usage():
|
||||||
"""
|
"""
|
||||||
|
@ -83,8 +83,8 @@ TEMPLATE_FILE_EXTENSION = '.html'
|
|||||||
# See the comments in django/core/template/loader.py for interface
|
# See the comments in django/core/template/loader.py for interface
|
||||||
# documentation.
|
# documentation.
|
||||||
TEMPLATE_LOADERS = (
|
TEMPLATE_LOADERS = (
|
||||||
# 'django.core.template.loaders.app_directories.load_template_source',
|
|
||||||
'django.core.template.loaders.filesystem.load_template_source',
|
'django.core.template.loaders.filesystem.load_template_source',
|
||||||
|
'django.core.template.loaders.app_directories.load_template_source',
|
||||||
# 'django.core.template.loaders.eggs.load_template_source',
|
# 'django.core.template.loaders.eggs.load_template_source',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ function URLify(s, num_chars) {
|
|||||||
s = s.replace(r, '');
|
s = s.replace(r, '');
|
||||||
s = s.replace(/[^\w\s-]/g, ''); // remove unneeded chars
|
s = s.replace(/[^\w\s-]/g, ''); // remove unneeded chars
|
||||||
s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces
|
s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces
|
||||||
s = s.replace(/\s+/g, '_'); // convert spaces to underscores
|
s = s.replace(/\s+/g, '-'); // convert spaces to hyphens
|
||||||
s = s.toLowerCase(); // convert to lowercase
|
s = s.toLowerCase(); // convert to lowercase
|
||||||
return s.substring(0, num_chars);// trim to first num_chars chars
|
return s.substring(0, num_chars);// trim to first num_chars chars
|
||||||
}
|
}
|
@ -288,9 +288,9 @@ DATA_TYPE_MAPPING = {
|
|||||||
|
|
||||||
def get_readable_field_data_type(field):
|
def get_readable_field_data_type(field):
|
||||||
# ForeignKey is a special case. Use the field type of the relation.
|
# ForeignKey is a special case. Use the field type of the relation.
|
||||||
if field.__class__.__name__ == 'ForeignKey':
|
if field.get_internal_type() == 'ForeignKey':
|
||||||
field = field.rel.get_related_field()
|
field = field.rel.get_related_field()
|
||||||
return DATA_TYPE_MAPPING[field.__class__.__name__] % field.__dict__
|
return DATA_TYPE_MAPPING[field.get_internal_type()] % field.__dict__
|
||||||
|
|
||||||
def extract_views_from_urlpatterns(urlpatterns, base=''):
|
def extract_views_from_urlpatterns(urlpatterns, base=''):
|
||||||
"""
|
"""
|
||||||
|
@ -556,8 +556,8 @@ def _get_template(opts, app_label, add=False, change=False, show_delete=False, f
|
|||||||
if not seen_collapse and 'collapse' in options.get('classes', ''):
|
if not seen_collapse and 'collapse' in options.get('classes', ''):
|
||||||
seen_collapse = True
|
seen_collapse = True
|
||||||
javascript_imports.append('%sjs/admin/CollapsedFieldsets.js' % ADMIN_MEDIA_PREFIX)
|
javascript_imports.append('%sjs/admin/CollapsedFieldsets.js' % ADMIN_MEDIA_PREFIX)
|
||||||
try:
|
|
||||||
for field_list in options['fields']:
|
for field_list in options['fields']:
|
||||||
|
try:
|
||||||
for f in field_list:
|
for f in field_list:
|
||||||
if f.rel and isinstance(f, meta.ManyToManyField) and f.rel.filter_interface:
|
if f.rel and isinstance(f, meta.ManyToManyField) and f.rel.filter_interface:
|
||||||
javascript_imports.extend(['%sjs/SelectBox.js' % ADMIN_MEDIA_PREFIX, '%sjs/SelectFilter2.js' % ADMIN_MEDIA_PREFIX])
|
javascript_imports.extend(['%sjs/SelectBox.js' % ADMIN_MEDIA_PREFIX, '%sjs/SelectFilter2.js' % ADMIN_MEDIA_PREFIX])
|
||||||
|
@ -13,7 +13,9 @@ settings.CACHE_BACKEND and use that to create and load a cache object.
|
|||||||
The CACHE_BACKEND setting is a quasi-URI; examples are:
|
The CACHE_BACKEND setting is a quasi-URI; examples are:
|
||||||
|
|
||||||
memcached://127.0.0.1:11211/ A memcached backend; the server is running
|
memcached://127.0.0.1:11211/ A memcached backend; the server is running
|
||||||
on localhost port 11211.
|
on localhost port 11211. You can use
|
||||||
|
multiple memcached servers by separating
|
||||||
|
them with semicolons.
|
||||||
|
|
||||||
db://tablename/ A database backend in a table named
|
db://tablename/ A database backend in a table named
|
||||||
"tablename". This table should be created
|
"tablename". This table should be created
|
||||||
@ -134,7 +136,7 @@ else:
|
|||||||
"Memcached cache backend."
|
"Memcached cache backend."
|
||||||
def __init__(self, server, params):
|
def __init__(self, server, params):
|
||||||
_Cache.__init__(self, params)
|
_Cache.__init__(self, params)
|
||||||
self._cache = memcache.Client([server])
|
self._cache = memcache.Client(server.split(';'))
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
val = self._cache.get(key)
|
val = self._cache.get(key)
|
||||||
|
@ -215,6 +215,7 @@ class FormField:
|
|||||||
####################
|
####################
|
||||||
|
|
||||||
class TextField(FormField):
|
class TextField(FormField):
|
||||||
|
input_type = "text"
|
||||||
def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=[]):
|
def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=[]):
|
||||||
self.field_name = field_name
|
self.field_name = field_name
|
||||||
self.length, self.maxlength = length, maxlength
|
self.length, self.maxlength = length, maxlength
|
||||||
@ -237,8 +238,8 @@ class TextField(FormField):
|
|||||||
maxlength = 'maxlength="%s" ' % self.maxlength
|
maxlength = 'maxlength="%s" ' % self.maxlength
|
||||||
if isinstance(data, unicode):
|
if isinstance(data, unicode):
|
||||||
data = data.encode(DEFAULT_CHARSET)
|
data = data.encode(DEFAULT_CHARSET)
|
||||||
return '<input type="text" id="%s" class="v%s%s" name="%s" size="%s" value="%s" %s/>' % \
|
return '<input type="%s" id="%s" class="v%s%s" name="%s" size="%s" value="%s" %s/>' % \
|
||||||
(FORM_FIELD_ID_PREFIX + self.field_name, self.__class__.__name__, self.is_required and ' required' or '',
|
(self.input_type, FORM_FIELD_ID_PREFIX + self.field_name, self.__class__.__name__, self.is_required and ' required' or '',
|
||||||
self.field_name, self.length, escape(data), maxlength)
|
self.field_name, self.length, escape(data), maxlength)
|
||||||
|
|
||||||
def html2python(data):
|
def html2python(data):
|
||||||
@ -246,11 +247,7 @@ class TextField(FormField):
|
|||||||
html2python = staticmethod(html2python)
|
html2python = staticmethod(html2python)
|
||||||
|
|
||||||
class PasswordField(TextField):
|
class PasswordField(TextField):
|
||||||
def render(self, data):
|
input_type = "password"
|
||||||
# value is always blank because we never want to redisplay it
|
|
||||||
return '<input type="password" id="%s" class="v%s%s" name="%s" value="" />' % \
|
|
||||||
(FORM_FIELD_ID_PREFIX + self.field_name, self.__class__.__name__, self.is_required and ' required' or '',
|
|
||||||
self.field_name)
|
|
||||||
|
|
||||||
class LargeTextField(TextField):
|
class LargeTextField(TextField):
|
||||||
def __init__(self, field_name, rows=10, cols=40, is_required=False, validator_list=[], maxlength=None):
|
def __init__(self, field_name, rows=10, cols=40, is_required=False, validator_list=[], maxlength=None):
|
||||||
|
@ -48,6 +48,9 @@ class BaseHandler:
|
|||||||
from django.core.mail import mail_admins
|
from django.core.mail import mail_admins
|
||||||
from django.conf.settings import DEBUG, INTERNAL_IPS, ROOT_URLCONF
|
from django.conf.settings import DEBUG, INTERNAL_IPS, ROOT_URLCONF
|
||||||
|
|
||||||
|
# Reset query list per request.
|
||||||
|
db.db.queries = []
|
||||||
|
|
||||||
# Apply request middleware
|
# Apply request middleware
|
||||||
for middleware_method in self._request_middleware:
|
for middleware_method in self._request_middleware:
|
||||||
response = middleware_method(request)
|
response = middleware_method(request)
|
||||||
|
@ -345,6 +345,27 @@ The full error: %s\n""" % \
|
|||||||
install.help_doc = "Executes ``sqlall`` for the given model module name(s) in the current database."
|
install.help_doc = "Executes ``sqlall`` for the given model module name(s) in the current database."
|
||||||
install.args = APP_ARGS
|
install.args = APP_ARGS
|
||||||
|
|
||||||
|
def installperms(mod):
|
||||||
|
"Installs any permissions for the given model, if needed."
|
||||||
|
from django.models.auth import permissions
|
||||||
|
from django.models.core import packages
|
||||||
|
num_added = 0
|
||||||
|
package = packages.get_object(pk=mod._MODELS[0]._meta.app_label)
|
||||||
|
for klass in mod._MODELS:
|
||||||
|
opts = klass._meta
|
||||||
|
for codename, name in _get_all_permissions(opts):
|
||||||
|
try:
|
||||||
|
permissions.get_object(name__exact=name, codename__exact=codename, package__label__exact=package.label)
|
||||||
|
except permissions.PermissionDoesNotExist:
|
||||||
|
p = permissions.Permission(name=name, package=package, codename=codename)
|
||||||
|
p.save()
|
||||||
|
print "Added permission '%r'." % p
|
||||||
|
num_added += 1
|
||||||
|
if not num_added:
|
||||||
|
print "No permissions were added, because all necessary permissions were already installed."
|
||||||
|
installperms.help_doc = "Installs any permissions for the given model module name(s), if needed."
|
||||||
|
installperms.args = APP_ARGS
|
||||||
|
|
||||||
def _start_helper(app_or_project, name, directory, other_name=''):
|
def _start_helper(app_or_project, name, directory, other_name=''):
|
||||||
other = {'project': 'app', 'app': 'project'}[app_or_project]
|
other = {'project': 'app', 'app': 'project'}[app_or_project]
|
||||||
if not _is_valid_dir_name(name):
|
if not _is_valid_dir_name(name):
|
||||||
|
@ -24,15 +24,15 @@ def fix_ampersands(value, _):
|
|||||||
|
|
||||||
def floatformat(text, _):
|
def floatformat(text, _):
|
||||||
"""
|
"""
|
||||||
Displays a floating point number as 34.2 (with one decimal place) - but
|
Displays a floating point number as 34.2 (with one decimal place) -- but
|
||||||
only if there's a point to be displayed
|
only if there's a point to be displayed
|
||||||
"""
|
"""
|
||||||
from math import modf
|
f = float(text)
|
||||||
if not text:
|
m = f - int(f)
|
||||||
return ''
|
if m:
|
||||||
if modf(float(text))[0] < 0.1:
|
return '%.1f' % f
|
||||||
return text
|
else:
|
||||||
return "%.1f" % float(text)
|
return '%d' % int(f)
|
||||||
|
|
||||||
def linenumbers(value, _):
|
def linenumbers(value, _):
|
||||||
"Displays text with line numbers"
|
"Displays text with line numbers"
|
||||||
@ -175,7 +175,7 @@ def removetags(value, tags):
|
|||||||
"Removes a space separated list of [X]HTML tags from the output"
|
"Removes a space separated list of [X]HTML tags from the output"
|
||||||
tags = [re.escape(tag) for tag in tags.split()]
|
tags = [re.escape(tag) for tag in tags.split()]
|
||||||
tags_re = '(%s)' % '|'.join(tags)
|
tags_re = '(%s)' % '|'.join(tags)
|
||||||
starttag_re = re.compile('<%s(>|(\s+[^>]*>))' % tags_re)
|
starttag_re = re.compile(r'<%s(/?>|(\s+[^>]*>))' % tags_re)
|
||||||
endtag_re = re.compile('</%s>' % tags_re)
|
endtag_re = re.compile('</%s>' % tags_re)
|
||||||
value = starttag_re.sub('', value)
|
value = starttag_re.sub('', value)
|
||||||
value = endtag_re.sub('', value)
|
value = endtag_re.sub('', value)
|
||||||
|
@ -37,6 +37,8 @@ def reloader_thread():
|
|||||||
mtimes = {}
|
mtimes = {}
|
||||||
while RUN_RELOADER:
|
while RUN_RELOADER:
|
||||||
for filename in filter(lambda v: v, map(lambda m: getattr(m, "__file__", None), sys.modules.values())) + reloadFiles:
|
for filename in filter(lambda v: v, map(lambda m: getattr(m, "__file__", None), sys.modules.values())) + reloadFiles:
|
||||||
|
if not os.path.exists(filename):
|
||||||
|
continue # File might be in an egg, so it can't be reloaded.
|
||||||
if filename.endswith(".pyc"):
|
if filename.endswith(".pyc"):
|
||||||
filename = filename[:-1]
|
filename = filename[:-1]
|
||||||
mtime = os.stat(filename).st_mtime
|
mtime = os.stat(filename).st_mtime
|
||||||
|
@ -21,6 +21,45 @@ import datetime, md5, re
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import cache
|
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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def dictitem(s):
|
||||||
|
t = s.split('=',1)
|
||||||
|
if len(t) > 1:
|
||||||
|
return (t[0].lower().replace('-', '_'), t[1])
|
||||||
|
else:
|
||||||
|
return (t[0].lower().replace('-', '_'), True)
|
||||||
|
|
||||||
|
def dictvalue(t):
|
||||||
|
if t[1] == True:
|
||||||
|
return t[0]
|
||||||
|
else:
|
||||||
|
return t[0] + '=' + str(t[1])
|
||||||
|
|
||||||
|
if response.has_header('Cache-Control'):
|
||||||
|
print response['Cache-Control']
|
||||||
|
cc = cc_delim_re.split(response['Cache-Control'])
|
||||||
|
print cc
|
||||||
|
cc = dict([dictitem(el) for el in cc])
|
||||||
|
else:
|
||||||
|
cc = {}
|
||||||
|
for (k,v) in kwargs.items():
|
||||||
|
cc[k.replace('_', '-')] = v
|
||||||
|
cc = ', '.join([dictvalue(el) for el in cc.items()])
|
||||||
|
response['Cache-Control'] = cc
|
||||||
|
|
||||||
vary_delim_re = re.compile(r',\s*')
|
vary_delim_re = re.compile(r',\s*')
|
||||||
|
|
||||||
def patch_response_headers(response, cache_timeout=None):
|
def patch_response_headers(response, cache_timeout=None):
|
||||||
@ -43,8 +82,7 @@ def patch_response_headers(response, cache_timeout=None):
|
|||||||
response['Last-Modified'] = now.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
response['Last-Modified'] = now.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
||||||
if not response.has_header('Expires'):
|
if not response.has_header('Expires'):
|
||||||
response['Expires'] = expires.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
response['Expires'] = expires.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
||||||
if not response.has_header('Cache-Control'):
|
patch_cache_control(response, max_age=cache_timeout)
|
||||||
response['Cache-Control'] = 'max-age=%d' % cache_timeout
|
|
||||||
|
|
||||||
def patch_vary_headers(response, newheaders):
|
def patch_vary_headers(response, newheaders):
|
||||||
"""
|
"""
|
||||||
|
@ -1,19 +1,22 @@
|
|||||||
def user_passes_test(view_func, test_func):
|
def user_passes_test(test_func):
|
||||||
"""
|
"""
|
||||||
Decorator for views that checks that the user passes the given test,
|
Decorator for views that checks that the user passes the given test,
|
||||||
redirecting to the log-in page if necessary. The test should be a callable
|
redirecting to the log-in page if necessary. The test should be a callable
|
||||||
that takes the user object and returns True if the user passes.
|
that takes the user object and returns True if the user passes.
|
||||||
"""
|
"""
|
||||||
from django.views.auth.login import redirect_to_login
|
def _dec(view_func):
|
||||||
def _checklogin(request, *args, **kwargs):
|
def _checklogin(request, *args, **kwargs):
|
||||||
|
from django.views.auth.login import redirect_to_login
|
||||||
if test_func(request.user):
|
if test_func(request.user):
|
||||||
return view_func(request, *args, **kwargs)
|
return view_func(request, *args, **kwargs)
|
||||||
return redirect_to_login(request.path)
|
return redirect_to_login(request.path)
|
||||||
return _checklogin
|
return _checklogin
|
||||||
|
return _dec
|
||||||
|
|
||||||
def login_required(view_func):
|
login_required = user_passes_test(lambda u: not u.is_anonymous())
|
||||||
|
login_required.__doc__ = (
|
||||||
"""
|
"""
|
||||||
Decorator for views that checks that the user is logged in, redirecting
|
Decorator for views that checks that the user is logged in, redirecting
|
||||||
to the log-in page if necessary.
|
to the log-in page if necessary.
|
||||||
"""
|
"""
|
||||||
return user_passes_test(lambda u: not u.is_anonymous())
|
)
|
||||||
|
@ -10,8 +10,24 @@ example, as that is unique across a Django project.
|
|||||||
Additionally, all headers from the response's Vary header will be taken into
|
Additionally, all headers from the response's Vary header will be taken into
|
||||||
account on caching -- just like the middleware does.
|
account on caching -- just like the middleware does.
|
||||||
"""
|
"""
|
||||||
|
import re
|
||||||
|
|
||||||
from django.utils.decorators import decorator_from_middleware
|
from django.utils.decorators import decorator_from_middleware
|
||||||
|
from django.utils.cache import patch_cache_control
|
||||||
from django.middleware.cache import CacheMiddleware
|
from django.middleware.cache import CacheMiddleware
|
||||||
|
|
||||||
cache_page = decorator_from_middleware(CacheMiddleware)
|
cache_page = decorator_from_middleware(CacheMiddleware)
|
||||||
|
|
||||||
|
def cache_control(**kwargs):
|
||||||
|
|
||||||
|
def _cache_controller(viewfunc):
|
||||||
|
|
||||||
|
def _cache_controlled(request, *args, **kw):
|
||||||
|
response = viewfunc(request, *args, **kw)
|
||||||
|
patch_cache_control(response, **kwargs)
|
||||||
|
return response
|
||||||
|
|
||||||
|
return _cache_controlled
|
||||||
|
|
||||||
|
return _cache_controller
|
||||||
|
|
||||||
|
@ -1,9 +1,35 @@
|
|||||||
"""
|
"""
|
||||||
Decorator for views that supports conditional get on ETag and Last-Modified
|
Decorators for views based on HTTP headers.
|
||||||
headers.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.utils.decorators import decorator_from_middleware
|
from django.utils.decorators import decorator_from_middleware
|
||||||
from django.middleware.http import ConditionalGetMiddleware
|
from django.middleware.http import ConditionalGetMiddleware
|
||||||
|
from django.utils.httpwrappers import HttpResponseForbidden
|
||||||
|
|
||||||
conditional_page = decorator_from_middleware(ConditionalGetMiddleware)
|
conditional_page = decorator_from_middleware(ConditionalGetMiddleware)
|
||||||
|
|
||||||
|
def require_http_methods(request_method_list):
|
||||||
|
"""
|
||||||
|
Decorator to make a view only accept particular request methods. Usage::
|
||||||
|
|
||||||
|
@require_http_methods(["GET", "POST"])
|
||||||
|
def my_view(request):
|
||||||
|
# I can assume now that only GET or POST requests make it this far
|
||||||
|
# ...
|
||||||
|
|
||||||
|
Note that request methods ARE case sensitive.
|
||||||
|
"""
|
||||||
|
def decorator(func):
|
||||||
|
def inner(request, *args, **kwargs):
|
||||||
|
method = request.META.get("REQUEST_METHOD", None)
|
||||||
|
if method not in request_method_list:
|
||||||
|
raise HttpResponseForbidden("REQUEST_METHOD '%s' not allowed" % method)
|
||||||
|
return func(request, *args, **kwargs)
|
||||||
|
return inner
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
require_GET = require_http_methods(["GET"])
|
||||||
|
require_GET.__doc__ = "Decorator to require that a view only accept the GET method."
|
||||||
|
|
||||||
|
require_POST = require_http_methods(["POST"])
|
||||||
|
require_POST.__doc__ = "Decorator to require that a view only accept the POST method."
|
@ -1,10 +1,11 @@
|
|||||||
from django.core.exceptions import Http404, ObjectDoesNotExist
|
from django.core.exceptions import Http404, ObjectDoesNotExist
|
||||||
from django.core.template import Context, loader
|
from django.core.template import Context, loader
|
||||||
from django.models.core import sites
|
from django.models.core import sites, contenttypes
|
||||||
from django.utils import httpwrappers
|
from django.utils import httpwrappers
|
||||||
|
|
||||||
def shortcut(request, content_type_id, object_id):
|
def shortcut(request, content_type_id, object_id):
|
||||||
from django.models.core import contenttypes
|
"""Redirect to an object's page based on a content-type ID and an object ID"""
|
||||||
|
# Look up the object, making sure it's got a get_absolute_url() function.
|
||||||
try:
|
try:
|
||||||
content_type = contenttypes.get_object(pk=content_type_id)
|
content_type = contenttypes.get_object(pk=content_type_id)
|
||||||
obj = content_type.get_object_for_this_type(pk=object_id)
|
obj = content_type.get_object_for_this_type(pk=object_id)
|
||||||
@ -14,25 +15,37 @@ def shortcut(request, content_type_id, object_id):
|
|||||||
absurl = obj.get_absolute_url()
|
absurl = obj.get_absolute_url()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise Http404, "%s objects don't have get_absolute_url() methods" % content_type.name
|
raise Http404, "%s objects don't have get_absolute_url() methods" % content_type.name
|
||||||
|
|
||||||
|
# Try to figure out the object's domain so we can do a cross-site redirect
|
||||||
|
# if necessary
|
||||||
|
|
||||||
|
# If the object actually defines a domain, we're done.
|
||||||
if absurl.startswith('http://'):
|
if absurl.startswith('http://'):
|
||||||
return httpwrappers.HttpResponseRedirect(absurl)
|
return httpwrappers.HttpResponseRedirect(absurl)
|
||||||
|
|
||||||
object_domain = None
|
object_domain = None
|
||||||
|
|
||||||
|
# Next, look for an many-to-many relationship to sites
|
||||||
if hasattr(obj, 'get_site_list'):
|
if hasattr(obj, 'get_site_list'):
|
||||||
site_list = obj.get_site_list()
|
site_list = obj.get_site_list()
|
||||||
if site_list:
|
if site_list:
|
||||||
object_domain = site_list[0].domain
|
object_domain = site_list[0].domain
|
||||||
|
|
||||||
|
# Next, look for a many-to-one relationship to sites
|
||||||
elif hasattr(obj, 'get_site'):
|
elif hasattr(obj, 'get_site'):
|
||||||
try:
|
try:
|
||||||
object_domain = obj.get_site().domain
|
object_domain = obj.get_site().domain
|
||||||
except sites.SiteDoesNotExist:
|
except sites.SiteDoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Then, fall back to the current site (if possible)
|
||||||
|
else:
|
||||||
try:
|
try:
|
||||||
object_domain = sites.get_current().domain
|
object_domain = sites.get_current().domain
|
||||||
except sites.SiteDoesNotExist:
|
except sites.SiteDoesNotExist:
|
||||||
pass
|
# Finally, give up and use a URL without the domain name
|
||||||
if not object_domain:
|
return httpwrappers.HttpResponseRedirect(obj.get_absolute_url())
|
||||||
return httpwrappers.HttpResponseRedirect(absurl)
|
return httpwrappers.HttpResponseRedirect('http://%s%s' % (object_domain, obj.get_absolute_url()))
|
||||||
return httpwrappers.HttpResponseRedirect('http://%s%s' % (object_domain, absurl))
|
|
||||||
|
|
||||||
def page_not_found(request):
|
def page_not_found(request):
|
||||||
"""
|
"""
|
||||||
|
@ -29,7 +29,9 @@ Examples:
|
|||||||
CACHE_BACKEND Explanation
|
CACHE_BACKEND Explanation
|
||||||
============================== ===========================================
|
============================== ===========================================
|
||||||
memcached://127.0.0.1:11211/ A memcached backend; the server is running
|
memcached://127.0.0.1:11211/ A memcached backend; the server is running
|
||||||
on localhost port 11211.
|
on localhost port 11211. You can use
|
||||||
|
multiple memcached servers by separating
|
||||||
|
them with semicolons.
|
||||||
|
|
||||||
db://tablename/ A database backend in a table named
|
db://tablename/ A database backend in a table named
|
||||||
"tablename". This table should be created
|
"tablename". This table should be created
|
||||||
@ -270,6 +272,40 @@ 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
|
.. _`HTTP Vary headers`: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44
|
||||||
|
|
||||||
|
Controlling cache: Using Vary 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.
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
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::
|
||||||
|
|
||||||
|
@cache_control(private=True, must_revalidate=True, max_age=3600)
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
.. _`HTTP Cache-Control headers`: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
|
||||||
|
|
||||||
Other optimizations
|
Other optimizations
|
||||||
===================
|
===================
|
||||||
|
|
||||||
|
@ -621,6 +621,14 @@ the relationship should work. All are optional:
|
|||||||
vertically).
|
vertically).
|
||||||
|
|
||||||
``limit_choices_to`` See the description under ``ForeignKey`` above.
|
``limit_choices_to`` See the description under ``ForeignKey`` above.
|
||||||
|
|
||||||
|
``singular`` The singular name of the field. Use to name the ``get_*``
|
||||||
|
methods: in the example above, Django gives the ``Pizza``
|
||||||
|
objects a ``get_topping_list()`` method, where ``topping``
|
||||||
|
is the default ``singular`` value derived from the lowercase
|
||||||
|
version of the class being linked to. Use the singular
|
||||||
|
parameter to change this, which is if you want one model to
|
||||||
|
have multiple ``ManyToMany`` relationships to another model.
|
||||||
======================= ============================================================
|
======================= ============================================================
|
||||||
|
|
||||||
One-to-one relationships
|
One-to-one relationships
|
||||||
@ -750,11 +758,12 @@ Here's a list of all possible ``META`` options. No options are required. Adding
|
|||||||
``permissions``
|
``permissions``
|
||||||
Extra permissions to enter into the permissions table when creating this
|
Extra permissions to enter into the permissions table when creating this
|
||||||
object. Add, delete and change permissions are automatically created for
|
object. Add, delete and change permissions are automatically created for
|
||||||
each object. This option specifies extra permissions::
|
each object that has ``admin`` set. This example specifies an extra
|
||||||
|
permission, ``can_deliver_pizzas``::
|
||||||
|
|
||||||
permissions = (("can_deliver_pizzas", "Can deliver pizzas"),)
|
permissions = (("can_deliver_pizzas", "Can deliver pizzas"),)
|
||||||
|
|
||||||
This is a list of 2-tuples of
|
This is a list or tuple of 2-tuples in the format
|
||||||
``(permission_code, human_readable_permission_name)``.
|
``(permission_code, human_readable_permission_name)``.
|
||||||
|
|
||||||
``unique_together``
|
``unique_together``
|
||||||
|
20
tests/othertests/defaultfilters.py
Normal file
20
tests/othertests/defaultfilters.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
"""
|
||||||
|
>>> floatformat(7.7, None)
|
||||||
|
'7.7'
|
||||||
|
>>> floatformat(7.0, None)
|
||||||
|
'7'
|
||||||
|
>>> floatformat(0.7, None)
|
||||||
|
'0.7'
|
||||||
|
>>> floatformat(0.07, None)
|
||||||
|
'0.1'
|
||||||
|
>>> floatformat(0.007, None)
|
||||||
|
'0.0'
|
||||||
|
>>> floatformat(0.0, None)
|
||||||
|
'0'
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.core.template.defaultfilters import *
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import doctest
|
||||||
|
doctest.testmod()
|
Loading…
x
Reference in New Issue
Block a user