diff options
| author | Boulder Sprinters <boulder-sprinters@djangoproject.com> | 2007-03-28 21:30:05 +0000 |
|---|---|---|
| committer | Boulder Sprinters <boulder-sprinters@djangoproject.com> | 2007-03-28 21:30:05 +0000 |
| commit | 1f3fc7bc9f8fca6b19b4b88852e5fce5f3dcf347 (patch) | |
| tree | c173e5a0b31ab0d9b90cfd323d6e592fd8bfb177 /django | |
| parent | d2c03a37798adf1975d96c12e927bed75db7feed (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__.py | 2 | ||||
| -rw-r--r-- | django/contrib/auth/models.py | 2 | ||||
| -rw-r--r-- | django/contrib/localflavor/fr/__init__.py | 0 | ||||
| -rw-r--r-- | django/contrib/localflavor/fr/forms.py | 44 | ||||
| -rw-r--r-- | django/contrib/localflavor/fr/fr_department.py | 112 | ||||
| -rw-r--r-- | django/contrib/localflavor/jp/__init__.py | 0 | ||||
| -rw-r--r-- | django/contrib/localflavor/jp/forms.py | 38 | ||||
| -rw-r--r-- | django/contrib/localflavor/jp/jp_prefectures.py | 51 | ||||
| -rw-r--r-- | django/core/cache/backends/memcached.py | 7 | ||||
| -rw-r--r-- | django/core/management.py | 36 | ||||
| -rw-r--r-- | django/middleware/cache.py | 2 | ||||
| -rw-r--r-- | django/template/defaulttags.py | 41 |
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) |
