summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorBoulder Sprinters <boulder-sprinters@djangoproject.com>2007-03-28 21:30:05 +0000
committerBoulder Sprinters <boulder-sprinters@djangoproject.com>2007-03-28 21:30:05 +0000
commit1f3fc7bc9f8fca6b19b4b88852e5fce5f3dcf347 (patch)
treec173e5a0b31ab0d9b90cfd323d6e592fd8bfb177 /django
parentd2c03a37798adf1975d96c12e927bed75db7feed (diff)
boulder-oracle-sprint: Merged to [4839], part two.
git-svn-id: http://code.djangoproject.com/svn/django/branches/boulder-oracle-sprint@4842 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django')
-rw-r--r--django/__init__.py2
-rw-r--r--django/contrib/auth/models.py2
-rw-r--r--django/contrib/localflavor/fr/__init__.py0
-rw-r--r--django/contrib/localflavor/fr/forms.py44
-rw-r--r--django/contrib/localflavor/fr/fr_department.py112
-rw-r--r--django/contrib/localflavor/jp/__init__.py0
-rw-r--r--django/contrib/localflavor/jp/forms.py38
-rw-r--r--django/contrib/localflavor/jp/jp_prefectures.py51
-rw-r--r--django/core/cache/backends/memcached.py7
-rw-r--r--django/core/management.py36
-rw-r--r--django/middleware/cache.py2
-rw-r--r--django/template/defaulttags.py41
12 files changed, 317 insertions, 18 deletions
diff --git a/django/__init__.py b/django/__init__.py
index 5d5461c867..a91a7e13c3 100644
--- a/django/__init__.py
+++ b/django/__init__.py
@@ -1 +1 @@
-VERSION = (0, 96, 'pre')
+VERSION = (0, 96, None)
diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py
index 4f4f0b7538..c3aa863892 100644
--- a/django/contrib/auth/models.py
+++ b/django/contrib/auth/models.py
@@ -45,7 +45,7 @@ class Permission(models.Model):
ordering = ('content_type', 'codename')
def __str__(self):
- return "%s | %s" % (self.content_type, self.name)
+ return "%s | %s | %s" % (self.content_type.app_label, self.content_type, self.name)
class Group(models.Model):
"""Groups are a generic way of categorizing users to apply permissions, or some other label, to those users. A user can belong to any number of groups.
diff --git a/django/contrib/localflavor/fr/__init__.py b/django/contrib/localflavor/fr/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/contrib/localflavor/fr/__init__.py
diff --git a/django/contrib/localflavor/fr/forms.py b/django/contrib/localflavor/fr/forms.py
new file mode 100644
index 0000000000..ee87c5cda2
--- /dev/null
+++ b/django/contrib/localflavor/fr/forms.py
@@ -0,0 +1,44 @@
+"""
+FR-specific Form helpers
+"""
+
+from django.newforms import ValidationError
+from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
+from django.newforms.util import smart_unicode
+from django.utils.translation import gettext
+import re
+
+phone_digits_re = re.compile(r'^0\d(\s|\.)?(\d{2}(\s|\.)?){3}\d{2}$')
+
+class FRZipCodeField(RegexField):
+ def __init__(self, *args, **kwargs):
+ super(FRZipCodeField, self).__init__(r'^\d{5}$',
+ max_length=None, min_length=None,
+ error_message=gettext(u'Enter a zip code in the format XXXXX.'),
+ *args, **kwargs)
+
+class FRPhoneNumberField(Field):
+ """
+ Validate local French phone number (not international ones)
+ The correct format is '0X XX XX XX XX'.
+ '0X.XX.XX.XX.XX' and '0XXXXXXXXX' validate but are corrected to
+ '0X XX XX XX XX'.
+ """
+ def clean(self, value):
+ super(FRPhoneNumberField, self).clean(value)
+ if value in EMPTY_VALUES:
+ return u''
+ value = re.sub('(\.|\s)', '', smart_unicode(value))
+ m = phone_digits_re.search(value)
+ if m:
+ return u'%s %s %s %s %s' % (value[0:2], value[2:4], value[4:6], value[6:8], value[8:10])
+ raise ValidationError(u'Phone numbers must be in 0X XX XX XX XX format.')
+
+class FRDepartmentSelect(Select):
+ """
+ A Select widget that uses a list of FR departments as its choices.
+ """
+ def __init__(self, attrs=None):
+ from fr_department import DEPARTMENT_ASCII_CHOICES # relative import
+ super(FRDepartmentSelect, self).__init__(attrs, choices=DEPARTMENT_ASCII_CHOICES)
+
diff --git a/django/contrib/localflavor/fr/fr_department.py b/django/contrib/localflavor/fr/fr_department.py
new file mode 100644
index 0000000000..02de295f88
--- /dev/null
+++ b/django/contrib/localflavor/fr/fr_department.py
@@ -0,0 +1,112 @@
+# -*- coding: utf-8 -*-
+
+DEPARTMENT_ASCII_CHOICES = (
+ ('01', '01 - Ain'),
+ ('02', '02 - Aisne'),
+ ('03', '03 - Allier'),
+ ('04', '04 - Alpes-de-Haute-Provence'),
+ ('05', '05 - Hautes-Alpes'),
+ ('06', '06 - Alpes-Maritimes'),
+ ('07', '07 - Ardeche'),
+ ('08', '08 - Ardennes'),
+ ('09', '09 - Ariege'),
+ ('10', '10 - Aube'),
+ ('11', '11 - Aude'),
+ ('12', '12 - Aveyron'),
+ ('13', '13 - Bouches-du-Rhone'),
+ ('14', '14 - Calvados'),
+ ('15', '15 - Cantal'),
+ ('16', '16 - Charente'),
+ ('17', '17 - Charente-Maritime'),
+ ('18', '18 - Cher'),
+ ('19', '19 - Correze'),
+ ('21', '21 - Cote-d\'Or'),
+ ('22', '22 - Cotes-d\'Armor'),
+ ('23', '23 - Creuse'),
+ ('24', '24 - Dordogne'),
+ ('25', '25 - Doubs'),
+ ('26', '26 - Drome'),
+ ('27', '27 - Eure'),
+ ('28', '28 - Eure-et-Loire'),
+ ('29', '29 - Finistere'),
+ ('2A', '2A - Corse-du-Sud'),
+ ('2B', '2B - Haute-Corse'),
+ ('30', '30 - Gard'),
+ ('31', '31 - Haute-Garonne'),
+ ('32', '32 - Gers'),
+ ('33', '33 - Gironde'),
+ ('34', '34 - Herault'),
+ ('35', '35 - Ille-et-Vilaine'),
+ ('36', '36 - Indre'),
+ ('37', '37 - Indre-et-Loire'),
+ ('38', '38 - Isere'),
+ ('39', '39 - Jura'),
+ ('40', '40 - Landes'),
+ ('41', '41 - Loir-et-Cher'),
+ ('42', '42 - Loire'),
+ ('43', '43 - Haute-Loire'),
+ ('44', '44 - Loire-Atlantique'),
+ ('45', '45 - Loiret'),
+ ('46', '46 - Lot'),
+ ('47', '47 - Lot-et-Garonne'),
+ ('48', '48 - Lozere'),
+ ('49', '49 - Maine-et-Loire'),
+ ('50', '50 - Manche'),
+ ('51', '51 - Marne'),
+ ('52', '52 - Haute-Marne'),
+ ('53', '53 - Mayenne'),
+ ('54', '54 - Meurthe-et-Moselle'),
+ ('55', '55 - Meuse'),
+ ('56', '56 - Morbihan'),
+ ('57', '57 - Moselle'),
+ ('58', '58 - Nievre'),
+ ('59', '59 - Nord'),
+ ('60', '60 - Oise'),
+ ('61', '61 - Orne'),
+ ('62', '62 - Pas-de-Calais'),
+ ('63', '63 - Puy-de-Dome'),
+ ('64', '64 - Pyrenees-Atlantiques'),
+ ('65', '65 - Hautes-Pyrenees'),
+ ('66', '66 - Pyrenees-Orientales'),
+ ('67', '67 - Bas-Rhin'),
+ ('68', '68 - Haut-Rhin'),
+ ('69', '69 - Rhone'),
+ ('70', '70 - Haute-Saone'),
+ ('71', '71 - Saone-et-Loire'),
+ ('72', '72 - Sarthe'),
+ ('73', '73 - Savoie'),
+ ('74', '74 - Haute-Savoie'),
+ ('75', '75 - Paris'),
+ ('76', '76 - Seine-Maritime'),
+ ('77', '77 - Seine-et-Marne'),
+ ('78', '78 - Yvelines'),
+ ('79', '79 - Deux-Sevres'),
+ ('80', '80 - Somme'),
+ ('81', '81 - Tarn'),
+ ('82', '82 - Tarn-et-Garonne'),
+ ('83', '83 - Var'),
+ ('84', '84 - Vaucluse'),
+ ('85', '85 - Vendee'),
+ ('86', '86 - Vienne'),
+ ('87', '87 - Haute-Vienne'),
+ ('88', '88 - Vosges'),
+ ('89', '89 - Yonne'),
+ ('90', '90 - Territoire de Belfort'),
+ ('91', '91 - Essonne'),
+ ('92', '92 - Hauts-de-Seine'),
+ ('93', '93 - Seine-Saint-Denis'),
+ ('94', '94 - Val-de-Marne'),
+ ('95', '95 - Val-d\'Oise'),
+ ('2A', '2A - Corse du sud'),
+ ('2B', '2B - Haute Corse'),
+ ('971', '971 - Guadeloupe'),
+ ('972', '972 - Martinique'),
+ ('973', '973 - Guyane'),
+ ('974', '974 - La Reunion'),
+ ('975', '975 - Saint-Pierre-et-Miquelon'),
+ ('976', '976 - Mayotte'),
+ ('984', '984 - Terres Australes et Antarctiques'),
+ ('986', '986 - Wallis et Futuna'),
+ ('987', '987 - Polynesie Francaise'),
+ ('988', '988 - Nouvelle-Caledonie'),
+)
diff --git a/django/contrib/localflavor/jp/__init__.py b/django/contrib/localflavor/jp/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/contrib/localflavor/jp/__init__.py
diff --git a/django/contrib/localflavor/jp/forms.py b/django/contrib/localflavor/jp/forms.py
new file mode 100644
index 0000000000..4d93a21227
--- /dev/null
+++ b/django/contrib/localflavor/jp/forms.py
@@ -0,0 +1,38 @@
+"""
+JP-specific Form helpers
+"""
+
+from django.core import validators
+from django.newforms import ValidationError
+from django.utils.translation import gettext
+from django.newforms.fields import RegexField, Select
+
+import re
+
+class JPPostalCodeField(RegexField):
+ """
+ A form field that validates its input is a Japanese postcode.
+
+ Accepts 7 digits, with or without a hyphen.
+ """
+ def __init__(self, *args, **kwargs):
+ super(JPPostalCodeField, self).__init__(r'^\d{3}-\d{4}$|^\d{7}$',
+ max_length=None, min_length=None,
+ error_message=gettext(u'Enter a postal code in the format XXXXXXX or XXX-XXXX.'),
+ *args, **kwargs)
+
+ def clean(self, value):
+ """
+ Validates the input and returns a string that contains only numbers.
+ Returns an empty string for empty values.
+ """
+ v = super(JPPostalCodeField, self).clean(value)
+ return v.replace('-', '')
+
+class JPPrefectureSelect(Select):
+ """
+ A Select widget that uses a list of Japanese prefectures as its choices.
+ """
+ def __init__(self, attrs=None):
+ from jp_prefectures import JP_PREFECTURES
+ super(JPPrefectureSelect, self).__init__(attrs, choices=JP_PREFECTURES)
diff --git a/django/contrib/localflavor/jp/jp_prefectures.py b/django/contrib/localflavor/jp/jp_prefectures.py
new file mode 100644
index 0000000000..72ac4f9474
--- /dev/null
+++ b/django/contrib/localflavor/jp/jp_prefectures.py
@@ -0,0 +1,51 @@
+from django.utils.translation import gettext_lazy as gettext_lazy
+
+JP_PREFECTURES = (
+ ('hokkaido', gettext_lazy('Hokkaido'),),
+ ('aomori', gettext_lazy('Aomori'),),
+ ('iwate', gettext_lazy('Iwate'),),
+ ('miyagi', gettext_lazy('Miyagi'),),
+ ('akita', gettext_lazy('Akita'),),
+ ('yamagata', gettext_lazy('Yamagata'),),
+ ('fukushima', gettext_lazy('Fukushima'),),
+ ('ibaraki', gettext_lazy('Ibaraki'),),
+ ('tochigi', gettext_lazy('Tochigi'),),
+ ('gunma', gettext_lazy('Gunma'),),
+ ('saitama', gettext_lazy('Saitama'),),
+ ('chiba', gettext_lazy('Chiba'),),
+ ('tokyo', gettext_lazy('Tokyo'),),
+ ('kanagawa', gettext_lazy('Kanagawa'),),
+ ('yamanashi', gettext_lazy('Yamanashi'),),
+ ('nagano', gettext_lazy('Nagano'),),
+ ('niigata', gettext_lazy('Niigata'),),
+ ('toyama', gettext_lazy('Toyama'),),
+ ('ishikawa', gettext_lazy('Ishikawa'),),
+ ('fukui', gettext_lazy('Fukui'),),
+ ('gifu', gettext_lazy('Gifu'),),
+ ('shizuoka', gettext_lazy('Shizuoka'),),
+ ('aichi', gettext_lazy('Aichi'),),
+ ('mie', gettext_lazy('Mie'),),
+ ('shiga', gettext_lazy('Shiga'),),
+ ('kyoto', gettext_lazy('Kyoto'),),
+ ('osaka', gettext_lazy('Osaka'),),
+ ('hyogo', gettext_lazy('Hyogo'),),
+ ('nara', gettext_lazy('Nara'),),
+ ('wakayama', gettext_lazy('Wakayama'),),
+ ('tottori', gettext_lazy('Tottori'),),
+ ('shimane', gettext_lazy('Shimane'),),
+ ('okayama', gettext_lazy('Okayama'),),
+ ('hiroshima', gettext_lazy('Hiroshima'),),
+ ('yamaguchi', gettext_lazy('Yamaguchi'),),
+ ('tokushima', gettext_lazy('Tokushima'),),
+ ('kagawa', gettext_lazy('Kagawa'),),
+ ('ehime', gettext_lazy('Ehime'),),
+ ('kochi', gettext_lazy('Kochi'),),
+ ('fukuoka', gettext_lazy('Fukuoka'),),
+ ('saga', gettext_lazy('Saga'),),
+ ('nagasaki', gettext_lazy('Nagasaki'),),
+ ('kumamoto', gettext_lazy('Kumamoto'),),
+ ('oita', gettext_lazy('Oita'),),
+ ('miyazaki', gettext_lazy('Miyazaki'),),
+ ('kagoshima', gettext_lazy('Kagoshima'),),
+ ('okinawa', gettext_lazy('Okinawa'),),
+)
diff --git a/django/core/cache/backends/memcached.py b/django/core/cache/backends/memcached.py
index 180f95da73..1ab019221a 100644
--- a/django/core/cache/backends/memcached.py
+++ b/django/core/cache/backends/memcached.py
@@ -3,9 +3,12 @@
from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError
try:
- import memcache
+ import cmemcache as memcache
except ImportError:
- raise InvalidCacheBackendError, "Memcached cache backend requires the 'memcache' library"
+ try:
+ import memcache
+ except:
+ raise InvalidCacheBackendError("Memcached cache backend requires either the 'memcache' or 'cmemcache' library")
class CacheClass(BaseCache):
def __init__(self, server, params):
diff --git a/django/core/management.py b/django/core/management.py
index 1cd3753740..26551fdc88 100644
--- a/django/core/management.py
+++ b/django/core/management.py
@@ -299,7 +299,7 @@ def get_sql_delete(app):
from django.db.backends.util import truncate_name
introspection = get_introspection_module()
- # This should work even if a connecton isn't available
+ # This should work even if a connection isn't available
try:
cursor = connection.cursor()
except:
@@ -486,7 +486,7 @@ def get_sql_indexes_for_model(model):
unique = f.unique and 'UNIQUE ' or ''
output.append(
style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
- truncate_name(style.SQL_TABLE('%s_%s' % (model._meta.db_table, f.column)), backend.get_max_name_length()) + ' ' + \
+ style.SQL_TABLE(backend.quote_name('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
style.SQL_KEYWORD('ON') + ' ' + \
style.SQL_TABLE(backend.quote_name(model._meta.db_table)) + ' ' + \
"(%s);" % style.SQL_FIELD(backend.quote_name(f.column))
@@ -546,6 +546,7 @@ def syncdb(verbosity=1, interactive=True):
created_models = set()
pending_references = {}
+ # Create the tables for each model
for app in models.get_apps():
app_name = app.__name__.split('.')[-2]
model_list = models.get_models(app)
@@ -567,6 +568,11 @@ def syncdb(verbosity=1, interactive=True):
cursor.execute(statement)
table_list.append(table_name_converter(model._meta.db_table))
+ # Create the m2m tables. This must be done after all tables have been created
+ # to ensure that all referred tables will exist.
+ for app in models.get_apps():
+ app_name = app.__name__.split('.')[-2]
+ model_list = models.get_models(app)
for model in model_list:
if model in created_models:
sql = _get_many_to_many_sql_for_model(model)
@@ -576,7 +582,7 @@ def syncdb(verbosity=1, interactive=True):
for statement in sql:
cursor.execute(statement)
- transaction.commit_unless_managed()
+ transaction.commit_unless_managed()
# Send the post_syncdb signal, so individual apps can do whatever they need
# to do at this point.
@@ -1383,18 +1389,26 @@ def load_data(fixture_labels, verbosity=1):
app_fixtures = [os.path.join(os.path.dirname(app.__file__),'fixtures') for app in get_apps()]
for fixture_label in fixture_labels:
+ parts = fixture_label.split('.')
+ if len(parts) == 1:
+ fixture_name = fixture_label
+ formats = serializers.get_serializer_formats()
+ else:
+ fixture_name, format = '.'.join(parts[:-1]), parts[-1]
+ if format in serializers.get_serializer_formats():
+ formats = [format]
+ else:
+ formats = []
+
if verbosity > 0:
- print "Loading '%s' fixtures..." % fixture_label
+ if formats:
+ print "Loading '%s' fixtures..." % fixture_name
+ else:
+ print "Skipping fixture '%s': %s is not a known serialization format" % (fixture_name, format)
+
for fixture_dir in app_fixtures + list(settings.FIXTURE_DIRS) + ['']:
if verbosity > 1:
print "Checking %s for fixtures..." % humanize(fixture_dir)
- parts = fixture_label.split('.')
- if len(parts) == 1:
- fixture_name = fixture_label
- formats = serializers.get_serializer_formats()
- else:
- fixture_name, format = '.'.join(parts[:-1]), parts[-1]
- formats = [format]
label_found = False
for format in formats:
diff --git a/django/middleware/cache.py b/django/middleware/cache.py
index 58800b24da..a88b4956b2 100644
--- a/django/middleware/cache.py
+++ b/django/middleware/cache.py
@@ -10,7 +10,7 @@ class CacheMiddleware(object):
Only parameter-less GET or HEAD-requests with status code 200 are cached.
If CACHE_MIDDLEWARE_ANONYMOUS_ONLY is set to True, only anonymous requests
- (i.e., those node made by a logged-in user) will be cached. This is a
+ (i.e., those not made by a logged-in user) will be cached. This is a
simple and effective way of avoiding the caching of the Django admin (and
any other user-specific content).
diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py
index b18fa1dce7..cf72d8f26e 100644
--- a/django/template/defaulttags.py
+++ b/django/template/defaulttags.py
@@ -354,6 +354,23 @@ class WidthRatioNode(Node):
return ''
return str(int(round(ratio)))
+class WithNode(Node):
+ def __init__(self, var, name, nodelist):
+ self.var = var
+ self.name = name
+ self.nodelist = nodelist
+
+ def __repr__(self):
+ return "<WithNode>"
+
+ def render(self, context):
+ val = self.var.resolve(context)
+ context.push()
+ context[self.name] = val
+ output = self.nodelist.render(context)
+ context.pop()
+ return output
+
#@register.tag
def comment(parser, token):
"""
@@ -595,8 +612,8 @@ def do_if(parser, token):
::
- {% if althlete_list %}
- Number of athletes: {{ althete_list|count }}
+ {% if athlete_list %}
+ Number of athletes: {{ athlete_list|count }}
{% else %}
No athletes.
{% endif %}
@@ -967,3 +984,23 @@ def widthratio(parser, token):
return WidthRatioNode(parser.compile_filter(this_value_expr),
parser.compile_filter(max_value_expr), max_width)
widthratio = register.tag(widthratio)
+
+#@register.tag
+def do_with(parser, token):
+ """
+ Add a value to the context (inside of this block) for caching and easy
+ access. For example::
+
+ {% with person.some_sql_method as total %}
+ {{ total }} object{{ total|pluralize }}
+ {% endwith %}
+ """
+ bits = list(token.split_contents())
+ if len(bits) != 4 or bits[2] != "as":
+ raise TemplateSyntaxError, "%r expected format is 'value as name'" % tagname
+ var = parser.compile_filter(bits[1])
+ name = bits[3]
+ nodelist = parser.parse(('endwith',))
+ parser.delete_first_token()
+ return WithNode(var, name, nodelist)
+do_with = register.tag('with', do_with)