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>
favo@exoweb.net
Eric Floehr <eric@intellovations.com>
Jorge Gajon <gajon@gajon.org>
gandalf@owca.info
Baishampayan Ghose
martin.glueck@gmail.com

View File

@ -81,7 +81,7 @@ def make_messages():
src = pythonize_re.sub('\n#', src)
open(os.path.join(dirpath, '%s.py' % file), "wb").write(src)
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))
(stdin, stdout, stderr) = os.popen3(cmd, 'b')
msgs = stdout.read()
@ -103,7 +103,7 @@ def make_messages():
open(os.path.join(dirpath, '%s.py' % file), "wb").write(templatize(src))
thefile = '%s.py' % file
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))
(stdin, stdout, stderr) = os.popen3(cmd, 'b')
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
break
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
@ -180,7 +180,7 @@ def model_detail(request, app_label, model_name):
if isinstance(field, models.ForeignKey):
data_type = related_object_name = field.rel.to.__name__
app_label = field.rel.to._meta.app_label
verbose = utils.parse_rst((_("the related `%s.%s` object") % (app_label, data_type)), 'model', _('model:') + data_type)
verbose = utils.parse_rst((_("the related `%(label)s.%(type)s` object") % {'label': app_label, 'type': data_type}), 'model', _('model:') + data_type)
else:
data_type = get_readable_field_data_type(field)
verbose = field.verbose_name
@ -211,7 +211,7 @@ def model_detail(request, app_label, model_name):
# Gather related objects
for rel in opts.get_all_related_objects():
verbose = _("related `%s.%s` objects") % (rel.opts.app_label, rel.opts.object_name)
verbose = _("related `%(label)s.%(name)s` objects") % {'label': rel.opts.app_label, 'name': rel.opts.object_name}
accessor = rel.get_accessor_name()
fields.append({
'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):
from django.contrib.contenttypes.models import ContentType
ContentType.objects.clear_cache()
app_models = get_models(app)
if not app_models:
return

View File

@ -20,6 +20,16 @@ class ContentTypeManager(models.Manager):
CONTENT_TYPE_CACHE[key] = 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):
name = models.CharField(maxlength=100)
app_label = 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
import re
@ -12,9 +14,9 @@ def ordinal(value):
value = int(value)
except ValueError:
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
return '%dth' % value
return "%d%s" % (value, t[0])
return '%d%s' % (value, t[value % 10])
register.filter(ordinal)
@ -41,11 +43,14 @@ def intword(value):
if value < 1000000:
return value
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:
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:
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
register.filter(intword)
@ -60,5 +65,5 @@ def apnumber(value):
return value
if not 0 < value < 10:
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)

View File

@ -1463,7 +1463,7 @@ def dump_data(app_labels, format='json', indent=None):
for model in get_models(app):
objects.extend(model.objects.all())
try:
print serializers.serialize(format, objects, indent=indent)
return serializers.serialize(format, objects, indent=indent)
except Exception, 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'
@ -1609,7 +1609,7 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
parser.print_usage_and_exit()
elif action == 'dumpdata':
try:
action_mapping[action](args[1:], options.format, options.indent)
print action_mapping[action](args[1:], options.format, options.indent)
except IndexError:
parser.print_usage_and_exit()
elif action in ('startapp', 'startproject'):

View File

@ -25,6 +25,13 @@ BUILTIN_SERIALIZERS = {
"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 = {}
def register_serializer(format, serializer_module):

View File

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

View File

@ -57,7 +57,7 @@ def Deserializer(object_list, **options):
for d in object_list:
# Look up the model and starting build a dict of data for it.
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 = {}
# Handle each field
@ -70,16 +70,17 @@ def Deserializer(object_list, **options):
# Handle M2M relations
if field.rel and isinstance(field.rel, models.ManyToManyRel):
pks = []
m2m_convert = field.rel.to._meta.pk.to_python
for pk in field_value:
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:
pks.append(pk)
pks.append(m2m_convert(pk))
m2m_data[field.name] = pks
# Handle FK fields
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
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
# serializer base class). None is handled specially.
# serializer base class).
if getattr(obj, field.name) is not None:
value = self.get_string_value(obj, field)
if value is not None:
self.xml.characters(str(value))
else:
self.xml.addQuickElement("None")
self.xml.endElement("field")
@ -127,7 +129,8 @@ class Deserializer(base.Deserializer):
pk = node.getAttribute("pk")
if not pk:
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
# {m2m_accessor_attribute : [list_of_related_objects]})
@ -148,9 +151,12 @@ class Deserializer(base.Deserializer):
# As is usually the case, relation fields get the special treatment.
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):
data[field.attname] = self._handle_fk_field_node(field_node)
data[field.attname] = self._handle_fk_field_node(field_node, field)
else:
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
@ -158,7 +164,7 @@ class Deserializer(base.Deserializer):
# Return a DeserializedObject so that the m2m data has a place to live.
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
"""
@ -166,13 +172,16 @@ class Deserializer(base.Deserializer):
if len(node.childNodes) == 1 and node.childNodes[0].nodeName == 'None':
return None
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
"""
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):
"""

View File

@ -140,7 +140,8 @@ def _isValidDate(date_string):
try:
date(year, month, day)
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):
if not ansi_date_re.search(field_data):
@ -363,7 +364,7 @@ class NumberIsInRange(object):
self.lower, self.upper = lower, upper
if not error_message:
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:
self.error_message = gettext("This value must be at least %s.") % lower
elif upper:

View File

@ -762,6 +762,13 @@ class NullBooleanField(Field):
kwargs['null'] = True
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):
return [oldforms.NullBooleanField]

View File

@ -16,7 +16,7 @@ class RelatedObject(object):
self.opts = model._meta
self.field = field
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()
def flatten_data(self, follow, obj=None):

View File

@ -130,7 +130,9 @@ class FormWrapper(object):
if self.edit_inline:
self.fill_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
raise KeyError, "Could not find Formfield or InlineObjectCollection named %r" % key
@ -226,6 +228,9 @@ class InlineObjectCollection(object):
self.errors = errors
self._collections = None
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):
self.fill()

View File

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

View File

@ -435,6 +435,15 @@ def cycle(parser, token):
cycle = register.tag(cycle)
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()
debug = register.tag(debug)
@ -538,21 +547,6 @@ def do_for(parser, token):
do_for = register.tag("for", do_for)
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())
if len(bits) != 3:
raise TemplateSyntaxError, "%r takes two arguments" % bits[0]
@ -568,11 +562,27 @@ def do_ifequal(parser, token, negate):
#@register.tag
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)
ifequal = register.tag(ifequal)
#@register.tag
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)
ifnotequal = register.tag(ifnotequal)
@ -889,8 +899,9 @@ templatetag = register.tag(templatetag)
def url(parser, token):
"""
Returns an absolute URL matching given view with its parameters. This is a
way to define links that aren't tied to a particular url configuration:
Returns an absolute URL matching given view with its parameters.
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 %}
@ -901,16 +912,16 @@ def url(parser, token):
URL. All arguments for the URL should be present.
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')
and this app's urlconf is included into the project's urlconf under some
path:
path::
('^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 %}

View File

@ -13,6 +13,7 @@ Usage:
from django.utils.dates import MONTHS, MONTHS_3, MONTHS_AP, WEEKDAYS
from django.utils.tzinfo import LocalTimezone
from django.utils.translation import gettext as _
from calendar import isleap, monthrange
import re, time
@ -36,14 +37,14 @@ class TimeFormat(Formatter):
def a(self):
"'a.m.' or 'p.m.'"
if self.data.hour > 11:
return 'p.m.'
return 'a.m.'
return _('p.m.')
return _('a.m.')
def A(self):
"'AM' or 'PM'"
if self.data.hour > 11:
return 'PM'
return 'AM'
return _('PM')
return _('AM')
def B(self):
"Swatch Internet time"
@ -91,9 +92,9 @@ class TimeFormat(Formatter):
Proprietary extension.
"""
if self.data.minute == 0 and self.data.hour == 0:
return 'midnight'
return _('midnight')
if self.data.minute == 0 and self.data.hour == 12:
return 'noon'
return _('noon')
return '%s %s' % (self.f(), self.a())
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
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)
if not next:
next = request.META.get('HTTP_REFERER', None)
if not next:
next = '/'
response = http.HttpResponseRedirect(next)
if check_for_language(lang_code):
if lang_code and check_for_language(lang_code):
if hasattr(request, 'session'):
request.session['django_language'] = lang_code
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::
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)
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
==============================================

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