1
0
mirror of https://github.com/django/django.git synced 2025-07-04 09:49:12 +00:00

boulder-oracle-sprint: Merged rest of package to trunk [4719]

git-svn-id: http://code.djangoproject.com/svn/django/branches/boulder-oracle-sprint@4722 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Boulder Sprinters 2007-03-13 15:40:41 +00:00
parent 429a542cec
commit ca343fc0ac
25 changed files with 1549 additions and 914 deletions

View File

@ -85,6 +85,7 @@ answer newbie questions, and generally made Django that much better:
Marc Fargas <telenieko@telenieko.com> Marc Fargas <telenieko@telenieko.com>
favo@exoweb.net favo@exoweb.net
Eric Floehr <eric@intellovations.com> Eric Floehr <eric@intellovations.com>
Jorge Gajon <gajon@gajon.org>
gandalf@owca.info gandalf@owca.info
Baishampayan Ghose Baishampayan Ghose
martin.glueck@gmail.com martin.glueck@gmail.com

View File

@ -81,7 +81,7 @@ def make_messages():
src = pythonize_re.sub('\n#', src) src = pythonize_re.sub('\n#', src)
open(os.path.join(dirpath, '%s.py' % file), "wb").write(src) open(os.path.join(dirpath, '%s.py' % file), "wb").write(src)
thefile = '%s.py' % file thefile = '%s.py' % file
cmd = 'xgettext %s -d %s -L Perl --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy -o - "%s"' % ( cmd = 'xgettext %s -d %s -L Perl --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy --from-code UTF-8 -o - "%s"' % (
os.path.exists(potfile) and '--omit-header' or '', domain, os.path.join(dirpath, thefile)) os.path.exists(potfile) and '--omit-header' or '', domain, os.path.join(dirpath, thefile))
(stdin, stdout, stderr) = os.popen3(cmd, 'b') (stdin, stdout, stderr) = os.popen3(cmd, 'b')
msgs = stdout.read() msgs = stdout.read()
@ -103,7 +103,7 @@ def make_messages():
open(os.path.join(dirpath, '%s.py' % file), "wb").write(templatize(src)) open(os.path.join(dirpath, '%s.py' % file), "wb").write(templatize(src))
thefile = '%s.py' % file thefile = '%s.py' % file
if verbose: sys.stdout.write('processing file %s in %s\n' % (file, dirpath)) if verbose: sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
cmd = 'xgettext %s -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy -o - "%s"' % ( cmd = 'xgettext %s -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy --from-code UTF-8 -o - "%s"' % (
os.path.exists(potfile) and '--omit-header' or '', domain, os.path.join(dirpath, thefile)) os.path.exists(potfile) and '--omit-header' or '', domain, os.path.join(dirpath, thefile))
(stdin, stdout, stderr) = os.popen3(cmd, 'b') (stdin, stdout, stderr) = os.popen3(cmd, 'b')
msgs = stdout.read() msgs = stdout.read()

File diff suppressed because it is too large Load Diff

View File

@ -168,7 +168,7 @@ def model_detail(request, app_label, model_name):
model = m model = m
break break
if model is None: if model is None:
raise Http404, _("Model %r not found in app %r") % (model_name, app_label) raise Http404, _("Model %(name)r not found in app %(label)r") % {'name': model_name, 'label': app_label}
opts = model._meta opts = model._meta
@ -180,7 +180,7 @@ def model_detail(request, app_label, model_name):
if isinstance(field, models.ForeignKey): if isinstance(field, models.ForeignKey):
data_type = related_object_name = field.rel.to.__name__ data_type = related_object_name = field.rel.to.__name__
app_label = field.rel.to._meta.app_label 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 `%(label)s.%(type)s` object") % {'label': app_label, 'type': data_type}), 'model', _('model:') + data_type)
else: else:
data_type = get_readable_field_data_type(field) data_type = get_readable_field_data_type(field)
verbose = field.verbose_name verbose = field.verbose_name
@ -211,7 +211,7 @@ def model_detail(request, app_label, model_name):
# Gather related objects # Gather related objects
for rel in opts.get_all_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 `%(label)s.%(name)s` objects") % {'label': rel.opts.app_label, 'name': rel.opts.object_name}
accessor = rel.get_accessor_name() accessor = rel.get_accessor_name()
fields.append({ fields.append({
'name' : "%s.all" % accessor, 'name' : "%s.all" % accessor,

View File

@ -7,6 +7,7 @@ from django.db.models import get_apps, get_models, signals
def create_contenttypes(app, created_models, verbosity=2): def create_contenttypes(app, created_models, verbosity=2):
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
ContentType.objects.clear_cache()
app_models = get_models(app) app_models = get_models(app)
if not app_models: if not app_models:
return return

View File

@ -19,6 +19,16 @@ class ContentTypeManager(models.Manager):
model=key[1], defaults={'name': str(opts.verbose_name)}) model=key[1], defaults={'name': str(opts.verbose_name)})
CONTENT_TYPE_CACHE[key] = ct CONTENT_TYPE_CACHE[key] = ct
return ct return ct
def clear_cache(self):
"""
Clear out the content-type cache. This needs to happen during database
flushes to prevent caching of "stale" content type IDs (see
django.contrib.contenttypes.management.create_contenttypes for where
this gets called).
"""
global CONTENT_TYPE_CACHE
CONTENT_TYPE_CACHE = {}
class ContentType(models.Model): class ContentType(models.Model):
name = models.CharField(maxlength=100) name = models.CharField(maxlength=100)

View File

@ -1,3 +1,5 @@
from django.utils.translation import ngettext
from django.utils.translation import gettext_lazy as _
from django import template from django import template
import re import re
@ -12,9 +14,9 @@ def ordinal(value):
value = int(value) value = int(value)
except ValueError: except ValueError:
return value return value
t = ('th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th') t = (_('th'), _('st'), _('nd'), _('rd'), _('th'), _('th'), _('th'), _('th'), _('th'), _('th'))
if value % 100 in (11, 12, 13): # special case if value % 100 in (11, 12, 13): # special case
return '%dth' % value return "%d%s" % (value, t[0])
return '%d%s' % (value, t[value % 10]) return '%d%s' % (value, t[value % 10])
register.filter(ordinal) register.filter(ordinal)
@ -41,11 +43,14 @@ def intword(value):
if value < 1000000: if value < 1000000:
return value return value
if value < 1000000000: if value < 1000000000:
return '%.1f million' % (value / 1000000.0) new_value = value / 1000000.0
return ngettext('%(value).1f million', '%(value).1f million', new_value) % {'value': new_value}
if value < 1000000000000: if value < 1000000000000:
return '%.1f billion' % (value / 1000000000.0) new_value = value / 1000000000.0
return ngettext('%(value).1f billion', '%(value).1f billion', new_value) % {'value': new_value}
if value < 1000000000000000: if value < 1000000000000000:
return '%.1f trillion' % (value / 1000000000000.0) new_value = value / 1000000000000.0
return ngettext('%(value).1f trillion', '%(value).1f trillion', new_value) % {'value': new_value}
return value return value
register.filter(intword) register.filter(intword)
@ -60,5 +65,5 @@ def apnumber(value):
return value return value
if not 0 < value < 10: if not 0 < value < 10:
return value return value
return ('one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine')[value-1] return (_('one'), _('two'), _('three'), _('four'), _('five'), _('six'), _('seven'), _('eight'), _('nine'))[value-1]
register.filter(apnumber) register.filter(apnumber)

View File

@ -1463,7 +1463,7 @@ def dump_data(app_labels, format='json', indent=None):
for model in get_models(app): for model in get_models(app):
objects.extend(model.objects.all()) objects.extend(model.objects.all())
try: try:
print serializers.serialize(format, objects, indent=indent) return serializers.serialize(format, objects, indent=indent)
except Exception, e: except Exception, e:
sys.stderr.write(style.ERROR("Unable to serialize database: %s\n" % e)) sys.stderr.write(style.ERROR("Unable to serialize database: %s\n" % e))
dump_data.help_doc = 'Output the contents of the database as a fixture of the given format' dump_data.help_doc = 'Output the contents of the database as a fixture of the given format'
@ -1609,7 +1609,7 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
parser.print_usage_and_exit() parser.print_usage_and_exit()
elif action == 'dumpdata': elif action == 'dumpdata':
try: try:
action_mapping[action](args[1:], options.format, options.indent) print action_mapping[action](args[1:], options.format, options.indent)
except IndexError: except IndexError:
parser.print_usage_and_exit() parser.print_usage_and_exit()
elif action in ('startapp', 'startproject'): elif action in ('startapp', 'startproject'):

View File

@ -25,6 +25,13 @@ BUILTIN_SERIALIZERS = {
"json" : "django.core.serializers.json", "json" : "django.core.serializers.json",
} }
# Check for PyYaml and register the serializer if it's available.
try:
import yaml
BUILTIN_SERIALIZERS["yaml"] = "django.core.serializers.pyyaml"
except ImportError:
pass
_serializers = {} _serializers = {}
def register_serializer(format, serializer_module): def register_serializer(format, serializer_module):

View File

@ -54,11 +54,7 @@ class Serializer(object):
Convert a field's value to a string. Convert a field's value to a string.
""" """
if isinstance(field, models.DateTimeField): if isinstance(field, models.DateTimeField):
value = getattr(obj, field.name) value = getattr(obj, field.name).strftime("%Y-%m-%d %H:%M:%S")
if value is None:
value = ''
else:
value = value.strftime("%Y-%m-%d %H:%M:%S")
elif isinstance(field, models.FileField): elif isinstance(field, models.FileField):
value = getattr(obj, "get_%s_url" % field.name, lambda: None)() value = getattr(obj, "get_%s_url" % field.name, lambda: None)()
else: else:

View File

@ -57,7 +57,7 @@ def Deserializer(object_list, **options):
for d in object_list: for d in object_list:
# Look up the model and starting build a dict of data for it. # Look up the model and starting build a dict of data for it.
Model = _get_model(d["model"]) Model = _get_model(d["model"])
data = {Model._meta.pk.attname : d["pk"]} data = {Model._meta.pk.attname : Model._meta.pk.to_python(d["pk"])}
m2m_data = {} m2m_data = {}
# Handle each field # Handle each field
@ -70,16 +70,17 @@ def Deserializer(object_list, **options):
# Handle M2M relations # Handle M2M relations
if field.rel and isinstance(field.rel, models.ManyToManyRel): if field.rel and isinstance(field.rel, models.ManyToManyRel):
pks = [] pks = []
m2m_convert = field.rel.to._meta.pk.to_python
for pk in field_value: for pk in field_value:
if isinstance(pk, unicode): if isinstance(pk, unicode):
pks.append(pk.encode(options.get("encoding", settings.DEFAULT_CHARSET))) pks.append(m2m_convert(pk.encode(options.get("encoding", settings.DEFAULT_CHARSET))))
else: else:
pks.append(pk) pks.append(m2m_convert(pk))
m2m_data[field.name] = pks m2m_data[field.name] = pks
# Handle FK fields # Handle FK fields
elif field.rel and isinstance(field.rel, models.ManyToOneRel): elif field.rel and isinstance(field.rel, models.ManyToOneRel):
data[field.attname] = field_value data[field.attname] = field.rel.to._meta.pk.to_python(field_value)
# Handle all other fields # Handle all other fields
else: else:

View File

@ -0,0 +1,36 @@
"""
YAML serializer.
Requires PyYaml (http://pyyaml.org/), but that's checked for in __init__.
"""
import datetime
from django.core.serializers.python import Serializer as PythonSerializer
from django.core.serializers.python import Deserializer as PythonDeserializer
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
import yaml
class Serializer(PythonSerializer):
"""
Convert a queryset to JSON.
"""
def end_serialization(self):
yaml.dump(self.objects, self.stream, **self.options)
def getvalue(self):
return self.stream.getvalue()
def Deserializer(stream_or_string, **options):
"""
Deserialize a stream or string of JSON data.
"""
if isinstance(stream_or_string, basestring):
stream = StringIO(stream_or_string)
else:
stream = stream_or_string
for obj in PythonDeserializer(yaml.load(stream)):
yield obj

View File

@ -57,10 +57,12 @@ class Serializer(base.Serializer):
}) })
# Get a "string version" of the object's data (this is handled by the # Get a "string version" of the object's data (this is handled by the
# serializer base class). None is handled specially. # serializer base class).
value = self.get_string_value(obj, field) if getattr(obj, field.name) is not None:
if value is not None: value = self.get_string_value(obj, field)
self.xml.characters(str(value)) self.xml.characters(str(value))
else:
self.xml.addQuickElement("None")
self.xml.endElement("field") self.xml.endElement("field")
@ -127,7 +129,8 @@ class Deserializer(base.Deserializer):
pk = node.getAttribute("pk") pk = node.getAttribute("pk")
if not pk: if not pk:
raise base.DeserializationError("<object> node is missing the 'pk' attribute") raise base.DeserializationError("<object> node is missing the 'pk' attribute")
data = {Model._meta.pk.name : pk}
data = {Model._meta.pk.attname : Model._meta.pk.to_python(pk)}
# Also start building a dict of m2m data (this is saved as # Also start building a dict of m2m data (this is saved as
# {m2m_accessor_attribute : [list_of_related_objects]}) # {m2m_accessor_attribute : [list_of_related_objects]})
@ -148,17 +151,20 @@ class Deserializer(base.Deserializer):
# As is usually the case, relation fields get the special treatment. # As is usually the case, relation fields get the special treatment.
if field.rel and isinstance(field.rel, models.ManyToManyRel): if field.rel and isinstance(field.rel, models.ManyToManyRel):
m2m_data[field.name] = self._handle_m2m_field_node(field_node) m2m_data[field.name] = self._handle_m2m_field_node(field_node, field)
elif field.rel and isinstance(field.rel, models.ManyToOneRel): elif field.rel and isinstance(field.rel, models.ManyToOneRel):
data[field.attname] = self._handle_fk_field_node(field_node) data[field.attname] = self._handle_fk_field_node(field_node, field)
else: else:
value = field.to_python(getInnerText(field_node).strip().encode(self.encoding)) if len(field_node.childNodes) == 1 and field_node.childNodes[0].nodeName == 'None':
value = None
else:
value = field.to_python(getInnerText(field_node).strip().encode(self.encoding))
data[field.name] = value data[field.name] = value
# Return a DeserializedObject so that the m2m data has a place to live. # Return a DeserializedObject so that the m2m data has a place to live.
return base.DeserializedObject(Model(**data), m2m_data) return base.DeserializedObject(Model(**data), m2m_data)
def _handle_fk_field_node(self, node): def _handle_fk_field_node(self, node, field):
""" """
Handle a <field> node for a ForeignKey Handle a <field> node for a ForeignKey
""" """
@ -166,13 +172,16 @@ class Deserializer(base.Deserializer):
if len(node.childNodes) == 1 and node.childNodes[0].nodeName == 'None': if len(node.childNodes) == 1 and node.childNodes[0].nodeName == 'None':
return None return None
else: else:
return getInnerText(node).strip().encode(self.encoding) return field.rel.to._meta.pk.to_python(
getInnerText(node).strip().encode(self.encoding))
def _handle_m2m_field_node(self, node): def _handle_m2m_field_node(self, node, field):
""" """
Handle a <field> node for a ManyToManyField Handle a <field> node for a ManyToManyField
""" """
return [c.getAttribute("pk").encode(self.encoding) for c in node.getElementsByTagName("object")] return [field.rel.to._meta.pk.to_python(
c.getAttribute("pk").encode(self.encoding))
for c in node.getElementsByTagName("object")]
def _get_model_from_node(self, node, attr): def _get_model_from_node(self, node, attr):
""" """

View File

@ -140,7 +140,8 @@ def _isValidDate(date_string):
try: try:
date(year, month, day) date(year, month, day)
except ValueError, e: except ValueError, e:
raise ValidationError, gettext('Invalid date: %s.' % e) msg = gettext('Invalid date: %s') % gettext(str(e))
raise ValidationError, msg
def isValidANSIDate(field_data, all_data): def isValidANSIDate(field_data, all_data):
if not ansi_date_re.search(field_data): if not ansi_date_re.search(field_data):
@ -363,7 +364,7 @@ class NumberIsInRange(object):
self.lower, self.upper = lower, upper self.lower, self.upper = lower, upper
if not error_message: if not error_message:
if lower and upper: if lower and upper:
self.error_message = gettext("This value must be between %s and %s.") % (lower, upper) self.error_message = gettext("This value must be between %(lower)s and %(upper)s.") % {'lower': lower, 'upper': upper}
elif lower: elif lower:
self.error_message = gettext("This value must be at least %s.") % lower self.error_message = gettext("This value must be at least %s.") % lower
elif upper: elif upper:

View File

@ -762,6 +762,13 @@ class NullBooleanField(Field):
kwargs['null'] = True kwargs['null'] = True
Field.__init__(self, *args, **kwargs) Field.__init__(self, *args, **kwargs)
def to_python(self, value):
if value in (None, True, False): return value
if value in ('None'): return None
if value in ('t', 'True', '1'): return True
if value in ('f', 'False', '0'): return False
raise validators.ValidationError, gettext("This value must be either None, True or False.")
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):
return [oldforms.NullBooleanField] return [oldforms.NullBooleanField]

View File

@ -16,7 +16,7 @@ class RelatedObject(object):
self.opts = model._meta self.opts = model._meta
self.field = field self.field = field
self.edit_inline = field.rel.edit_inline self.edit_inline = field.rel.edit_inline
self.name = '%s_%s' % (self.opts.app_label, self.opts.module_name) self.name = '%s:%s' % (self.opts.app_label, self.opts.module_name)
self.var_name = self.opts.object_name.lower() self.var_name = self.opts.object_name.lower()
def flatten_data(self, follow, obj=None): def flatten_data(self, follow, obj=None):

View File

@ -130,7 +130,9 @@ class FormWrapper(object):
if self.edit_inline: if self.edit_inline:
self.fill_inline_collections() self.fill_inline_collections()
for inline_collection in self._inline_collections: for inline_collection in self._inline_collections:
if inline_collection.name == key: # The 'orig_name' comparison is for backwards compatibility
# with hand-crafted forms.
if inline_collection.name == key or (':' not in key and inline_collection.orig_name == key):
return inline_collection return inline_collection
raise KeyError, "Could not find Formfield or InlineObjectCollection named %r" % key raise KeyError, "Could not find Formfield or InlineObjectCollection named %r" % key
@ -226,6 +228,9 @@ class InlineObjectCollection(object):
self.errors = errors self.errors = errors
self._collections = None self._collections = None
self.name = rel_obj.name self.name = rel_obj.name
# This is the name used prior to fixing #1839. Needs for backwards
# compatibility.
self.orig_name = rel_obj.opts.module_name
def __len__(self): def __len__(self):
self.fill() self.fill()

View File

@ -70,14 +70,15 @@ def floatformat(text, arg=-1):
With a negative numeric argument, it will display that many decimal With a negative numeric argument, it will display that many decimal
places -- but only if there's places to be displayed. places -- but only if there's places to be displayed.
Examples: Examples:
num1 = 34.23234
num2 = 34.00000 * num1 = 34.23234
num1|floatformat results in 34.2 * num2 = 34.00000
num2|floatformat is 34 * num1|floatformat results in 34.2
num1|floatformat:3 is 34.232 * num2|floatformat is 34
num2|floatformat:3 is 34.000 * num1|floatformat:3 is 34.232
num1|floatformat:-3 is 34.232 * num2|floatformat:3 is 34.000
num2|floatformat:-3 is 34 * num1|floatformat:-3 is 34.232
* num2|floatformat:-3 is 34
""" """
try: try:
f = float(text) f = float(text)

View File

@ -435,6 +435,15 @@ def cycle(parser, token):
cycle = register.tag(cycle) cycle = register.tag(cycle)
def debug(parser, token): def debug(parser, token):
"""
Output a whole load of debugging information, including the current context and imported modules.
Sample usage::
<pre>
{% debug %}
</pre>
"""
return DebugNode() return DebugNode()
debug = register.tag(debug) debug = register.tag(debug)
@ -538,21 +547,6 @@ def do_for(parser, token):
do_for = register.tag("for", do_for) do_for = register.tag("for", do_for)
def do_ifequal(parser, token, negate): def do_ifequal(parser, token, negate):
"""
Output the contents of the block if the two arguments equal/don't equal each other.
Examples::
{% ifequal user.id comment.user_id %}
...
{% endifequal %}
{% ifnotequal user.id comment.user_id %}
...
{% else %}
...
{% endifnotequal %}
"""
bits = list(token.split_contents()) bits = list(token.split_contents())
if len(bits) != 3: if len(bits) != 3:
raise TemplateSyntaxError, "%r takes two arguments" % bits[0] raise TemplateSyntaxError, "%r takes two arguments" % bits[0]
@ -568,11 +562,27 @@ def do_ifequal(parser, token, negate):
#@register.tag #@register.tag
def ifequal(parser, token): def ifequal(parser, token):
"""
Output the contents of the block if the two arguments equal each other.
Examples::
{% ifequal user.id comment.user_id %}
...
{% endifequal %}
{% ifnotequal user.id comment.user_id %}
...
{% else %}
...
{% endifnotequal %}
"""
return do_ifequal(parser, token, False) return do_ifequal(parser, token, False)
ifequal = register.tag(ifequal) ifequal = register.tag(ifequal)
#@register.tag #@register.tag
def ifnotequal(parser, token): def ifnotequal(parser, token):
"""Output the contents of the block if the two arguments are not equal. See ifequal"""
return do_ifequal(parser, token, True) return do_ifequal(parser, token, True)
ifnotequal = register.tag(ifnotequal) ifnotequal = register.tag(ifnotequal)
@ -889,8 +899,9 @@ templatetag = register.tag(templatetag)
def url(parser, token): def url(parser, token):
""" """
Returns an absolute URL matching given view with its parameters. This is a Returns an absolute URL matching given view with its parameters.
way to define links that aren't tied to a particular url configuration:
This is a way to define links that aren't tied to a particular url configuration::
{% url path.to.some_view arg1,arg2,name1=value1 %} {% url path.to.some_view arg1,arg2,name1=value1 %}
@ -901,16 +912,16 @@ def url(parser, token):
URL. All arguments for the URL should be present. URL. All arguments for the URL should be present.
For example if you have a view ``app_name.client`` taking client's id and For example if you have a view ``app_name.client`` taking client's id and
the corresponding line in a urlconf looks like this: the corresponding line in a urlconf looks like this::
('^client/(\d+)/$', 'app_name.client') ('^client/(\d+)/$', 'app_name.client')
and this app's urlconf is included into the project's urlconf under some and this app's urlconf is included into the project's urlconf under some
path: path::
('^clients/', include('project_name.app_name.urls')) ('^clients/', include('project_name.app_name.urls'))
then in a template you can create a link for a certain client like this: then in a template you can create a link for a certain client like this::
{% url app_name.client client.id %} {% url app_name.client client.id %}

View File

@ -13,6 +13,7 @@ Usage:
from django.utils.dates import MONTHS, MONTHS_3, MONTHS_AP, WEEKDAYS from django.utils.dates import MONTHS, MONTHS_3, MONTHS_AP, WEEKDAYS
from django.utils.tzinfo import LocalTimezone from django.utils.tzinfo import LocalTimezone
from django.utils.translation import gettext as _
from calendar import isleap, monthrange from calendar import isleap, monthrange
import re, time import re, time
@ -36,14 +37,14 @@ class TimeFormat(Formatter):
def a(self): def a(self):
"'a.m.' or 'p.m.'" "'a.m.' or 'p.m.'"
if self.data.hour > 11: if self.data.hour > 11:
return 'p.m.' return _('p.m.')
return 'a.m.' return _('a.m.')
def A(self): def A(self):
"'AM' or 'PM'" "'AM' or 'PM'"
if self.data.hour > 11: if self.data.hour > 11:
return 'PM' return _('PM')
return 'AM' return _('AM')
def B(self): def B(self):
"Swatch Internet time" "Swatch Internet time"
@ -91,9 +92,9 @@ class TimeFormat(Formatter):
Proprietary extension. Proprietary extension.
""" """
if self.data.minute == 0 and self.data.hour == 0: if self.data.minute == 0 and self.data.hour == 0:
return 'midnight' return _('midnight')
if self.data.minute == 0 and self.data.hour == 12: if self.data.minute == 0 and self.data.hour == 12:
return 'noon' return _('noon')
return '%s %s' % (self.f(), self.a()) return '%s %s' % (self.f(), self.a())
def s(self): def s(self):

View File

@ -9,16 +9,16 @@ def set_language(request):
""" """
Redirect to a given url while setting the chosen language in the Redirect to a given url while setting the chosen language in the
session or cookie. The url and the language code need to be session or cookie. The url and the language code need to be
specified in the GET paramters. specified in the GET parameters.
""" """
lang_code = request.GET['language'] lang_code = request.GET.get('language', None)
next = request.GET.get('next', None) next = request.GET.get('next', None)
if not next: if not next:
next = request.META.get('HTTP_REFERER', None) next = request.META.get('HTTP_REFERER', None)
if not next: if not next:
next = '/' next = '/'
response = http.HttpResponseRedirect(next) response = http.HttpResponseRedirect(next)
if check_for_language(lang_code): if lang_code and check_for_language(lang_code):
if hasattr(request, 'session'): if hasattr(request, 'session'):
request.session['django_language'] = lang_code request.session['django_language'] = lang_code
else: else:

View File

@ -304,3 +304,14 @@ If you have access to a command shell on a Unix system, you can accomplish this
easily by using the ``touch`` command:: easily by using the ``touch`` command::
touch mysite.fcgi touch mysite.fcgi
Serving admin media files
=========================
Regardless of the server and configuration you eventually decide to use, you will
also need to give some thought to how to serve the admin media files. The
advice given in the modpython_ documentation is also applicable in the setups
detailed above.
.. _modpython: ../modpython/#serving-the-admin-files

View File

@ -417,6 +417,27 @@ Here's a simple function that might drive the above form::
form = forms.FormWrapper(manipulator, new_data, errors) form = forms.FormWrapper(manipulator, new_data, errors)
return render_to_response('contact_form.html', {'form': form}) return render_to_response('contact_form.html', {'form': form})
Implementing ``flatten_data`` for custom manipulators
------------------------------------------------------
It is possible (although rarely needed) to replace the default automatically
created manipulators on a model with your own custom manipulators. If you do
this and you are intending to use those models in generic views, you should
also define a ``flatten_data`` method in any ``ChangeManipulator`` replacement.
This should act like the default ``flatten_data`` and return a dictionary
mapping field names to their values, like so::
def flatten_data(self):
obj = self.original_object
return dict(
from = obj.from,
subject = obj.subject,
...
)
In this way, your new change manipulator will act exactly like the default
version.
``FileField`` and ``ImageField`` special cases ``FileField`` and ``ImageField`` special cases
============================================== ==============================================

View File

@ -282,6 +282,17 @@ How to create language files
Once you've tagged your strings for later translation, you need to write (or Once you've tagged your strings for later translation, you need to write (or
obtain) the language translations themselves. Here's how that works. obtain) the language translations themselves. Here's how that works.
.. admonition:: Locale restrictions
Django does not support localising your application into a locale for
which Django itself has not been translated -- it will ignore your
translation files. If you were to try this and Django supported it, you
would inevitably see a mixture of translated strings (from your
application) and English strings (from Django itself). If you are wanting
to support a locale for your application that is not already part of
Django, you will need to make at least a minimal translation of the Django
core.
Message files Message files
------------- -------------