Ticket #17627: 0003.patch
File 0003.patch, 127.9 KB (added by , 13 years ago) |
---|
-
AUTHORS
diff --git a/AUTHORS b/AUTHORS index 5fa21d3..faa6126 100644
a b answer newbie questions, and generally made Django that much better: 218 218 David Gouldin <dgouldin@gmail.com> 219 219 pradeep.gowda@gmail.com 220 220 Collin Grady <collin@collingrady.com> 221 Luke Granger-Brown <django@lukegb.com> 221 222 Gabriel Grant <g@briel.ca> 222 223 Simon Greenhill <dev@simon.net.nz> 223 224 Owen Griffiths … … answer newbie questions, and generally made Django that much better: 295 296 Cameron Knight (ckknight) 296 297 Nena Kojadin <nena@kiberpipa.org> 297 298 Igor Kolar <ike@email.si> 299 Wiktor Kołodziej 298 300 Tomáš Kopeček <permonik@m6.cz> 299 301 Gasper Koren 300 302 Mikhail Korobov <kmike84@googlemail.com> -
django/conf/locale/en/LC_MESSAGES/django.po
diff --git a/django/conf/locale/en/LC_MESSAGES/django.po b/django/conf/locale/en/LC_MESSAGES/django.po index abb52ae..1f3317b 100644
a b msgstr "" 655 655 msgid "\"%s\" is not a valid value for a primary key." 656 656 msgstr "" 657 657 658 #: forms/util .py:70658 #: forms/utils.py:70 659 659 #, python-format 660 660 msgid "" 661 661 "%(datetime)s couldn't be interpreted in time zone %(current_timezone)s; it " -
django/contrib/admin/actions.py
diff --git a/django/contrib/admin/actions.py b/django/contrib/admin/actions.py index 5b56402..4a03a97 100644
a b Built-in, globally-available admin actions. 4 4 5 5 from django.core.exceptions import PermissionDenied 6 6 from django.contrib.admin import helpers 7 from django.contrib.admin.util import get_deleted_objects, model_ngettext7 from django.contrib.admin.utils import get_deleted_objects, model_ngettext 8 8 from django.db import router 9 9 from django.template.response import TemplateResponse 10 10 from django.utils.encoding import force_unicode -
django/contrib/admin/filters.py
diff --git a/django/contrib/admin/filters.py b/django/contrib/admin/filters.py index 550683b..dc4434b 100644
a b from django.core.exceptions import ImproperlyConfigured 12 12 from django.utils.encoding import smart_unicode 13 13 from django.utils.translation import ugettext_lazy as _ 14 14 15 from django.contrib.admin.util import (get_model_from_relation,15 from django.contrib.admin.utils import (get_model_from_relation, 16 16 reverse_field_path, get_limit_choices_to_from_path, prepare_lookup_value) 17 17 18 18 class ListFilter(object): -
django/contrib/admin/helpers.py
diff --git a/django/contrib/admin/helpers.py b/django/contrib/admin/helpers.py index b08d1c8..ae46be4 100644
a b 1 1 from django import forms 2 from django.contrib.admin.util import (flatten_fieldsets, lookup_field,2 from django.contrib.admin.utils import (flatten_fieldsets, lookup_field, 3 3 display_for_field, label_for_field, help_text_for_field) 4 4 from django.contrib.admin.templatetags.admin_static import static 5 5 from django.contrib.contenttypes.models import ContentType 6 6 from django.core.exceptions import ObjectDoesNotExist 7 7 from django.db.models.fields.related import ManyToManyRel 8 from django.forms.util import flatatt8 from django.forms.utils import flatatt 9 9 from django.template.defaultfilters import capfirst 10 10 from django.utils.encoding import force_unicode, smart_unicode 11 11 from django.utils.html import escape, conditional_escape … … class InlineFieldset(Fieldset): 318 318 yield Fieldline(self.form, field, self.readonly_fields, 319 319 model_admin=self.model_admin) 320 320 321 class AdminErrorList(forms.util .ErrorList):321 class AdminErrorList(forms.utils.ErrorList): 322 322 """ 323 323 Stores all errors for the form/formsets in an add/change stage view. 324 324 """ -
django/contrib/admin/models.py
diff --git a/django/contrib/admin/models.py b/django/contrib/admin/models.py index 0e5b8a7..013ae44 100644
a b 1 1 from django.db import models 2 2 from django.contrib.contenttypes.models import ContentType 3 3 from django.contrib.auth.models import User 4 from django.contrib.admin.util import quote4 from django.contrib.admin.utils import quote 5 5 from django.utils.translation import ugettext_lazy as _ 6 6 from django.utils.encoding import smart_unicode 7 7 from django.utils.safestring import mark_safe -
django/contrib/admin/options.py
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index f5f6256..0dcb4e6 100644
a b from django.forms.models import (modelform_factory, modelformset_factory, 6 6 inlineformset_factory, BaseInlineFormSet) 7 7 from django.contrib.contenttypes.models import ContentType 8 8 from django.contrib.admin import widgets, helpers 9 from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_format_dict9 from django.contrib.admin.utils import unquote, flatten_fieldsets, get_deleted_objects, model_format_dict 10 10 from django.contrib.admin.templatetags.admin_static import static 11 11 from django.contrib import messages 12 12 from django.views.decorators.csrf import csrf_protect -
django/contrib/admin/templatetags/admin_list.py
diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py index e778429..23ba3ea 100644
a b 1 1 import datetime 2 2 3 from django.contrib.admin.util import lookup_field, display_for_field, label_for_field3 from django.contrib.admin.utils import lookup_field, display_for_field, label_for_field 4 4 from django.contrib.admin.views.main import (ALL_VAR, EMPTY_CHANGELIST_VALUE, 5 5 ORDER_VAR, PAGE_VAR, SEARCH_VAR) 6 6 from django.contrib.admin.templatetags.admin_static import static -
django/contrib/admin/util.py
diff --git a/django/contrib/admin/util.py b/django/contrib/admin/util.py index 61182a6..fc8b3dd 100644
a b 1 from django.db import models 2 from django.db.models.sql.constants import LOOKUP_SEP 3 from django.db.models.deletion import Collector 4 from django.db.models.related import RelatedObject 5 from django.forms.forms import pretty_name 6 from django.utils import formats 7 from django.utils.html import escape 8 from django.utils.safestring import mark_safe 9 from django.utils.text import capfirst 10 from django.utils import timezone 11 from django.utils.encoding import force_unicode, smart_unicode, smart_str 12 from django.utils.translation import ungettext 13 from django.core.urlresolvers import reverse 1 import warnings 14 2 15 def lookup_needs_distinct(opts, lookup_path): 16 """ 17 Returns True if 'distinct()' should be used to query the given lookup path. 18 """ 19 field_name = lookup_path.split('__', 1)[0] 20 field = opts.get_field_by_name(field_name)[0] 21 if ((hasattr(field, 'rel') and 22 isinstance(field.rel, models.ManyToManyRel)) or 23 (isinstance(field, models.related.RelatedObject) and 24 not field.field.unique)): 25 return True 26 return False 3 warnings.warn("The django.contrib.admin.util module has been renamed " 4 "(https://code.djangoproject.com/ticket/17627/). " 5 "Use django.contrib.admin.utils instead.", PendingDeprecationWarning) 27 6 28 def prepare_lookup_value(key, value): 29 """ 30 Returns a lookup value prepared to be used in queryset filtering. 31 """ 32 # if key ends with __in, split parameter into separate values 33 if key.endswith('__in'): 34 value = value.split(',') 35 # if key ends with __isnull, special case '' and false 36 if key.endswith('__isnull'): 37 if value.lower() in ('', 'false'): 38 value = False 39 else: 40 value = True 41 return value 42 43 def quote(s): 44 """ 45 Ensure that primary key values do not confuse the admin URLs by escaping 46 any '/', '_' and ':' characters. Similar to urllib.quote, except that the 47 quoting is slightly different so that it doesn't get automatically 48 unquoted by the Web browser. 49 """ 50 if not isinstance(s, basestring): 51 return s 52 res = list(s) 53 for i in range(len(res)): 54 c = res[i] 55 if c in """:/_#?;@&=+$,"<>%\\""": 56 res[i] = '_%02X' % ord(c) 57 return ''.join(res) 58 59 60 def unquote(s): 61 """ 62 Undo the effects of quote(). Based heavily on urllib.unquote(). 63 """ 64 mychr = chr 65 myatoi = int 66 list = s.split('_') 67 res = [list[0]] 68 myappend = res.append 69 del list[0] 70 for item in list: 71 if item[1:2]: 72 try: 73 myappend(mychr(myatoi(item[:2], 16)) + item[2:]) 74 except ValueError: 75 myappend('_' + item) 76 else: 77 myappend('_' + item) 78 return "".join(res) 79 80 81 def flatten_fieldsets(fieldsets): 82 """Returns a list of field names from an admin fieldsets structure.""" 83 field_names = [] 84 for name, opts in fieldsets: 85 for field in opts['fields']: 86 # type checking feels dirty, but it seems like the best way here 87 if type(field) == tuple: 88 field_names.extend(field) 89 else: 90 field_names.append(field) 91 return field_names 92 93 94 def get_deleted_objects(objs, opts, user, admin_site, using): 95 """ 96 Find all objects related to ``objs`` that should also be deleted. ``objs`` 97 must be a homogenous iterable of objects (e.g. a QuerySet). 98 99 Returns a nested list of strings suitable for display in the 100 template with the ``unordered_list`` filter. 101 102 """ 103 collector = NestedObjects(using=using) 104 collector.collect(objs) 105 perms_needed = set() 106 107 def format_callback(obj): 108 has_admin = obj.__class__ in admin_site._registry 109 opts = obj._meta 110 111 if has_admin: 112 admin_url = reverse('%s:%s_%s_change' 113 % (admin_site.name, 114 opts.app_label, 115 opts.object_name.lower()), 116 None, (quote(obj._get_pk_val()),)) 117 p = '%s.%s' % (opts.app_label, 118 opts.get_delete_permission()) 119 if not user.has_perm(p): 120 perms_needed.add(opts.verbose_name) 121 # Display a link to the admin page. 122 return mark_safe(u'%s: <a href="%s">%s</a>' % 123 (escape(capfirst(opts.verbose_name)), 124 admin_url, 125 escape(obj))) 126 else: 127 # Don't display link to edit, because it either has no 128 # admin or is edited inline. 129 return u'%s: %s' % (capfirst(opts.verbose_name), 130 force_unicode(obj)) 131 132 to_delete = collector.nested(format_callback) 133 134 protected = [format_callback(obj) for obj in collector.protected] 135 136 return to_delete, perms_needed, protected 137 138 139 class NestedObjects(Collector): 140 def __init__(self, *args, **kwargs): 141 super(NestedObjects, self).__init__(*args, **kwargs) 142 self.edges = {} # {from_instance: [to_instances]} 143 self.protected = set() 144 145 def add_edge(self, source, target): 146 self.edges.setdefault(source, []).append(target) 147 148 def collect(self, objs, source_attr=None, **kwargs): 149 for obj in objs: 150 if source_attr: 151 self.add_edge(getattr(obj, source_attr), obj) 152 else: 153 self.add_edge(None, obj) 154 try: 155 return super(NestedObjects, self).collect(objs, source_attr=source_attr, **kwargs) 156 except models.ProtectedError, e: 157 self.protected.update(e.protected_objects) 158 159 def related_objects(self, related, objs): 160 qs = super(NestedObjects, self).related_objects(related, objs) 161 return qs.select_related(related.field.name) 162 163 def _nested(self, obj, seen, format_callback): 164 if obj in seen: 165 return [] 166 seen.add(obj) 167 children = [] 168 for child in self.edges.get(obj, ()): 169 children.extend(self._nested(child, seen, format_callback)) 170 if format_callback: 171 ret = [format_callback(obj)] 172 else: 173 ret = [obj] 174 if children: 175 ret.append(children) 176 return ret 177 178 def nested(self, format_callback=None): 179 """ 180 Return the graph as a nested list. 181 182 """ 183 seen = set() 184 roots = [] 185 for root in self.edges.get(None, ()): 186 roots.extend(self._nested(root, seen, format_callback)) 187 return roots 188 189 190 def model_format_dict(obj): 191 """ 192 Return a `dict` with keys 'verbose_name' and 'verbose_name_plural', 193 typically for use with string formatting. 194 195 `obj` may be a `Model` instance, `Model` subclass, or `QuerySet` instance. 196 197 """ 198 if isinstance(obj, (models.Model, models.base.ModelBase)): 199 opts = obj._meta 200 elif isinstance(obj, models.query.QuerySet): 201 opts = obj.model._meta 202 else: 203 opts = obj 204 return { 205 'verbose_name': force_unicode(opts.verbose_name), 206 'verbose_name_plural': force_unicode(opts.verbose_name_plural) 207 } 208 209 210 def model_ngettext(obj, n=None): 211 """ 212 Return the appropriate `verbose_name` or `verbose_name_plural` value for 213 `obj` depending on the count `n`. 214 215 `obj` may be a `Model` instance, `Model` subclass, or `QuerySet` instance. 216 If `obj` is a `QuerySet` instance, `n` is optional and the length of the 217 `QuerySet` is used. 218 219 """ 220 if isinstance(obj, models.query.QuerySet): 221 if n is None: 222 n = obj.count() 223 obj = obj.model 224 d = model_format_dict(obj) 225 singular, plural = d["verbose_name"], d["verbose_name_plural"] 226 return ungettext(singular, plural, n or 0) 227 228 229 def lookup_field(name, obj, model_admin=None): 230 opts = obj._meta 231 try: 232 f = opts.get_field(name) 233 except models.FieldDoesNotExist: 234 # For non-field values, the value is either a method, property or 235 # returned via a callable. 236 if callable(name): 237 attr = name 238 value = attr(obj) 239 elif (model_admin is not None and hasattr(model_admin, name) and 240 not name == '__str__' and not name == '__unicode__'): 241 attr = getattr(model_admin, name) 242 value = attr(obj) 243 else: 244 attr = getattr(obj, name) 245 if callable(attr): 246 value = attr() 247 else: 248 value = attr 249 f = None 250 else: 251 attr = None 252 value = getattr(obj, name) 253 return f, attr, value 254 255 256 def label_for_field(name, model, model_admin=None, return_attr=False): 257 """ 258 Returns a sensible label for a field name. The name can be a callable or the 259 name of an object attributes, as well as a genuine fields. If return_attr is 260 True, the resolved attribute (which could be a callable) is also returned. 261 This will be None if (and only if) the name refers to a field. 262 """ 263 attr = None 264 try: 265 field = model._meta.get_field_by_name(name)[0] 266 if isinstance(field, RelatedObject): 267 label = field.opts.verbose_name 268 else: 269 label = field.verbose_name 270 except models.FieldDoesNotExist: 271 if name == "__unicode__": 272 label = force_unicode(model._meta.verbose_name) 273 attr = unicode 274 elif name == "__str__": 275 label = smart_str(model._meta.verbose_name) 276 attr = str 277 else: 278 if callable(name): 279 attr = name 280 elif model_admin is not None and hasattr(model_admin, name): 281 attr = getattr(model_admin, name) 282 elif hasattr(model, name): 283 attr = getattr(model, name) 284 else: 285 message = "Unable to lookup '%s' on %s" % (name, model._meta.object_name) 286 if model_admin: 287 message += " or %s" % (model_admin.__class__.__name__,) 288 raise AttributeError(message) 289 290 if hasattr(attr, "short_description"): 291 label = attr.short_description 292 elif callable(attr): 293 if attr.__name__ == "<lambda>": 294 label = "--" 295 else: 296 label = pretty_name(attr.__name__) 297 else: 298 label = pretty_name(name) 299 if return_attr: 300 return (label, attr) 301 else: 302 return label 303 304 def help_text_for_field(name, model): 305 try: 306 help_text = model._meta.get_field_by_name(name)[0].help_text 307 except models.FieldDoesNotExist: 308 help_text = "" 309 return smart_unicode(help_text) 310 311 312 def display_for_field(value, field): 313 from django.contrib.admin.templatetags.admin_list import _boolean_icon 314 from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE 315 316 if field.flatchoices: 317 return dict(field.flatchoices).get(value, EMPTY_CHANGELIST_VALUE) 318 # NullBooleanField needs special-case null-handling, so it comes 319 # before the general null test. 320 elif isinstance(field, models.BooleanField) or isinstance(field, models.NullBooleanField): 321 return _boolean_icon(value) 322 elif value is None: 323 return EMPTY_CHANGELIST_VALUE 324 elif isinstance(field, models.DateTimeField): 325 return formats.localize(timezone.localtime(value)) 326 elif isinstance(field, models.DateField) or isinstance(field, models.TimeField): 327 return formats.localize(value) 328 elif isinstance(field, models.DecimalField): 329 return formats.number_format(value, field.decimal_places) 330 elif isinstance(field, models.FloatField): 331 return formats.number_format(value) 332 else: 333 return smart_unicode(value) 334 335 336 class NotRelationField(Exception): 337 pass 338 339 340 def get_model_from_relation(field): 341 if isinstance(field, models.related.RelatedObject): 342 return field.model 343 elif getattr(field, 'rel'): # or isinstance? 344 return field.rel.to 345 else: 346 raise NotRelationField 347 348 349 def reverse_field_path(model, path): 350 """ Create a reversed field path. 351 352 E.g. Given (Order, "user__groups"), 353 return (Group, "user__order"). 354 355 Final field must be a related model, not a data field. 356 357 """ 358 reversed_path = [] 359 parent = model 360 pieces = path.split(LOOKUP_SEP) 361 for piece in pieces: 362 field, model, direct, m2m = parent._meta.get_field_by_name(piece) 363 # skip trailing data field if extant: 364 if len(reversed_path) == len(pieces)-1: # final iteration 365 try: 366 get_model_from_relation(field) 367 except NotRelationField: 368 break 369 if direct: 370 related_name = field.related_query_name() 371 parent = field.rel.to 372 else: 373 related_name = field.field.name 374 parent = field.model 375 reversed_path.insert(0, related_name) 376 return (parent, LOOKUP_SEP.join(reversed_path)) 377 378 379 def get_fields_from_path(model, path): 380 """ Return list of Fields given path relative to model. 381 382 e.g. (ModelX, "user__groups__name") -> [ 383 <django.db.models.fields.related.ForeignKey object at 0x...>, 384 <django.db.models.fields.related.ManyToManyField object at 0x...>, 385 <django.db.models.fields.CharField object at 0x...>, 386 ] 387 """ 388 pieces = path.split(LOOKUP_SEP) 389 fields = [] 390 for piece in pieces: 391 if fields: 392 parent = get_model_from_relation(fields[-1]) 393 else: 394 parent = model 395 fields.append(parent._meta.get_field_by_name(piece)[0]) 396 return fields 397 398 399 def remove_trailing_data_field(fields): 400 """ Discard trailing non-relation field if extant. """ 401 try: 402 get_model_from_relation(fields[-1]) 403 except NotRelationField: 404 fields = fields[:-1] 405 return fields 406 407 408 def get_limit_choices_to_from_path(model, path): 409 """ Return Q object for limiting choices if applicable. 410 411 If final model in path is linked via a ForeignKey or ManyToManyField which 412 has a `limit_choices_to` attribute, return it as a Q object. 413 """ 414 415 fields = get_fields_from_path(model, path) 416 fields = remove_trailing_data_field(fields) 417 limit_choices_to = ( 418 fields and hasattr(fields[-1], 'rel') and 419 getattr(fields[-1].rel, 'limit_choices_to', None)) 420 if not limit_choices_to: 421 return models.Q() # empty Q 422 elif isinstance(limit_choices_to, models.Q): 423 return limit_choices_to # already a Q 424 else: 425 return models.Q(**limit_choices_to) # convert dict to Q 7 from django.contrib.admin.utils import * -
new file django/contrib/admin/utils.py
diff --git a/django/contrib/admin/utils.py b/django/contrib/admin/utils.py new file mode 100644 index 0000000..61182a6
- + 1 from django.db import models 2 from django.db.models.sql.constants import LOOKUP_SEP 3 from django.db.models.deletion import Collector 4 from django.db.models.related import RelatedObject 5 from django.forms.forms import pretty_name 6 from django.utils import formats 7 from django.utils.html import escape 8 from django.utils.safestring import mark_safe 9 from django.utils.text import capfirst 10 from django.utils import timezone 11 from django.utils.encoding import force_unicode, smart_unicode, smart_str 12 from django.utils.translation import ungettext 13 from django.core.urlresolvers import reverse 14 15 def lookup_needs_distinct(opts, lookup_path): 16 """ 17 Returns True if 'distinct()' should be used to query the given lookup path. 18 """ 19 field_name = lookup_path.split('__', 1)[0] 20 field = opts.get_field_by_name(field_name)[0] 21 if ((hasattr(field, 'rel') and 22 isinstance(field.rel, models.ManyToManyRel)) or 23 (isinstance(field, models.related.RelatedObject) and 24 not field.field.unique)): 25 return True 26 return False 27 28 def prepare_lookup_value(key, value): 29 """ 30 Returns a lookup value prepared to be used in queryset filtering. 31 """ 32 # if key ends with __in, split parameter into separate values 33 if key.endswith('__in'): 34 value = value.split(',') 35 # if key ends with __isnull, special case '' and false 36 if key.endswith('__isnull'): 37 if value.lower() in ('', 'false'): 38 value = False 39 else: 40 value = True 41 return value 42 43 def quote(s): 44 """ 45 Ensure that primary key values do not confuse the admin URLs by escaping 46 any '/', '_' and ':' characters. Similar to urllib.quote, except that the 47 quoting is slightly different so that it doesn't get automatically 48 unquoted by the Web browser. 49 """ 50 if not isinstance(s, basestring): 51 return s 52 res = list(s) 53 for i in range(len(res)): 54 c = res[i] 55 if c in """:/_#?;@&=+$,"<>%\\""": 56 res[i] = '_%02X' % ord(c) 57 return ''.join(res) 58 59 60 def unquote(s): 61 """ 62 Undo the effects of quote(). Based heavily on urllib.unquote(). 63 """ 64 mychr = chr 65 myatoi = int 66 list = s.split('_') 67 res = [list[0]] 68 myappend = res.append 69 del list[0] 70 for item in list: 71 if item[1:2]: 72 try: 73 myappend(mychr(myatoi(item[:2], 16)) + item[2:]) 74 except ValueError: 75 myappend('_' + item) 76 else: 77 myappend('_' + item) 78 return "".join(res) 79 80 81 def flatten_fieldsets(fieldsets): 82 """Returns a list of field names from an admin fieldsets structure.""" 83 field_names = [] 84 for name, opts in fieldsets: 85 for field in opts['fields']: 86 # type checking feels dirty, but it seems like the best way here 87 if type(field) == tuple: 88 field_names.extend(field) 89 else: 90 field_names.append(field) 91 return field_names 92 93 94 def get_deleted_objects(objs, opts, user, admin_site, using): 95 """ 96 Find all objects related to ``objs`` that should also be deleted. ``objs`` 97 must be a homogenous iterable of objects (e.g. a QuerySet). 98 99 Returns a nested list of strings suitable for display in the 100 template with the ``unordered_list`` filter. 101 102 """ 103 collector = NestedObjects(using=using) 104 collector.collect(objs) 105 perms_needed = set() 106 107 def format_callback(obj): 108 has_admin = obj.__class__ in admin_site._registry 109 opts = obj._meta 110 111 if has_admin: 112 admin_url = reverse('%s:%s_%s_change' 113 % (admin_site.name, 114 opts.app_label, 115 opts.object_name.lower()), 116 None, (quote(obj._get_pk_val()),)) 117 p = '%s.%s' % (opts.app_label, 118 opts.get_delete_permission()) 119 if not user.has_perm(p): 120 perms_needed.add(opts.verbose_name) 121 # Display a link to the admin page. 122 return mark_safe(u'%s: <a href="%s">%s</a>' % 123 (escape(capfirst(opts.verbose_name)), 124 admin_url, 125 escape(obj))) 126 else: 127 # Don't display link to edit, because it either has no 128 # admin or is edited inline. 129 return u'%s: %s' % (capfirst(opts.verbose_name), 130 force_unicode(obj)) 131 132 to_delete = collector.nested(format_callback) 133 134 protected = [format_callback(obj) for obj in collector.protected] 135 136 return to_delete, perms_needed, protected 137 138 139 class NestedObjects(Collector): 140 def __init__(self, *args, **kwargs): 141 super(NestedObjects, self).__init__(*args, **kwargs) 142 self.edges = {} # {from_instance: [to_instances]} 143 self.protected = set() 144 145 def add_edge(self, source, target): 146 self.edges.setdefault(source, []).append(target) 147 148 def collect(self, objs, source_attr=None, **kwargs): 149 for obj in objs: 150 if source_attr: 151 self.add_edge(getattr(obj, source_attr), obj) 152 else: 153 self.add_edge(None, obj) 154 try: 155 return super(NestedObjects, self).collect(objs, source_attr=source_attr, **kwargs) 156 except models.ProtectedError, e: 157 self.protected.update(e.protected_objects) 158 159 def related_objects(self, related, objs): 160 qs = super(NestedObjects, self).related_objects(related, objs) 161 return qs.select_related(related.field.name) 162 163 def _nested(self, obj, seen, format_callback): 164 if obj in seen: 165 return [] 166 seen.add(obj) 167 children = [] 168 for child in self.edges.get(obj, ()): 169 children.extend(self._nested(child, seen, format_callback)) 170 if format_callback: 171 ret = [format_callback(obj)] 172 else: 173 ret = [obj] 174 if children: 175 ret.append(children) 176 return ret 177 178 def nested(self, format_callback=None): 179 """ 180 Return the graph as a nested list. 181 182 """ 183 seen = set() 184 roots = [] 185 for root in self.edges.get(None, ()): 186 roots.extend(self._nested(root, seen, format_callback)) 187 return roots 188 189 190 def model_format_dict(obj): 191 """ 192 Return a `dict` with keys 'verbose_name' and 'verbose_name_plural', 193 typically for use with string formatting. 194 195 `obj` may be a `Model` instance, `Model` subclass, or `QuerySet` instance. 196 197 """ 198 if isinstance(obj, (models.Model, models.base.ModelBase)): 199 opts = obj._meta 200 elif isinstance(obj, models.query.QuerySet): 201 opts = obj.model._meta 202 else: 203 opts = obj 204 return { 205 'verbose_name': force_unicode(opts.verbose_name), 206 'verbose_name_plural': force_unicode(opts.verbose_name_plural) 207 } 208 209 210 def model_ngettext(obj, n=None): 211 """ 212 Return the appropriate `verbose_name` or `verbose_name_plural` value for 213 `obj` depending on the count `n`. 214 215 `obj` may be a `Model` instance, `Model` subclass, or `QuerySet` instance. 216 If `obj` is a `QuerySet` instance, `n` is optional and the length of the 217 `QuerySet` is used. 218 219 """ 220 if isinstance(obj, models.query.QuerySet): 221 if n is None: 222 n = obj.count() 223 obj = obj.model 224 d = model_format_dict(obj) 225 singular, plural = d["verbose_name"], d["verbose_name_plural"] 226 return ungettext(singular, plural, n or 0) 227 228 229 def lookup_field(name, obj, model_admin=None): 230 opts = obj._meta 231 try: 232 f = opts.get_field(name) 233 except models.FieldDoesNotExist: 234 # For non-field values, the value is either a method, property or 235 # returned via a callable. 236 if callable(name): 237 attr = name 238 value = attr(obj) 239 elif (model_admin is not None and hasattr(model_admin, name) and 240 not name == '__str__' and not name == '__unicode__'): 241 attr = getattr(model_admin, name) 242 value = attr(obj) 243 else: 244 attr = getattr(obj, name) 245 if callable(attr): 246 value = attr() 247 else: 248 value = attr 249 f = None 250 else: 251 attr = None 252 value = getattr(obj, name) 253 return f, attr, value 254 255 256 def label_for_field(name, model, model_admin=None, return_attr=False): 257 """ 258 Returns a sensible label for a field name. The name can be a callable or the 259 name of an object attributes, as well as a genuine fields. If return_attr is 260 True, the resolved attribute (which could be a callable) is also returned. 261 This will be None if (and only if) the name refers to a field. 262 """ 263 attr = None 264 try: 265 field = model._meta.get_field_by_name(name)[0] 266 if isinstance(field, RelatedObject): 267 label = field.opts.verbose_name 268 else: 269 label = field.verbose_name 270 except models.FieldDoesNotExist: 271 if name == "__unicode__": 272 label = force_unicode(model._meta.verbose_name) 273 attr = unicode 274 elif name == "__str__": 275 label = smart_str(model._meta.verbose_name) 276 attr = str 277 else: 278 if callable(name): 279 attr = name 280 elif model_admin is not None and hasattr(model_admin, name): 281 attr = getattr(model_admin, name) 282 elif hasattr(model, name): 283 attr = getattr(model, name) 284 else: 285 message = "Unable to lookup '%s' on %s" % (name, model._meta.object_name) 286 if model_admin: 287 message += " or %s" % (model_admin.__class__.__name__,) 288 raise AttributeError(message) 289 290 if hasattr(attr, "short_description"): 291 label = attr.short_description 292 elif callable(attr): 293 if attr.__name__ == "<lambda>": 294 label = "--" 295 else: 296 label = pretty_name(attr.__name__) 297 else: 298 label = pretty_name(name) 299 if return_attr: 300 return (label, attr) 301 else: 302 return label 303 304 def help_text_for_field(name, model): 305 try: 306 help_text = model._meta.get_field_by_name(name)[0].help_text 307 except models.FieldDoesNotExist: 308 help_text = "" 309 return smart_unicode(help_text) 310 311 312 def display_for_field(value, field): 313 from django.contrib.admin.templatetags.admin_list import _boolean_icon 314 from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE 315 316 if field.flatchoices: 317 return dict(field.flatchoices).get(value, EMPTY_CHANGELIST_VALUE) 318 # NullBooleanField needs special-case null-handling, so it comes 319 # before the general null test. 320 elif isinstance(field, models.BooleanField) or isinstance(field, models.NullBooleanField): 321 return _boolean_icon(value) 322 elif value is None: 323 return EMPTY_CHANGELIST_VALUE 324 elif isinstance(field, models.DateTimeField): 325 return formats.localize(timezone.localtime(value)) 326 elif isinstance(field, models.DateField) or isinstance(field, models.TimeField): 327 return formats.localize(value) 328 elif isinstance(field, models.DecimalField): 329 return formats.number_format(value, field.decimal_places) 330 elif isinstance(field, models.FloatField): 331 return formats.number_format(value) 332 else: 333 return smart_unicode(value) 334 335 336 class NotRelationField(Exception): 337 pass 338 339 340 def get_model_from_relation(field): 341 if isinstance(field, models.related.RelatedObject): 342 return field.model 343 elif getattr(field, 'rel'): # or isinstance? 344 return field.rel.to 345 else: 346 raise NotRelationField 347 348 349 def reverse_field_path(model, path): 350 """ Create a reversed field path. 351 352 E.g. Given (Order, "user__groups"), 353 return (Group, "user__order"). 354 355 Final field must be a related model, not a data field. 356 357 """ 358 reversed_path = [] 359 parent = model 360 pieces = path.split(LOOKUP_SEP) 361 for piece in pieces: 362 field, model, direct, m2m = parent._meta.get_field_by_name(piece) 363 # skip trailing data field if extant: 364 if len(reversed_path) == len(pieces)-1: # final iteration 365 try: 366 get_model_from_relation(field) 367 except NotRelationField: 368 break 369 if direct: 370 related_name = field.related_query_name() 371 parent = field.rel.to 372 else: 373 related_name = field.field.name 374 parent = field.model 375 reversed_path.insert(0, related_name) 376 return (parent, LOOKUP_SEP.join(reversed_path)) 377 378 379 def get_fields_from_path(model, path): 380 """ Return list of Fields given path relative to model. 381 382 e.g. (ModelX, "user__groups__name") -> [ 383 <django.db.models.fields.related.ForeignKey object at 0x...>, 384 <django.db.models.fields.related.ManyToManyField object at 0x...>, 385 <django.db.models.fields.CharField object at 0x...>, 386 ] 387 """ 388 pieces = path.split(LOOKUP_SEP) 389 fields = [] 390 for piece in pieces: 391 if fields: 392 parent = get_model_from_relation(fields[-1]) 393 else: 394 parent = model 395 fields.append(parent._meta.get_field_by_name(piece)[0]) 396 return fields 397 398 399 def remove_trailing_data_field(fields): 400 """ Discard trailing non-relation field if extant. """ 401 try: 402 get_model_from_relation(fields[-1]) 403 except NotRelationField: 404 fields = fields[:-1] 405 return fields 406 407 408 def get_limit_choices_to_from_path(model, path): 409 """ Return Q object for limiting choices if applicable. 410 411 If final model in path is linked via a ForeignKey or ManyToManyField which 412 has a `limit_choices_to` attribute, return it as a Q object. 413 """ 414 415 fields = get_fields_from_path(model, path) 416 fields = remove_trailing_data_field(fields) 417 limit_choices_to = ( 418 fields and hasattr(fields[-1], 'rel') and 419 getattr(fields[-1].rel, 'limit_choices_to', None)) 420 if not limit_choices_to: 421 return models.Q() # empty Q 422 elif isinstance(limit_choices_to, models.Q): 423 return limit_choices_to # already a Q 424 else: 425 return models.Q(**limit_choices_to) # convert dict to Q -
django/contrib/admin/validation.py
diff --git a/django/contrib/admin/validation.py b/django/contrib/admin/validation.py index 733f89d..bd99b84 100644
a b from django.db.models.fields import FieldDoesNotExist 4 4 from django.forms.models import (BaseModelForm, BaseModelFormSet, fields_for_model, 5 5 _get_foreign_key) 6 6 from django.contrib.admin import ListFilter, FieldListFilter 7 from django.contrib.admin.util import get_fields_from_path, NotRelationField7 from django.contrib.admin.utils import get_fields_from_path, NotRelationField 8 8 from django.contrib.admin.options import (flatten_fieldsets, BaseModelAdmin, 9 9 HORIZONTAL, VERTICAL) 10 10 -
django/contrib/admin/views/main.py
diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index 56f13f8..e12cca5 100644
a b from django.utils.http import urlencode 10 10 11 11 from django.contrib.admin import FieldListFilter 12 12 from django.contrib.admin.options import IncorrectLookupParameters 13 from django.contrib.admin.util import (quote, get_fields_from_path,13 from django.contrib.admin.utils import (quote, get_fields_from_path, 14 14 lookup_needs_distinct, prepare_lookup_value) 15 15 16 16 # Changelist settings -
django/contrib/admin/widgets.py
diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py index 29958b2..148ce1c 100644
a b from django import forms 7 7 from django.contrib.admin.templatetags.admin_static import static 8 8 from django.core.urlresolvers import reverse 9 9 from django.forms.widgets import RadioFieldRenderer 10 from django.forms.util import flatatt10 from django.forms.utils import flatatt 11 11 from django.utils.html import escape 12 12 from django.utils.text import Truncator 13 13 from django.utils.translation import ugettext as _ -
django/contrib/auth/admin.py
diff --git a/django/contrib/auth/admin.py b/django/contrib/auth/admin.py index f14b3d2..973bdb8 100644
a b class UserAdmin(admin.ModelAdmin): 71 71 if obj is None: 72 72 defaults.update({ 73 73 'form': self.add_form, 74 'fields': admin.util .flatten_fieldsets(self.add_fieldsets),74 'fields': admin.utils.flatten_fieldsets(self.add_fieldsets), 75 75 }) 76 76 defaults.update(kwargs) 77 77 return super(UserAdmin, self).get_form(request, obj, **defaults) -
django/contrib/auth/forms.py
diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py index badd760..d988ce3 100644
a b 1 1 from django import forms 2 from django.forms.util import flatatt2 from django.forms.utils import flatatt 3 3 from django.template import loader 4 4 from django.utils.encoding import smart_str 5 5 from django.utils.http import int_to_base36 -
django/contrib/comments/forms.py
diff --git a/django/contrib/comments/forms.py b/django/contrib/comments/forms.py index 830e24b..88c2e5e 100644
a b 1 1 import time 2 2 from django import forms 3 from django.forms.util import ErrorDict3 from django.forms.utils import ErrorDict 4 4 from django.conf import settings 5 5 from django.contrib.contenttypes.models import ContentType 6 6 from django.contrib.comments.models import Comment -
django/contrib/gis/db/backends/oracle/creation.py
diff --git a/django/contrib/gis/db/backends/oracle/creation.py b/django/contrib/gis/db/backends/oracle/creation.py index 043da91..14f8d4d 100644
a b 1 1 from django.db.backends.oracle.creation import DatabaseCreation 2 from django.db.backends.util import truncate_name2 from django.db.backends.utils import truncate_name 3 3 4 4 class OracleCreation(DatabaseCreation): 5 5 -
django/contrib/gis/db/backends/oracle/operations.py
diff --git a/django/contrib/gis/db/backends/oracle/operations.py b/django/contrib/gis/db/backends/oracle/operations.py index a2374bb..97380a3 100644
a b from decimal import Decimal 13 13 from django.db.backends.oracle.base import DatabaseOperations 14 14 from django.contrib.gis.db.backends.base import BaseSpatialOperations 15 15 from django.contrib.gis.db.backends.oracle.adapter import OracleSpatialAdapter 16 from django.contrib.gis.db.backends.util import SpatialFunction16 from django.contrib.gis.db.backends.utils import SpatialFunction 17 17 from django.contrib.gis.geometry.backend import Geometry 18 18 from django.contrib.gis.measure import Distance 19 19 -
django/contrib/gis/db/backends/postgis/operations.py
diff --git a/django/contrib/gis/db/backends/postgis/operations.py b/django/contrib/gis/db/backends/postgis/operations.py index 3286748..31e659c 100644
a b from decimal import Decimal 3 3 4 4 from django.conf import settings 5 5 from django.contrib.gis.db.backends.base import BaseSpatialOperations 6 from django.contrib.gis.db.backends.util import SpatialOperation, SpatialFunction6 from django.contrib.gis.db.backends.utils import SpatialOperation, SpatialFunction 7 7 from django.contrib.gis.db.backends.postgis.adapter import PostGISAdapter 8 8 from django.contrib.gis.geometry.backend import Geometry 9 9 from django.contrib.gis.measure import Distance -
django/contrib/gis/db/backends/spatialite/operations.py
diff --git a/django/contrib/gis/db/backends/spatialite/operations.py b/django/contrib/gis/db/backends/spatialite/operations.py index a0efb99..6dacff0 100644
a b import re 2 2 from decimal import Decimal 3 3 4 4 from django.contrib.gis.db.backends.base import BaseSpatialOperations 5 from django.contrib.gis.db.backends.util import SpatialOperation, SpatialFunction5 from django.contrib.gis.db.backends.utils import SpatialOperation, SpatialFunction 6 6 from django.contrib.gis.db.backends.spatialite.adapter import SpatiaLiteAdapter 7 7 from django.contrib.gis.geometry.backend import Geometry 8 8 from django.contrib.gis.measure import Distance -
django/contrib/gis/db/backends/util.py
diff --git a/django/contrib/gis/db/backends/util.py b/django/contrib/gis/db/backends/util.py index b50c8e2..3b52c38 100644
a b 1 """ 2 A collection of utility routines and classes used by the spatial 3 backends. 4 """ 1 import warnings 5 2 6 def gqn(val): 7 """ 8 The geographic quote name function; used for quoting tables and 9 geometries (they use single rather than the double quotes of the 10 backend quotename function). 11 """ 12 if isinstance(val, basestring): 13 if isinstance(val, unicode): val = val.encode('ascii') 14 return "'%s'" % val 15 else: 16 return str(val) 3 warnings.warn("The django.contrib.gis.db.util module has been renamed " 4 "(https://code.djangoproject.com/ticket/17627/). " 5 "Use django.contrib.gis.db.utils instead.", PendingDeprecationWarning) 17 6 18 class SpatialOperation(object): 19 """ 20 Base class for generating spatial SQL. 21 """ 22 sql_template = '%(geo_col)s %(operator)s %(geometry)s' 23 24 def __init__(self, function='', operator='', result='', **kwargs): 25 self.function = function 26 self.operator = operator 27 self.result = result 28 self.extra = kwargs 29 30 def as_sql(self, geo_col, geometry='%s'): 31 return self.sql_template % self.params(geo_col, geometry) 32 33 def params(self, geo_col, geometry): 34 params = {'function' : self.function, 35 'geo_col' : geo_col, 36 'geometry' : geometry, 37 'operator' : self.operator, 38 'result' : self.result, 39 } 40 params.update(self.extra) 41 return params 42 43 class SpatialFunction(SpatialOperation): 44 """ 45 Base class for generating spatial SQL related to a function. 46 """ 47 sql_template = '%(function)s(%(geo_col)s, %(geometry)s)' 48 49 def __init__(self, func, result='', operator='', **kwargs): 50 # Getting the function prefix. 51 default = {'function' : func, 52 'operator' : operator, 53 'result' : result 54 } 55 kwargs.update(default) 56 super(SpatialFunction, self).__init__(**kwargs) 7 from django.contrib.gis.db.utils import * -
new file django/contrib/gis/db/backends/utils.py
diff --git a/django/contrib/gis/db/backends/utils.py b/django/contrib/gis/db/backends/utils.py new file mode 100644 index 0000000..b50c8e2
- + 1 """ 2 A collection of utility routines and classes used by the spatial 3 backends. 4 """ 5 6 def gqn(val): 7 """ 8 The geographic quote name function; used for quoting tables and 9 geometries (they use single rather than the double quotes of the 10 backend quotename function). 11 """ 12 if isinstance(val, basestring): 13 if isinstance(val, unicode): val = val.encode('ascii') 14 return "'%s'" % val 15 else: 16 return str(val) 17 18 class SpatialOperation(object): 19 """ 20 Base class for generating spatial SQL. 21 """ 22 sql_template = '%(geo_col)s %(operator)s %(geometry)s' 23 24 def __init__(self, function='', operator='', result='', **kwargs): 25 self.function = function 26 self.operator = operator 27 self.result = result 28 self.extra = kwargs 29 30 def as_sql(self, geo_col, geometry='%s'): 31 return self.sql_template % self.params(geo_col, geometry) 32 33 def params(self, geo_col, geometry): 34 params = {'function' : self.function, 35 'geo_col' : geo_col, 36 'geometry' : geometry, 37 'operator' : self.operator, 38 'result' : self.result, 39 } 40 params.update(self.extra) 41 return params 42 43 class SpatialFunction(SpatialOperation): 44 """ 45 Base class for generating spatial SQL related to a function. 46 """ 47 sql_template = '%(function)s(%(geo_col)s, %(geometry)s)' 48 49 def __init__(self, func, result='', operator='', **kwargs): 50 # Getting the function prefix. 51 default = {'function' : func, 52 'operator' : operator, 53 'result' : result 54 } 55 kwargs.update(default) 56 super(SpatialFunction, self).__init__(**kwargs) -
django/contrib/gis/db/models/sql/compiler.py
diff --git a/django/contrib/gis/db/models/sql/compiler.py b/django/contrib/gis/db/models/sql/compiler.py index 07eea32..a387fb6 100644
a b 1 1 from itertools import izip 2 from django.db.backends.util import truncate_name, typecast_timestamp2 from django.db.backends.utils import truncate_name, typecast_timestamp 3 3 from django.db.models.sql import compiler 4 4 from django.db.models.sql.constants import TABLE_NAME, MULTI 5 5 -
django/contrib/localflavor/it/forms.py
diff --git a/django/contrib/localflavor/it/forms.py b/django/contrib/localflavor/it/forms.py index 0060b48..a7dd5cd 100644
a b import re 8 8 9 9 from django.contrib.localflavor.it.it_province import PROVINCE_CHOICES 10 10 from django.contrib.localflavor.it.it_region import REGION_CHOICES 11 from django.contrib.localflavor.it.util import ssn_check_digit, vat_number_check_digit11 from django.contrib.localflavor.it.utils import ssn_check_digit, vat_number_check_digit 12 12 from django.core.validators import EMPTY_VALUES 13 13 from django.forms import ValidationError 14 14 from django.forms.fields import Field, RegexField, Select -
django/contrib/localflavor/it/util.py
diff --git a/django/contrib/localflavor/it/util.py b/django/contrib/localflavor/it/util.py index c162ff7..8abd1bd 100644
a b 1 from django.utils.encoding import smart_str, smart_unicode 1 import warnings 2 2 3 def ssn_check_digit(value): 4 "Calculate Italian social security number check digit." 5 ssn_even_chars = { 6 '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, 7 '9': 9, 'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6, 'H': 7, 8 'I': 8, 'J': 9, 'K': 10, 'L': 11, 'M': 12, 'N': 13, 'O': 14, 'P': 15, 9 'Q': 16, 'R': 17, 'S': 18, 'T': 19, 'U': 20, 'V': 21, 'W': 22, 'X': 23, 10 'Y': 24, 'Z': 25 11 } 12 ssn_odd_chars = { 13 '0': 1, '1': 0, '2': 5, '3': 7, '4': 9, '5': 13, '6': 15, '7': 17, '8': 14 19, '9': 21, 'A': 1, 'B': 0, 'C': 5, 'D': 7, 'E': 9, 'F': 13, 'G': 15, 15 'H': 17, 'I': 19, 'J': 21, 'K': 2, 'L': 4, 'M': 18, 'N': 20, 'O': 11, 16 'P': 3, 'Q': 6, 'R': 8, 'S': 12, 'T': 14, 'U': 16, 'V': 10, 'W': 22, 17 'X': 25, 'Y': 24, 'Z': 23 18 } 19 # Chars from 'A' to 'Z' 20 ssn_check_digits = [chr(x) for x in range(65, 91)] 3 warnings.warn("The django.contrib.localflavor.it.util module has been renamed " 4 "(https://code.djangoproject.com/ticket/17627/). " 5 "Use django.contrib.localflavor.it.utils instead.", PendingDeprecationWarning) 21 6 22 ssn = value.upper() 23 total = 0 24 for i in range(0, 15): 25 try: 26 if i % 2 == 0: 27 total += ssn_odd_chars[ssn[i]] 28 else: 29 total += ssn_even_chars[ssn[i]] 30 except KeyError: 31 msg = "Character '%(char)s' is not allowed." % {'char': ssn[i]} 32 raise ValueError(msg) 33 return ssn_check_digits[total % 26] 34 35 def vat_number_check_digit(vat_number): 36 "Calculate Italian VAT number check digit." 37 normalized_vat_number = smart_str(vat_number).zfill(10) 38 total = 0 39 for i in range(0, 10, 2): 40 total += int(normalized_vat_number[i]) 41 for i in range(1, 11, 2): 42 quotient , remainder = divmod(int(normalized_vat_number[i]) * 2, 10) 43 total += quotient + remainder 44 return smart_unicode((10 - total % 10) % 10) 7 from django.contrib.localflavor.it.utils import * -
new file django/contrib/localflavor/it/utils.py
diff --git a/django/contrib/localflavor/it/utils.py b/django/contrib/localflavor/it/utils.py new file mode 100644 index 0000000..c162ff7
- + 1 from django.utils.encoding import smart_str, smart_unicode 2 3 def ssn_check_digit(value): 4 "Calculate Italian social security number check digit." 5 ssn_even_chars = { 6 '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, 7 '9': 9, 'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6, 'H': 7, 8 'I': 8, 'J': 9, 'K': 10, 'L': 11, 'M': 12, 'N': 13, 'O': 14, 'P': 15, 9 'Q': 16, 'R': 17, 'S': 18, 'T': 19, 'U': 20, 'V': 21, 'W': 22, 'X': 23, 10 'Y': 24, 'Z': 25 11 } 12 ssn_odd_chars = { 13 '0': 1, '1': 0, '2': 5, '3': 7, '4': 9, '5': 13, '6': 15, '7': 17, '8': 14 19, '9': 21, 'A': 1, 'B': 0, 'C': 5, 'D': 7, 'E': 9, 'F': 13, 'G': 15, 15 'H': 17, 'I': 19, 'J': 21, 'K': 2, 'L': 4, 'M': 18, 'N': 20, 'O': 11, 16 'P': 3, 'Q': 6, 'R': 8, 'S': 12, 'T': 14, 'U': 16, 'V': 10, 'W': 22, 17 'X': 25, 'Y': 24, 'Z': 23 18 } 19 # Chars from 'A' to 'Z' 20 ssn_check_digits = [chr(x) for x in range(65, 91)] 21 22 ssn = value.upper() 23 total = 0 24 for i in range(0, 15): 25 try: 26 if i % 2 == 0: 27 total += ssn_odd_chars[ssn[i]] 28 else: 29 total += ssn_even_chars[ssn[i]] 30 except KeyError: 31 msg = "Character '%(char)s' is not allowed." % {'char': ssn[i]} 32 raise ValueError(msg) 33 return ssn_check_digits[total % 26] 34 35 def vat_number_check_digit(vat_number): 36 "Calculate Italian VAT number check digit." 37 normalized_vat_number = smart_str(vat_number).zfill(10) 38 total = 0 39 for i in range(0, 10, 2): 40 total += int(normalized_vat_number[i]) 41 for i in range(1, 11, 2): 42 quotient , remainder = divmod(int(normalized_vat_number[i]) * 2, 10) 43 total += quotient + remainder 44 return smart_unicode((10 - total % 10) % 10) -
django/contrib/localflavor/uy/forms.py
diff --git a/django/contrib/localflavor/uy/forms.py b/django/contrib/localflavor/uy/forms.py index 2112162..6107667 100644
a b from django.core.validators import EMPTY_VALUES 9 9 from django.forms.fields import Select, RegexField 10 10 from django.forms import ValidationError 11 11 from django.utils.translation import ugettext_lazy as _ 12 from django.contrib.localflavor.uy.util import get_validation_digit12 from django.contrib.localflavor.uy.utils import get_validation_digit 13 13 14 14 15 15 class UYDepartamentSelect(Select): -
django/contrib/localflavor/uy/util.py
diff --git a/django/contrib/localflavor/uy/util.py b/django/contrib/localflavor/uy/util.py index 0c1a8f8..95598ad 100644
a b 1 # -*- coding: utf-8 -*- 1 import warnings 2 2 3 def get_validation_digit(number): 4 """ Calculates the validation digit for the given number. """ 5 sum = 0 6 dvs = [4, 3, 6, 7, 8, 9, 2] 7 number = str(number) 3 warnings.warn("The django.contrib.localflavor.uy.util module has been renamed " 4 "(https://code.djangoproject.com/ticket/17627/). " 5 "Use django.contrib.localflavor.uy.utils instead.", PendingDeprecationWarning) 8 6 9 for i in range(0, len(number)): 10 sum = (int(number[-1 - i]) * dvs[i] + sum) % 10 11 12 return (10-sum) % 10 7 from django.contrib.localflavor.uy.utils import * -
new file django/contrib/localflavor/uy/utils.py
diff --git a/django/contrib/localflavor/uy/utils.py b/django/contrib/localflavor/uy/utils.py new file mode 100644 index 0000000..0c1a8f8
- + 1 # -*- coding: utf-8 -*- 2 3 def get_validation_digit(number): 4 """ Calculates the validation digit for the given number. """ 5 sum = 0 6 dvs = [4, 3, 6, 7, 8, 9, 2] 7 number = str(number) 8 9 for i in range(0, len(number)): 10 sum = (int(number[-1 - i]) * dvs[i] + sum) % 10 11 12 return (10-sum) % 10 -
django/db/backends/__init__.py
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index 7674f5c..37985e8 100644
a b from contextlib import contextmanager 8 8 9 9 from django.conf import settings 10 10 from django.db import DEFAULT_DB_ALIAS 11 from django.db.backends import util 11 from django.db.backends import utils 12 12 from django.db.transaction import TransactionManagementError 13 13 from django.utils.importlib import import_module 14 14 from django.utils.timezone import is_aware … … class BaseDatabaseWrapper(object): 305 305 (self.use_debug_cursor is None and settings.DEBUG)): 306 306 cursor = self.make_debug_cursor(self._cursor()) 307 307 else: 308 cursor = util .CursorWrapper(self._cursor(), self)308 cursor = utils.CursorWrapper(self._cursor(), self) 309 309 return cursor 310 310 311 311 def make_debug_cursor(self, cursor): 312 return util .CursorDebugWrapper(cursor, self)312 return utils.CursorDebugWrapper(cursor, self) 313 313 314 314 class BaseDatabaseFeatures(object): 315 315 allows_group_by_pk = False … … class BaseDatabaseOperations(object): 798 798 """ 799 799 if value is None: 800 800 return None 801 return util .format_number(value, max_digits, decimal_places)801 return utils.format_number(value, max_digits, decimal_places) 802 802 803 803 def year_lookup_bounds(self, value): 804 804 """ -
django/db/backends/creation.py
diff --git a/django/db/backends/creation.py b/django/db/backends/creation.py index 0cd0558..e845abd 100644
a b class BaseDatabaseCreation(object): 129 129 """ 130 130 Returns any ALTER TABLE statements to add constraints after the fact. 131 131 """ 132 from django.db.backends.util import truncate_name132 from django.db.backends.utils import truncate_name 133 133 134 134 if not model._meta.managed or model._meta.proxy: 135 135 return [] … … class BaseDatabaseCreation(object): 171 171 """ 172 172 Return the CREATE INDEX SQL statements for a single model field. 173 173 """ 174 from django.db.backends.util import truncate_name174 from django.db.backends.utils import truncate_name 175 175 176 176 if f.db_index and not f.unique: 177 177 qn = self.connection.ops.quote_name … … class BaseDatabaseCreation(object): 215 215 return output 216 216 217 217 def sql_remove_table_constraints(self, model, references_to_delete, style): 218 from django.db.backends.util import truncate_name218 from django.db.backends.utils import truncate_name 219 219 if not model._meta.managed or model._meta.proxy: 220 220 return [] 221 221 output = [] -
django/db/backends/dummy/base.py
diff --git a/django/db/backends/dummy/base.py b/django/db/backends/dummy/base.py index 746f26b..2800288 100644
a b ImproperlyConfigured. 8 8 """ 9 9 10 10 from django.core.exceptions import ImproperlyConfigured 11 from django.db.backends import *11 from django.db.backends import BaseDatabaseFeatures, BaseDatabaseOperations, BaseDatabaseWrapper, BaseDatabaseValidation 12 12 from django.db.backends.creation import BaseDatabaseCreation 13 13 14 14 def complain(*args, **kwargs): -
django/db/backends/mysql/base.py
diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py index e30cb90..830103f 100644
a b if (version < (1,2,1) or (version[:3] == (1, 2, 1) and 26 26 from MySQLdb.converters import conversions, Thing2Literal 27 27 from MySQLdb.constants import FIELD_TYPE, CLIENT 28 28 29 from django.db.backends import utils as backend_utils, BaseDatabaseFeatures, BaseDatabaseOperations, BaseDatabaseWrapper 29 30 from django.db import utils 30 from django.db.backends import *31 31 from django.db.backends.signals import connection_created 32 32 from django.db.backends.mysql.client import DatabaseClient 33 33 from django.db.backends.mysql.creation import DatabaseCreation … … def adapt_datetime_with_timezone_support(value, conv): 76 76 # timezone support is active, Django expects timezone-aware datetime objects. 77 77 django_conversions = conversions.copy() 78 78 django_conversions.update({ 79 FIELD_TYPE.TIME: util.typecast_time,80 FIELD_TYPE.DECIMAL: util.typecast_decimal,81 FIELD_TYPE.NEWDECIMAL: util.typecast_decimal,79 FIELD_TYPE.TIME: backend_utils.typecast_time, 80 FIELD_TYPE.DECIMAL: backend_utils.typecast_decimal, 81 FIELD_TYPE.NEWDECIMAL: backend_utils.typecast_decimal, 82 82 FIELD_TYPE.DATETIME: parse_datetime_with_timezone_support, 83 83 datetime.datetime: adapt_datetime_with_timezone_support, 84 84 }) … … server_version_re = re.compile(r'(\d{1,2})\.(\d{1,2})\.(\d{1,2})') 93 93 # MySQL-4.1 and newer, so the MysqlDebugWrapper is unnecessary. Since the 94 94 # point is to raise Warnings as exceptions, this can be done with the Python 95 95 # warning module, and this is setup when the connection is created, and the 96 # standard util.CursorDebugWrapper can be used. Also, using sql_mode96 # standard backend_utils.CursorDebugWrapper can be used. Also, using sql_mode 97 97 # TRADITIONAL will automatically cause most warnings to be treated as errors. 98 98 99 99 class CursorWrapper(object): … … class DatabaseFeatures(BaseDatabaseFeatures): 169 169 self._storage_engine = None 170 170 171 171 def _mysql_storage_engine(self): 172 " Internal method used in Django tests. Don't rely on this from your code"172 """Internal method used in Django tests. Don't rely on this from your code""" 173 173 if self._storage_engine is None: 174 174 cursor = self.connection.cursor() 175 175 cursor.execute('CREATE TABLE INTROSPECT_TEST (X INT)') … … class DatabaseFeatures(BaseDatabaseFeatures): 184 184 return self._storage_engine 185 185 186 186 def _can_introspect_foreign_keys(self): 187 " Confirm support for introspected foreign keys"187 """Confirm support for introspected foreign keys""" 188 188 return self._mysql_storage_engine() != 'MyISAM' 189 189 190 190 class DatabaseOperations(BaseDatabaseOperations): -
django/db/backends/oracle/base.py
diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py index 6bc6e1d..8a9f137 100644
a b Requires cx_Oracle: http://cx-oracle.sourceforge.net/ 8 8 import datetime 9 9 import decimal 10 10 import sys 11 import warnings 11 12 12 13 13 14 def _setup_environment(environ): … … except ImportError, e: 44 45 from django.core.exceptions import ImproperlyConfigured 45 46 raise ImproperlyConfigured("Error loading cx_Oracle module: %s" % e) 46 47 47 from django. conf import settings48 from django.db.backends import utils as backend_utils, settings, BaseDatabaseFeatures, BaseDatabaseOperations, BaseDatabaseWrapper, BaseDatabaseValidation 48 49 from django.db import utils 49 from django.db.backends import *50 50 from django.db.backends.signals import connection_created 51 51 from django.db.backends.oracle.client import DatabaseClient 52 52 from django.db.backends.oracle.creation import DatabaseCreation … … WHEN (new.%(col_name)s IS NULL) 167 167 value = float(value) 168 168 # Convert floats to decimals 169 169 elif value is not None and field and field.get_internal_type() == 'DecimalField': 170 value = util.typecast_decimal(field.format_number(value))170 value = backend_utils.typecast_decimal(field.format_number(value)) 171 171 # cx_Oracle always returns datetime.datetime objects for 172 172 # DATE and TIMESTAMP columns, but Django wants to see a 173 173 # python datetime.date, .time, or .datetime. We use the type … … WHEN (new.%(col_name)s IS NULL) 242 242 # always defaults to uppercase. 243 243 # We simplify things by making Oracle identifiers always uppercase. 244 244 if not name.startswith('"') and not name.endswith('"'): 245 name = '"%s"' % util.truncate_name(name.upper(),245 name = '"%s"' % backend_utils.truncate_name(name.upper(), 246 246 self.max_name_length()) 247 247 return name.upper() 248 248 … … WHEN (new.%(col_name)s IS NULL) 367 367 return [first % value, second % value] 368 368 369 369 def combine_expression(self, connector, sub_expressions): 370 " Oracle requires special cases for %% and & operators in query expressions"370 """Oracle requires special cases for %% and & operators in query expressions""" 371 371 if connector == '%%': 372 372 return 'MOD(%s)' % ','.join(sub_expressions) 373 373 elif connector == '&': … … WHEN (new.%(col_name)s IS NULL) 378 378 379 379 def _get_sequence_name(self, table): 380 380 name_length = self.max_name_length() - 3 381 return '%s_SQ' % util.truncate_name(table, name_length).upper()381 return '%s_SQ' % backend_utils.truncate_name(table, name_length).upper() 382 382 383 383 def _get_trigger_name(self, table): 384 384 name_length = self.max_name_length() - 3 385 return '%s_TR' % util.truncate_name(table, name_length).upper()385 return '%s_TR' % backend_utils.truncate_name(table, name_length).upper() 386 386 387 387 def bulk_insert_sql(self, fields, num_values): 388 388 items_sql = "SELECT %s FROM DUAL" % ", ".join(["%s"] * len(fields)) -
django/db/backends/postgresql_psycopg2/base.py
diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py index 802ebf2..9b7d647 100644
a b Requires psycopg 2: http://initd.org/projects/psycopg2 5 5 """ 6 6 import sys 7 7 8 from django.db.backends import settings, BaseDatabaseFeatures, BaseDatabaseWrapper, BaseDatabaseValidation 8 9 from django.db import utils 9 from django.db.backends import *10 10 from django.db.backends.signals import connection_created 11 11 from django.db.backends.postgresql_psycopg2.operations import DatabaseOperations 12 12 from django.db.backends.postgresql_psycopg2.client import DatabaseClient -
django/db/backends/postgresql_psycopg2/creation.py
diff --git a/django/db/backends/postgresql_psycopg2/creation.py b/django/db/backends/postgresql_psycopg2/creation.py index ca389b9..75db89a 100644
a b 1 1 import psycopg2.extensions 2 2 3 3 from django.db.backends.creation import BaseDatabaseCreation 4 from django.db.backends.util import truncate_name4 from django.db.backends.utils import truncate_name 5 5 6 6 7 7 class DatabaseCreation(BaseDatabaseCreation): -
django/db/backends/sqlite3/base.py
diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index 0b19442..0d93fc7 100644
a b import warnings 11 11 import re 12 12 import sys 13 13 14 from django.db import utils 15 from django.db.backends import * 14 from django.db.backends import utils as backend_utils, settings, BaseDatabaseFeatures, BaseDatabaseOperations, BaseDatabaseWrapper, BaseDatabaseValidation 16 15 from django.db.backends.signals import connection_created 17 16 from django.db.backends.sqlite3.client import DatabaseClient 18 17 from django.db.backends.sqlite3.creation import DatabaseCreation 19 18 from django.db.backends.sqlite3.introspection import DatabaseIntrospection 19 from django.db import utils 20 20 from django.utils.dateparse import parse_date, parse_datetime, parse_time 21 21 from django.utils.safestring import SafeString 22 22 from django.utils import timezone … … Database.register_converter("date", parse_date) 59 59 Database.register_converter("datetime", parse_datetime_with_timezone_support) 60 60 Database.register_converter("timestamp", parse_datetime_with_timezone_support) 61 61 Database.register_converter("TIMESTAMP", parse_datetime_with_timezone_support) 62 Database.register_converter("decimal", util.typecast_decimal)62 Database.register_converter("decimal", backend_utils.typecast_decimal) 63 63 Database.register_adapter(datetime.datetime, adapt_datetime_with_timezone_support) 64 Database.register_adapter(decimal.Decimal, util.rev_typecast_decimal)64 Database.register_adapter(decimal.Decimal, backend_utils.rev_typecast_decimal) 65 65 if Database.version_info >= (2, 4, 1): 66 66 # Starting in 2.4.1, the str type is not accepted anymore, therefore, 67 67 # we convert all str objects to Unicode … … class DatabaseOperations(BaseDatabaseOperations): 190 190 """ 191 191 internal_type = field.get_internal_type() 192 192 if internal_type == 'DecimalField': 193 return util.typecast_decimal(field.format_number(value))193 return backend_utils.typecast_decimal(field.format_number(value)) 194 194 elif internal_type and internal_type.endswith('IntegerField') or internal_type == 'AutoField': 195 195 return int(value) 196 196 elif internal_type == 'DateField': … … def _sqlite_extract(lookup_type, dt): 356 356 if dt is None: 357 357 return None 358 358 try: 359 dt = util.typecast_timestamp(dt)359 dt = backend_utils.typecast_timestamp(dt) 360 360 except (ValueError, TypeError): 361 361 return None 362 362 if lookup_type == 'week_day': … … def _sqlite_extract(lookup_type, dt): 366 366 367 367 def _sqlite_date_trunc(lookup_type, dt): 368 368 try: 369 dt = util.typecast_timestamp(dt)369 dt = backend_utils.typecast_timestamp(dt) 370 370 except (ValueError, TypeError): 371 371 return None 372 372 if lookup_type == 'year': … … def _sqlite_date_trunc(lookup_type, dt): 378 378 379 379 def _sqlite_format_dtdelta(dt, conn, days, secs, usecs): 380 380 try: 381 dt = util.typecast_timestamp(dt)381 dt = backend_utils.typecast_timestamp(dt) 382 382 delta = datetime.timedelta(int(days), int(secs), int(usecs)) 383 383 if conn.strip() == '+': 384 384 dt = dt + delta -
django/db/backends/util.py
diff --git a/django/db/backends/util.py b/django/db/backends/util.py index 32e0f4f..c6f3785 100644
a b 1 import datetime 2 import decimal 3 import hashlib 4 from time import time 1 import warnings 5 2 6 from django.conf import settings 7 from django.utils.log import getLogger 8 from django.utils.timezone import utc 3 warnings.warn("The django.db.backends.util module has been renamed " 4 "(https://code.djangoproject.com/ticket/17627/). " 5 "Use django.db.backends.utils instead.", PendingDeprecationWarning) 9 6 10 11 logger = getLogger('django.db.backends') 12 13 14 class CursorWrapper(object): 15 def __init__(self, cursor, db): 16 self.cursor = cursor 17 self.db = db 18 19 def set_dirty(self): 20 if self.db.is_managed(): 21 self.db.set_dirty() 22 23 def __getattr__(self, attr): 24 self.set_dirty() 25 if attr in self.__dict__: 26 return self.__dict__[attr] 27 else: 28 return getattr(self.cursor, attr) 29 30 def __iter__(self): 31 return iter(self.cursor) 32 33 34 class CursorDebugWrapper(CursorWrapper): 35 36 def execute(self, sql, params=()): 37 self.set_dirty() 38 start = time() 39 try: 40 return self.cursor.execute(sql, params) 41 finally: 42 stop = time() 43 duration = stop - start 44 sql = self.db.ops.last_executed_query(self.cursor, sql, params) 45 self.db.queries.append({ 46 'sql': sql, 47 'time': "%.3f" % duration, 48 }) 49 logger.debug('(%.3f) %s; args=%s' % (duration, sql, params), 50 extra={'duration': duration, 'sql': sql, 'params': params} 51 ) 52 53 def executemany(self, sql, param_list): 54 self.set_dirty() 55 start = time() 56 try: 57 return self.cursor.executemany(sql, param_list) 58 finally: 59 stop = time() 60 duration = stop - start 61 try: 62 times = len(param_list) 63 except TypeError: # param_list could be an iterator 64 times = '?' 65 self.db.queries.append({ 66 'sql': '%s times: %s' % (times, sql), 67 'time': "%.3f" % duration, 68 }) 69 logger.debug('(%.3f) %s; args=%s' % (duration, sql, param_list), 70 extra={'duration': duration, 'sql': sql, 'params': param_list} 71 ) 72 73 74 ############################################### 75 # Converters from database (string) to Python # 76 ############################################### 77 78 def typecast_date(s): 79 return s and datetime.date(*map(int, s.split('-'))) or None # returns None if s is null 80 81 def typecast_time(s): # does NOT store time zone information 82 if not s: return None 83 hour, minutes, seconds = s.split(':') 84 if '.' in seconds: # check whether seconds have a fractional part 85 seconds, microseconds = seconds.split('.') 86 else: 87 microseconds = '0' 88 return datetime.time(int(hour), int(minutes), int(seconds), int(float('.'+microseconds) * 1000000)) 89 90 def typecast_timestamp(s): # does NOT store time zone information 91 # "2005-07-29 15:48:00.590358-05" 92 # "2005-07-29 09:56:00-05" 93 if not s: return None 94 if not ' ' in s: return typecast_date(s) 95 d, t = s.split() 96 # Extract timezone information, if it exists. Currently we just throw 97 # it away, but in the future we may make use of it. 98 if '-' in t: 99 t, tz = t.split('-', 1) 100 tz = '-' + tz 101 elif '+' in t: 102 t, tz = t.split('+', 1) 103 tz = '+' + tz 104 else: 105 tz = '' 106 dates = d.split('-') 107 times = t.split(':') 108 seconds = times[2] 109 if '.' in seconds: # check whether seconds have a fractional part 110 seconds, microseconds = seconds.split('.') 111 else: 112 microseconds = '0' 113 tzinfo = utc if settings.USE_TZ else None 114 return datetime.datetime(int(dates[0]), int(dates[1]), int(dates[2]), 115 int(times[0]), int(times[1]), int(seconds), 116 int((microseconds + '000000')[:6]), tzinfo) 117 118 def typecast_decimal(s): 119 if s is None or s == '': 120 return None 121 return decimal.Decimal(s) 122 123 ############################################### 124 # Converters from Python to database (string) # 125 ############################################### 126 127 def rev_typecast_decimal(d): 128 if d is None: 129 return None 130 return str(d) 131 132 def truncate_name(name, length=None, hash_len=4): 133 """Shortens a string to a repeatable mangled version with the given length. 134 """ 135 if length is None or len(name) <= length: 136 return name 137 138 hsh = hashlib.md5(name).hexdigest()[:hash_len] 139 return '%s%s' % (name[:length-hash_len], hsh) 140 141 def format_number(value, max_digits, decimal_places): 142 """ 143 Formats a number into a string with the requisite number of digits and 144 decimal places. 145 """ 146 if isinstance(value, decimal.Decimal): 147 context = decimal.getcontext().copy() 148 context.prec = max_digits 149 return u'%s' % str(value.quantize(decimal.Decimal(".1") ** decimal_places, context=context)) 150 else: 151 return u"%.*f" % (decimal_places, value) 7 from django.db.backends.utils import * -
new file django/db/backends/utils.py
diff --git a/django/db/backends/utils.py b/django/db/backends/utils.py new file mode 100644 index 0000000..32e0f4f
- + 1 import datetime 2 import decimal 3 import hashlib 4 from time import time 5 6 from django.conf import settings 7 from django.utils.log import getLogger 8 from django.utils.timezone import utc 9 10 11 logger = getLogger('django.db.backends') 12 13 14 class CursorWrapper(object): 15 def __init__(self, cursor, db): 16 self.cursor = cursor 17 self.db = db 18 19 def set_dirty(self): 20 if self.db.is_managed(): 21 self.db.set_dirty() 22 23 def __getattr__(self, attr): 24 self.set_dirty() 25 if attr in self.__dict__: 26 return self.__dict__[attr] 27 else: 28 return getattr(self.cursor, attr) 29 30 def __iter__(self): 31 return iter(self.cursor) 32 33 34 class CursorDebugWrapper(CursorWrapper): 35 36 def execute(self, sql, params=()): 37 self.set_dirty() 38 start = time() 39 try: 40 return self.cursor.execute(sql, params) 41 finally: 42 stop = time() 43 duration = stop - start 44 sql = self.db.ops.last_executed_query(self.cursor, sql, params) 45 self.db.queries.append({ 46 'sql': sql, 47 'time': "%.3f" % duration, 48 }) 49 logger.debug('(%.3f) %s; args=%s' % (duration, sql, params), 50 extra={'duration': duration, 'sql': sql, 'params': params} 51 ) 52 53 def executemany(self, sql, param_list): 54 self.set_dirty() 55 start = time() 56 try: 57 return self.cursor.executemany(sql, param_list) 58 finally: 59 stop = time() 60 duration = stop - start 61 try: 62 times = len(param_list) 63 except TypeError: # param_list could be an iterator 64 times = '?' 65 self.db.queries.append({ 66 'sql': '%s times: %s' % (times, sql), 67 'time': "%.3f" % duration, 68 }) 69 logger.debug('(%.3f) %s; args=%s' % (duration, sql, param_list), 70 extra={'duration': duration, 'sql': sql, 'params': param_list} 71 ) 72 73 74 ############################################### 75 # Converters from database (string) to Python # 76 ############################################### 77 78 def typecast_date(s): 79 return s and datetime.date(*map(int, s.split('-'))) or None # returns None if s is null 80 81 def typecast_time(s): # does NOT store time zone information 82 if not s: return None 83 hour, minutes, seconds = s.split(':') 84 if '.' in seconds: # check whether seconds have a fractional part 85 seconds, microseconds = seconds.split('.') 86 else: 87 microseconds = '0' 88 return datetime.time(int(hour), int(minutes), int(seconds), int(float('.'+microseconds) * 1000000)) 89 90 def typecast_timestamp(s): # does NOT store time zone information 91 # "2005-07-29 15:48:00.590358-05" 92 # "2005-07-29 09:56:00-05" 93 if not s: return None 94 if not ' ' in s: return typecast_date(s) 95 d, t = s.split() 96 # Extract timezone information, if it exists. Currently we just throw 97 # it away, but in the future we may make use of it. 98 if '-' in t: 99 t, tz = t.split('-', 1) 100 tz = '-' + tz 101 elif '+' in t: 102 t, tz = t.split('+', 1) 103 tz = '+' + tz 104 else: 105 tz = '' 106 dates = d.split('-') 107 times = t.split(':') 108 seconds = times[2] 109 if '.' in seconds: # check whether seconds have a fractional part 110 seconds, microseconds = seconds.split('.') 111 else: 112 microseconds = '0' 113 tzinfo = utc if settings.USE_TZ else None 114 return datetime.datetime(int(dates[0]), int(dates[1]), int(dates[2]), 115 int(times[0]), int(times[1]), int(seconds), 116 int((microseconds + '000000')[:6]), tzinfo) 117 118 def typecast_decimal(s): 119 if s is None or s == '': 120 return None 121 return decimal.Decimal(s) 122 123 ############################################### 124 # Converters from Python to database (string) # 125 ############################################### 126 127 def rev_typecast_decimal(d): 128 if d is None: 129 return None 130 return str(d) 131 132 def truncate_name(name, length=None, hash_len=4): 133 """Shortens a string to a repeatable mangled version with the given length. 134 """ 135 if length is None or len(name) <= length: 136 return name 137 138 hsh = hashlib.md5(name).hexdigest()[:hash_len] 139 return '%s%s' % (name[:length-hash_len], hsh) 140 141 def format_number(value, max_digits, decimal_places): 142 """ 143 Formats a number into a string with the requisite number of digits and 144 decimal places. 145 """ 146 if isinstance(value, decimal.Decimal): 147 context = decimal.getcontext().copy() 148 context.prec = max_digits 149 return u'%s' % str(value.quantize(decimal.Decimal(".1") ** decimal_places, context=context)) 150 else: 151 return u"%.*f" % (decimal_places, value) -
django/db/models/fields/__init__.py
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 22546c2..debdacf 100644
a b class DecimalField(Field): 860 860 Formats a number into a string with the requisite number of digits and 861 861 decimal places. 862 862 """ 863 # Method moved to django.db.backends.util .863 # Method moved to django.db.backends.utils. 864 864 # 865 865 # It is preserved because it is used by the oracle backend 866 866 # (django.db.backends.oracle.query), and also for 867 867 # backwards-compatibility with any external code which may have used 868 868 # this method. 869 from django.db.backends import util 870 return util .format_number(value, self.max_digits, self.decimal_places)869 from django.db.backends import utils 870 return utils.format_number(value, self.max_digits, self.decimal_places) 871 871 872 872 def get_db_prep_save(self, value, connection): 873 873 return connection.ops.value_to_db_decimal(self.to_python(value), -
django/db/models/fields/related.py
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index e23c7dc..ab0c74e 100644
a b 1 1 from operator import attrgetter 2 2 3 3 from django.db import connection, router 4 from django.db.backends import util 4 from django.db.backends import utils 5 5 from django.db.models import signals, get_model 6 6 from django.db.models.fields import (AutoField, Field, IntegerField, 7 7 PositiveIntegerField, PositiveSmallIntegerField, FieldDoesNotExist) … … class ManyToManyField(RelatedField, Field): 1130 1130 elif self.db_table: 1131 1131 return self.db_table 1132 1132 else: 1133 return util .truncate_name('%s_%s' % (opts.db_table, self.name),1133 return utils.truncate_name('%s_%s' % (opts.db_table, self.name), 1134 1134 connection.ops.max_name_length()) 1135 1135 1136 1136 def _get_m2m_attr(self, related, attr): -
django/db/models/options.py
diff --git a/django/db/models/options.py b/django/db/models/options.py index e13a496..4bf45d7 100644
a b class Options(object): 65 65 66 66 def contribute_to_class(self, cls, name): 67 67 from django.db import connection 68 from django.db.backends.util import truncate_name68 from django.db.backends.utils import truncate_name 69 69 70 70 cls._meta = self 71 71 self.installed = re.sub('\.models$', '', cls.__module__) in settings.INSTALLED_APPS -
django/db/models/query_utils.py
diff --git a/django/db/models/query_utils.py b/django/db/models/query_utils.py index a56ab5c..8e9d770 100644
a b circular import difficulties. 8 8 9 9 import weakref 10 10 11 from django.db.backends import util 11 from django.db.backends import utils 12 12 from django.utils import tree 13 13 14 14 … … def deferred_class_factory(model, attrs): 155 155 # name using the passed in attrs. It's OK to reuse an existing class 156 156 # object if the attrs are identical. 157 157 name = "%s_Deferred_%s" % (model.__name__, '_'.join(sorted(list(attrs)))) 158 name = util .truncate_name(name, 80, 32)158 name = utils.truncate_name(name, 80, 32) 159 159 160 160 overrides = dict([(attr, DeferredAttribute(attr, model)) 161 161 for attr in attrs]) -
django/db/models/sql/compiler.py
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index 6c516e2..95841cd 100644
a b from itertools import izip 2 2 3 3 from django.core.exceptions import FieldError 4 4 from django.db import transaction 5 from django.db.backends.util import truncate_name5 from django.db.backends.utils import truncate_name 6 6 from django.db.models.query_utils import select_related_descend 7 7 from django.db.models.sql.constants import * 8 8 from django.db.models.sql.datastructures import EmptyResultSet … … class SQLDateCompiler(SQLCompiler): 1067 1067 from django.db.models.fields import DateTimeField 1068 1068 fields = [DateTimeField()] 1069 1069 else: 1070 from django.db.backends.util import typecast_timestamp1070 from django.db.backends.utils import typecast_timestamp 1071 1071 needs_string_cast = self.connection.features.needs_datetime_string_cast 1072 1072 1073 1073 offset = len(self.query.extra_select) -
django/forms/fields.py
diff --git a/django/forms/fields.py b/django/forms/fields.py index 96ecabf..61f57e0 100644
a b except ImportError: 17 17 18 18 from django.core import validators 19 19 from django.core.exceptions import ValidationError 20 from django.forms.util import ErrorList, from_current_timezone, to_current_timezone20 from django.forms.utils import ErrorList, from_current_timezone, to_current_timezone 21 21 from django.forms.widgets import (TextInput, PasswordInput, HiddenInput, 22 22 MultipleHiddenInput, ClearableFileInput, CheckboxInput, Select, 23 23 NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput, -
django/forms/forms.py
diff --git a/django/forms/forms.py b/django/forms/forms.py index 94eb22d..155ee90 100644
a b import copy 8 8 9 9 from django.core.exceptions import ValidationError 10 10 from django.forms.fields import Field, FileField 11 from django.forms.util import flatatt, ErrorDict, ErrorList11 from django.forms.utils import flatatt, ErrorDict, ErrorList 12 12 from django.forms.widgets import Media, media_property, TextInput, Textarea 13 13 from django.utils.datastructures import SortedDict 14 14 from django.utils.html import conditional_escape -
django/forms/formsets.py
diff --git a/django/forms/formsets.py b/django/forms/formsets.py index dcd2f01..2736ed8 100644
a b from __future__ import absolute_import 3 3 from django.core.exceptions import ValidationError 4 4 from django.forms import Form 5 5 from django.forms.fields import IntegerField, BooleanField 6 from django.forms.util import ErrorList6 from django.forms.utils import ErrorList 7 7 from django.forms.widgets import Media, HiddenInput 8 8 from django.utils.encoding import StrAndUnicode 9 9 from django.utils.safestring import mark_safe -
django/forms/models.py
diff --git a/django/forms/models.py b/django/forms/models.py index cd8f027..730f3ee 100644
a b from django.core.validators import EMPTY_VALUES 10 10 from django.forms.fields import Field, ChoiceField 11 11 from django.forms.forms import BaseForm, get_declared_fields 12 12 from django.forms.formsets import BaseFormSet, formset_factory 13 from django.forms.util import ErrorList13 from django.forms.utils import ErrorList 14 14 from django.forms.widgets import (SelectMultiple, HiddenInput, 15 15 MultipleHiddenInput, media_property) 16 16 from django.utils.encoding import smart_unicode, force_unicode -
django/forms/util.py
diff --git a/django/forms/util.py b/django/forms/util.py index 886f08e..6b14b92 100644
a b 1 from django.conf import settings 2 from django.utils.html import conditional_escape 3 from django.utils.encoding import StrAndUnicode, force_unicode 4 from django.utils.safestring import mark_safe 5 from django.utils import timezone 6 from django.utils.translation import ugettext_lazy as _ 1 import warnings 7 2 8 # Import ValidationError so that it can be imported from this 9 # module to maintain backwards compatibility. 10 from django.core.exceptions import ValidationError 3 warnings.warn("The django.forms.util module has been renamed " 4 "(https://code.djangoproject.com/ticket/17627/). " 5 "Use django.forms.utils instead.", PendingDeprecationWarning) 11 6 12 def flatatt(attrs): 13 """ 14 Convert a dictionary of attributes to a single string. 15 The returned string will contain a leading space followed by key="value", 16 XML-style pairs. It is assumed that the keys do not need to be XML-escaped. 17 If the passed dictionary is empty, then return an empty string. 18 """ 19 return u''.join([u' %s="%s"' % (k, conditional_escape(v)) for k, v in attrs.items()]) 20 21 class ErrorDict(dict, StrAndUnicode): 22 """ 23 A collection of errors that knows how to display itself in various formats. 24 25 The dictionary keys are the field names, and the values are the errors. 26 """ 27 def __unicode__(self): 28 return self.as_ul() 29 30 def as_ul(self): 31 if not self: return u'' 32 return mark_safe(u'<ul class="errorlist">%s</ul>' 33 % ''.join([u'<li>%s%s</li>' % (k, conditional_escape(force_unicode(v))) 34 for k, v in self.items()])) 35 36 def as_text(self): 37 return u'\n'.join([u'* %s\n%s' % (k, u'\n'.join([u' * %s' % force_unicode(i) for i in v])) for k, v in self.items()]) 38 39 class ErrorList(list, StrAndUnicode): 40 """ 41 A collection of errors that knows how to display itself in various formats. 42 """ 43 def __unicode__(self): 44 return self.as_ul() 45 46 def as_ul(self): 47 if not self: return u'' 48 return mark_safe(u'<ul class="errorlist">%s</ul>' 49 % ''.join([u'<li>%s</li>' % conditional_escape(force_unicode(e)) for e in self])) 50 51 def as_text(self): 52 if not self: return u'' 53 return u'\n'.join([u'* %s' % force_unicode(e) for e in self]) 54 55 def __repr__(self): 56 return repr([force_unicode(e) for e in self]) 57 58 # Utilities for time zone support in DateTimeField et al. 59 60 def from_current_timezone(value): 61 """ 62 When time zone support is enabled, convert naive datetimes 63 entered in the current time zone to aware datetimes. 64 """ 65 if settings.USE_TZ and value is not None and timezone.is_naive(value): 66 current_timezone = timezone.get_current_timezone() 67 try: 68 return timezone.make_aware(value, current_timezone) 69 except Exception, e: 70 raise ValidationError(_('%(datetime)s couldn\'t be interpreted ' 71 'in time zone %(current_timezone)s; it ' 72 'may be ambiguous or it may not exist.') 73 % {'datetime': value, 74 'current_timezone': current_timezone}) 75 return value 76 77 def to_current_timezone(value): 78 """ 79 When time zone support is enabled, convert aware datetimes 80 to naive dateimes in the current time zone for display. 81 """ 82 if settings.USE_TZ and value is not None and timezone.is_aware(value): 83 current_timezone = timezone.get_current_timezone() 84 return timezone.make_naive(value, current_timezone) 85 return value 7 from django.forms.utils import * -
new file django/forms/utils.py
diff --git a/django/forms/utils.py b/django/forms/utils.py new file mode 100644 index 0000000..886f08e
- + 1 from django.conf import settings 2 from django.utils.html import conditional_escape 3 from django.utils.encoding import StrAndUnicode, force_unicode 4 from django.utils.safestring import mark_safe 5 from django.utils import timezone 6 from django.utils.translation import ugettext_lazy as _ 7 8 # Import ValidationError so that it can be imported from this 9 # module to maintain backwards compatibility. 10 from django.core.exceptions import ValidationError 11 12 def flatatt(attrs): 13 """ 14 Convert a dictionary of attributes to a single string. 15 The returned string will contain a leading space followed by key="value", 16 XML-style pairs. It is assumed that the keys do not need to be XML-escaped. 17 If the passed dictionary is empty, then return an empty string. 18 """ 19 return u''.join([u' %s="%s"' % (k, conditional_escape(v)) for k, v in attrs.items()]) 20 21 class ErrorDict(dict, StrAndUnicode): 22 """ 23 A collection of errors that knows how to display itself in various formats. 24 25 The dictionary keys are the field names, and the values are the errors. 26 """ 27 def __unicode__(self): 28 return self.as_ul() 29 30 def as_ul(self): 31 if not self: return u'' 32 return mark_safe(u'<ul class="errorlist">%s</ul>' 33 % ''.join([u'<li>%s%s</li>' % (k, conditional_escape(force_unicode(v))) 34 for k, v in self.items()])) 35 36 def as_text(self): 37 return u'\n'.join([u'* %s\n%s' % (k, u'\n'.join([u' * %s' % force_unicode(i) for i in v])) for k, v in self.items()]) 38 39 class ErrorList(list, StrAndUnicode): 40 """ 41 A collection of errors that knows how to display itself in various formats. 42 """ 43 def __unicode__(self): 44 return self.as_ul() 45 46 def as_ul(self): 47 if not self: return u'' 48 return mark_safe(u'<ul class="errorlist">%s</ul>' 49 % ''.join([u'<li>%s</li>' % conditional_escape(force_unicode(e)) for e in self])) 50 51 def as_text(self): 52 if not self: return u'' 53 return u'\n'.join([u'* %s' % force_unicode(e) for e in self]) 54 55 def __repr__(self): 56 return repr([force_unicode(e) for e in self]) 57 58 # Utilities for time zone support in DateTimeField et al. 59 60 def from_current_timezone(value): 61 """ 62 When time zone support is enabled, convert naive datetimes 63 entered in the current time zone to aware datetimes. 64 """ 65 if settings.USE_TZ and value is not None and timezone.is_naive(value): 66 current_timezone = timezone.get_current_timezone() 67 try: 68 return timezone.make_aware(value, current_timezone) 69 except Exception, e: 70 raise ValidationError(_('%(datetime)s couldn\'t be interpreted ' 71 'in time zone %(current_timezone)s; it ' 72 'may be ambiguous or it may not exist.') 73 % {'datetime': value, 74 'current_timezone': current_timezone}) 75 return value 76 77 def to_current_timezone(value): 78 """ 79 When time zone support is enabled, convert aware datetimes 80 to naive dateimes in the current time zone for display. 81 """ 82 if settings.USE_TZ and value is not None and timezone.is_aware(value): 83 current_timezone = timezone.get_current_timezone() 84 return timezone.make_naive(value, current_timezone) 85 return value -
django/forms/widgets.py
diff --git a/django/forms/widgets.py b/django/forms/widgets.py index 1fbef98..74e3043 100644
a b from itertools import chain 10 10 from urlparse import urljoin 11 11 12 12 from django.conf import settings 13 from django.forms.util import flatatt, to_current_timezone13 from django.forms.utils import flatatt, to_current_timezone 14 14 from django.utils.datastructures import MultiValueDict, MergeDict 15 15 from django.utils.html import escape, conditional_escape 16 16 from django.utils.translation import ugettext, ugettext_lazy -
docs/internals/deprecation.txt
diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index cb91a1c..f9bfa37 100644
a b these changes. 271 271 in 1.4. The backward compatibility will be removed -- 272 272 ``HttpRequest.raw_post_data`` will no longer work. 273 273 274 1.7 275 --- 276 277 * Instances of ``util.py`` in the Django codebase have been renamed to ``utils.py`` in 278 an effort to unify all util and utils references across Django. Compatibility modules 279 for ``django.contrib.admin.util`` (now :mod:`django.contrib.admin.utils`), 280 ``django.contrib.gis.db.backends.util`` (now :mod:`django.contrib.gis.db.backends.utils``), 281 ``django.contrib.localflavor.it.util`` (now :mod:`django.contrib.localflavor.it.utils``), 282 ``django.contrib.localflavor.uy.util`` (now :mod:`django.contrib.localflavor.uy.utils``), 283 ``django.db.backends.util`` (now :mod:`django.db.backends.utils`), 284 and ``django.forms.util`` (now :mod:`django.forms.utils`) will be removed. 285 274 286 2.0 275 287 --- 276 288 -
deleted file tests/regressiontests/admin_util/models.py
diff --git a/tests/regressiontests/admin_util/__init__.py b/tests/regressiontests/admin_util/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/regressiontests/admin_util/models.py b/tests/regressiontests/admin_util/models.py deleted file mode 100644 index 0e81df3..0000000
+ - 1 from django.db import models2 3 4 class Article(models.Model):5 """6 A simple Article model for testing7 """8 site = models.ForeignKey('sites.Site', related_name="admin_articles")9 title = models.CharField(max_length=100)10 title2 = models.CharField(max_length=100, verbose_name="another name")11 created = models.DateTimeField()12 13 def test_from_model(self):14 return "nothing"15 16 def test_from_model_with_override(self):17 return "nothing"18 test_from_model_with_override.short_description = "not What you Expect"19 20 class Count(models.Model):21 num = models.PositiveSmallIntegerField()22 parent = models.ForeignKey('self', null=True)23 24 def __unicode__(self):25 return unicode(self.num)26 27 class Event(models.Model):28 date = models.DateTimeField(auto_now_add=True)29 30 class Location(models.Model):31 event = models.OneToOneField(Event, verbose_name='awesome event')32 33 class Guest(models.Model):34 event = models.OneToOneField(Event)35 name = models.CharField(max_length=255)36 37 class Meta:38 verbose_name = "awesome guest" -
deleted file tests/regressiontests/admin_util/tests.py
diff --git a/tests/regressiontests/admin_util/tests.py b/tests/regressiontests/admin_util/tests.py deleted file mode 100644 index 8113f2e..0000000
+ - 1 from __future__ import absolute_import2 3 from datetime import datetime4 5 from django.conf import settings6 from django.contrib import admin7 from django.contrib.admin import helpers8 from django.contrib.admin.util import (display_for_field, label_for_field,9 lookup_field, NestedObjects)10 from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE11 from django.contrib.sites.models import Site12 from django.db import models, DEFAULT_DB_ALIAS13 from django import forms14 from django.test import TestCase15 from django.utils import unittest16 from django.utils.formats import localize17 from django.utils.safestring import mark_safe18 19 from .models import Article, Count, Event, Location20 21 22 class NestedObjectsTests(TestCase):23 """24 Tests for ``NestedObject`` utility collection.25 26 """27 def setUp(self):28 self.n = NestedObjects(using=DEFAULT_DB_ALIAS)29 self.objs = [Count.objects.create(num=i) for i in range(5)]30 31 def _check(self, target):32 self.assertEqual(self.n.nested(lambda obj: obj.num), target)33 34 def _connect(self, i, j):35 self.objs[i].parent = self.objs[j]36 self.objs[i].save()37 38 def _collect(self, *indices):39 self.n.collect([self.objs[i] for i in indices])40 41 def test_unrelated_roots(self):42 self._connect(2, 1)43 self._collect(0)44 self._collect(1)45 self._check([0, 1, [2]])46 47 def test_siblings(self):48 self._connect(1, 0)49 self._connect(2, 0)50 self._collect(0)51 self._check([0, [1, 2]])52 53 def test_non_added_parent(self):54 self._connect(0, 1)55 self._collect(0)56 self._check([0])57 58 def test_cyclic(self):59 self._connect(0, 2)60 self._connect(1, 0)61 self._connect(2, 1)62 self._collect(0)63 self._check([0, [1, [2]]])64 65 def test_queries(self):66 self._connect(1, 0)67 self._connect(2, 0)68 # 1 query to fetch all children of 0 (1 and 2)69 # 1 query to fetch all children of 1 and 2 (none)70 # Should not require additional queries to populate the nested graph.71 self.assertNumQueries(2, self._collect, 0)72 73 class UtilTests(unittest.TestCase):74 def test_values_from_lookup_field(self):75 """76 Regression test for #12654: lookup_field77 """78 SITE_NAME = 'example.com'79 TITLE_TEXT = 'Some title'80 CREATED_DATE = datetime.min81 ADMIN_METHOD = 'admin method'82 SIMPLE_FUNCTION = 'function'83 INSTANCE_ATTRIBUTE = 'attr'84 85 class MockModelAdmin(object):86 def get_admin_value(self, obj):87 return ADMIN_METHOD88 89 simple_function = lambda obj: SIMPLE_FUNCTION90 91 article = Article(92 site=Site(domain=SITE_NAME),93 title=TITLE_TEXT,94 created=CREATED_DATE,95 )96 article.non_field = INSTANCE_ATTRIBUTE97 98 verifications = (99 ('site', SITE_NAME),100 ('created', localize(CREATED_DATE)),101 ('title', TITLE_TEXT),102 ('get_admin_value', ADMIN_METHOD),103 (simple_function, SIMPLE_FUNCTION),104 ('test_from_model', article.test_from_model()),105 ('non_field', INSTANCE_ATTRIBUTE)106 )107 108 mock_admin = MockModelAdmin()109 for name, value in verifications:110 field, attr, resolved_value = lookup_field(name, article, mock_admin)111 112 if field is not None:113 resolved_value = display_for_field(resolved_value, field)114 115 self.assertEqual(value, resolved_value)116 117 def test_null_display_for_field(self):118 """119 Regression test for #12550: display_for_field should handle None120 value.121 """122 display_value = display_for_field(None, models.CharField())123 self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE)124 125 display_value = display_for_field(None, models.CharField(126 choices=(127 (None, "test_none"),128 )129 ))130 self.assertEqual(display_value, "test_none")131 132 display_value = display_for_field(None, models.DateField())133 self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE)134 135 display_value = display_for_field(None, models.TimeField())136 self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE)137 138 # Regression test for #13071: NullBooleanField has special139 # handling.140 display_value = display_for_field(None, models.NullBooleanField())141 expected = u'<img src="%sadmin/img/icon-unknown.gif" alt="None" />' % settings.STATIC_URL142 self.assertEqual(display_value, expected)143 144 display_value = display_for_field(None, models.DecimalField())145 self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE)146 147 display_value = display_for_field(None, models.FloatField())148 self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE)149 150 def test_label_for_field(self):151 """152 Tests for label_for_field153 """154 self.assertEqual(155 label_for_field("title", Article),156 "title"157 )158 self.assertEqual(159 label_for_field("title2", Article),160 "another name"161 )162 self.assertEqual(163 label_for_field("title2", Article, return_attr=True),164 ("another name", None)165 )166 167 self.assertEqual(168 label_for_field("__unicode__", Article),169 "article"170 )171 self.assertEqual(172 label_for_field("__str__", Article),173 "article"174 )175 176 self.assertRaises(177 AttributeError,178 lambda: label_for_field("unknown", Article)179 )180 181 def test_callable(obj):182 return "nothing"183 self.assertEqual(184 label_for_field(test_callable, Article),185 "Test callable"186 )187 self.assertEqual(188 label_for_field(test_callable, Article, return_attr=True),189 ("Test callable", test_callable)190 )191 192 self.assertEqual(193 label_for_field("test_from_model", Article),194 "Test from model"195 )196 self.assertEqual(197 label_for_field("test_from_model", Article, return_attr=True),198 ("Test from model", Article.test_from_model)199 )200 self.assertEqual(201 label_for_field("test_from_model_with_override", Article),202 "not What you Expect"203 )204 205 self.assertEqual(206 label_for_field(lambda x: "nothing", Article),207 "--"208 )209 210 class MockModelAdmin(object):211 def test_from_model(self, obj):212 return "nothing"213 test_from_model.short_description = "not Really the Model"214 215 self.assertEqual(216 label_for_field("test_from_model", Article, model_admin=MockModelAdmin),217 "not Really the Model"218 )219 self.assertEqual(220 label_for_field("test_from_model", Article,221 model_admin = MockModelAdmin,222 return_attr = True223 ),224 ("not Really the Model", MockModelAdmin.test_from_model)225 )226 227 def test_related_name(self):228 """229 Regression test for #13963230 """231 self.assertEqual(232 label_for_field('location', Event, return_attr=True),233 ('location', None),234 )235 self.assertEqual(236 label_for_field('event', Location, return_attr=True),237 ('awesome event', None),238 )239 self.assertEqual(240 label_for_field('guest', Event, return_attr=True),241 ('awesome guest', None),242 )243 244 def test_logentry_unicode(self):245 """246 Regression test for #15661247 """248 log_entry = admin.models.LogEntry()249 250 log_entry.action_flag = admin.models.ADDITION251 self.assertTrue(252 unicode(log_entry).startswith('Added ')253 )254 255 log_entry.action_flag = admin.models.CHANGE256 self.assertTrue(257 unicode(log_entry).startswith('Changed ')258 )259 260 log_entry.action_flag = admin.models.DELETION261 self.assertTrue(262 unicode(log_entry).startswith('Deleted ')263 )264 265 def test_safestring_in_field_label(self):266 # safestring should not be escaped267 class MyForm(forms.Form):268 text = forms.CharField(label=mark_safe('<i>text</i>'))269 cb = forms.BooleanField(label=mark_safe('<i>cb</i>'))270 271 form = MyForm()272 self.assertEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(),273 '<label for="id_text" class="required inline"><i>text</i>:</label>')274 self.assertEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(),275 '<label for="id_cb" class="vCheckboxLabel required inline"><i>cb</i></label>')276 277 # normal strings needs to be escaped278 class MyForm(forms.Form):279 text = forms.CharField(label='&text')280 cb = forms.BooleanField(label='&cb')281 282 form = MyForm()283 self.assertEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(),284 '<label for="id_text" class="required inline">&text:</label>')285 self.assertEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(),286 '<label for="id_cb" class="vCheckboxLabel required inline">&cb</label>') -
new file tests/regressiontests/admin_utils/models.py
diff --git a/tests/regressiontests/admin_utils/__init__.py b/tests/regressiontests/admin_utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/regressiontests/admin_utils/models.py b/tests/regressiontests/admin_utils/models.py new file mode 100644 index 0000000..0e81df3
- + 1 from django.db import models 2 3 4 class Article(models.Model): 5 """ 6 A simple Article model for testing 7 """ 8 site = models.ForeignKey('sites.Site', related_name="admin_articles") 9 title = models.CharField(max_length=100) 10 title2 = models.CharField(max_length=100, verbose_name="another name") 11 created = models.DateTimeField() 12 13 def test_from_model(self): 14 return "nothing" 15 16 def test_from_model_with_override(self): 17 return "nothing" 18 test_from_model_with_override.short_description = "not What you Expect" 19 20 class Count(models.Model): 21 num = models.PositiveSmallIntegerField() 22 parent = models.ForeignKey('self', null=True) 23 24 def __unicode__(self): 25 return unicode(self.num) 26 27 class Event(models.Model): 28 date = models.DateTimeField(auto_now_add=True) 29 30 class Location(models.Model): 31 event = models.OneToOneField(Event, verbose_name='awesome event') 32 33 class Guest(models.Model): 34 event = models.OneToOneField(Event) 35 name = models.CharField(max_length=255) 36 37 class Meta: 38 verbose_name = "awesome guest" -
new file tests/regressiontests/admin_utils/tests.py
diff --git a/tests/regressiontests/admin_utils/tests.py b/tests/regressiontests/admin_utils/tests.py new file mode 100644 index 0000000..d7eaabe
- + 1 from __future__ import absolute_import 2 3 from datetime import datetime 4 5 from django.conf import settings 6 from django.contrib import admin 7 from django.contrib.admin import helpers 8 from django.contrib.admin.utils import (display_for_field, label_for_field, 9 lookup_field, NestedObjects) 10 from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE 11 from django.contrib.sites.models import Site 12 from django.db import models, DEFAULT_DB_ALIAS 13 from django import forms 14 from django.test import TestCase 15 from django.utils import unittest 16 from django.utils.formats import localize 17 from django.utils.safestring import mark_safe 18 19 from .models import Article, Count, Event, Location 20 21 22 class NestedObjectsTests(TestCase): 23 """ 24 Tests for ``NestedObject`` utility collection. 25 26 """ 27 def setUp(self): 28 self.n = NestedObjects(using=DEFAULT_DB_ALIAS) 29 self.objs = [Count.objects.create(num=i) for i in range(5)] 30 31 def _check(self, target): 32 self.assertEqual(self.n.nested(lambda obj: obj.num), target) 33 34 def _connect(self, i, j): 35 self.objs[i].parent = self.objs[j] 36 self.objs[i].save() 37 38 def _collect(self, *indices): 39 self.n.collect([self.objs[i] for i in indices]) 40 41 def test_unrelated_roots(self): 42 self._connect(2, 1) 43 self._collect(0) 44 self._collect(1) 45 self._check([0, 1, [2]]) 46 47 def test_siblings(self): 48 self._connect(1, 0) 49 self._connect(2, 0) 50 self._collect(0) 51 self._check([0, [1, 2]]) 52 53 def test_non_added_parent(self): 54 self._connect(0, 1) 55 self._collect(0) 56 self._check([0]) 57 58 def test_cyclic(self): 59 self._connect(0, 2) 60 self._connect(1, 0) 61 self._connect(2, 1) 62 self._collect(0) 63 self._check([0, [1, [2]]]) 64 65 def test_queries(self): 66 self._connect(1, 0) 67 self._connect(2, 0) 68 # 1 query to fetch all children of 0 (1 and 2) 69 # 1 query to fetch all children of 1 and 2 (none) 70 # Should not require additional queries to populate the nested graph. 71 self.assertNumQueries(2, self._collect, 0) 72 73 class UtilTests(unittest.TestCase): 74 def test_values_from_lookup_field(self): 75 """ 76 Regression test for #12654: lookup_field 77 """ 78 SITE_NAME = 'example.com' 79 TITLE_TEXT = 'Some title' 80 CREATED_DATE = datetime.min 81 ADMIN_METHOD = 'admin method' 82 SIMPLE_FUNCTION = 'function' 83 INSTANCE_ATTRIBUTE = 'attr' 84 85 class MockModelAdmin(object): 86 def get_admin_value(self, obj): 87 return ADMIN_METHOD 88 89 simple_function = lambda obj: SIMPLE_FUNCTION 90 91 article = Article( 92 site=Site(domain=SITE_NAME), 93 title=TITLE_TEXT, 94 created=CREATED_DATE, 95 ) 96 article.non_field = INSTANCE_ATTRIBUTE 97 98 verifications = ( 99 ('site', SITE_NAME), 100 ('created', localize(CREATED_DATE)), 101 ('title', TITLE_TEXT), 102 ('get_admin_value', ADMIN_METHOD), 103 (simple_function, SIMPLE_FUNCTION), 104 ('test_from_model', article.test_from_model()), 105 ('non_field', INSTANCE_ATTRIBUTE) 106 ) 107 108 mock_admin = MockModelAdmin() 109 for name, value in verifications: 110 field, attr, resolved_value = lookup_field(name, article, mock_admin) 111 112 if field is not None: 113 resolved_value = display_for_field(resolved_value, field) 114 115 self.assertEqual(value, resolved_value) 116 117 def test_null_display_for_field(self): 118 """ 119 Regression test for #12550: display_for_field should handle None 120 value. 121 """ 122 display_value = display_for_field(None, models.CharField()) 123 self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE) 124 125 display_value = display_for_field(None, models.CharField( 126 choices=( 127 (None, "test_none"), 128 ) 129 )) 130 self.assertEqual(display_value, "test_none") 131 132 display_value = display_for_field(None, models.DateField()) 133 self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE) 134 135 display_value = display_for_field(None, models.TimeField()) 136 self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE) 137 138 # Regression test for #13071: NullBooleanField has special 139 # handling. 140 display_value = display_for_field(None, models.NullBooleanField()) 141 expected = u'<img src="%sadmin/img/icon-unknown.gif" alt="None" />' % settings.STATIC_URL 142 self.assertEqual(display_value, expected) 143 144 display_value = display_for_field(None, models.DecimalField()) 145 self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE) 146 147 display_value = display_for_field(None, models.FloatField()) 148 self.assertEqual(display_value, EMPTY_CHANGELIST_VALUE) 149 150 def test_label_for_field(self): 151 """ 152 Tests for label_for_field 153 """ 154 self.assertEqual( 155 label_for_field("title", Article), 156 "title" 157 ) 158 self.assertEqual( 159 label_for_field("title2", Article), 160 "another name" 161 ) 162 self.assertEqual( 163 label_for_field("title2", Article, return_attr=True), 164 ("another name", None) 165 ) 166 167 self.assertEqual( 168 label_for_field("__unicode__", Article), 169 "article" 170 ) 171 self.assertEqual( 172 label_for_field("__str__", Article), 173 "article" 174 ) 175 176 self.assertRaises( 177 AttributeError, 178 lambda: label_for_field("unknown", Article) 179 ) 180 181 def test_callable(obj): 182 return "nothing" 183 self.assertEqual( 184 label_for_field(test_callable, Article), 185 "Test callable" 186 ) 187 self.assertEqual( 188 label_for_field(test_callable, Article, return_attr=True), 189 ("Test callable", test_callable) 190 ) 191 192 self.assertEqual( 193 label_for_field("test_from_model", Article), 194 "Test from model" 195 ) 196 self.assertEqual( 197 label_for_field("test_from_model", Article, return_attr=True), 198 ("Test from model", Article.test_from_model) 199 ) 200 self.assertEqual( 201 label_for_field("test_from_model_with_override", Article), 202 "not What you Expect" 203 ) 204 205 self.assertEqual( 206 label_for_field(lambda x: "nothing", Article), 207 "--" 208 ) 209 210 class MockModelAdmin(object): 211 def test_from_model(self, obj): 212 return "nothing" 213 test_from_model.short_description = "not Really the Model" 214 215 self.assertEqual( 216 label_for_field("test_from_model", Article, model_admin=MockModelAdmin), 217 "not Really the Model" 218 ) 219 self.assertEqual( 220 label_for_field("test_from_model", Article, 221 model_admin = MockModelAdmin, 222 return_attr = True 223 ), 224 ("not Really the Model", MockModelAdmin.test_from_model) 225 ) 226 227 def test_related_name(self): 228 """ 229 Regression test for #13963 230 """ 231 self.assertEqual( 232 label_for_field('location', Event, return_attr=True), 233 ('location', None), 234 ) 235 self.assertEqual( 236 label_for_field('event', Location, return_attr=True), 237 ('awesome event', None), 238 ) 239 self.assertEqual( 240 label_for_field('guest', Event, return_attr=True), 241 ('awesome guest', None), 242 ) 243 244 def test_logentry_unicode(self): 245 """ 246 Regression test for #15661 247 """ 248 log_entry = admin.models.LogEntry() 249 250 log_entry.action_flag = admin.models.ADDITION 251 self.assertTrue( 252 unicode(log_entry).startswith('Added ') 253 ) 254 255 log_entry.action_flag = admin.models.CHANGE 256 self.assertTrue( 257 unicode(log_entry).startswith('Changed ') 258 ) 259 260 log_entry.action_flag = admin.models.DELETION 261 self.assertTrue( 262 unicode(log_entry).startswith('Deleted ') 263 ) 264 265 def test_safestring_in_field_label(self): 266 # safestring should not be escaped 267 class MyForm(forms.Form): 268 text = forms.CharField(label=mark_safe('<i>text</i>')) 269 cb = forms.BooleanField(label=mark_safe('<i>cb</i>')) 270 271 form = MyForm() 272 self.assertEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(), 273 '<label for="id_text" class="required inline"><i>text</i>:</label>') 274 self.assertEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(), 275 '<label for="id_cb" class="vCheckboxLabel required inline"><i>cb</i></label>') 276 277 # normal strings needs to be escaped 278 class MyForm(forms.Form): 279 text = forms.CharField(label='&text') 280 cb = forms.BooleanField(label='&cb') 281 282 form = MyForm() 283 self.assertEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(), 284 '<label for="id_text" class="required inline">&text:</label>') 285 self.assertEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(), 286 '<label for="id_cb" class="vCheckboxLabel required inline">&cb</label>') -
tests/regressiontests/admin_views/admin.py
diff --git a/tests/regressiontests/admin_views/admin.py b/tests/regressiontests/admin_views/admin.py index d960749..86cd039 100644
a b site.register(UnorderedObject, UnorderedObjectAdmin) 625 625 # related OneToOne object not registered in admin 626 626 # when deleting Book so as exercise all four troublesome (w.r.t escaping 627 627 # and calling force_unicode to avoid problems on Python 2.3) paths through 628 # contrib.admin.util 's get_deleted_objects function.628 # contrib.admin.utils's get_deleted_objects function. 629 629 site.register(Book, inlines=[ChapterInline]) 630 630 site.register(Promo) 631 631 site.register(ChapterXtra1, ChapterXtra1Admin) -
tests/regressiontests/admin_views/tests.py
diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py index 5241d26..0652e81 100755
a b from django.contrib import admin 16 16 from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME 17 17 from django.contrib.admin.models import LogEntry, DELETION 18 18 from django.contrib.admin.sites import LOGIN_FORM_KEY 19 from django.contrib.admin.util import quote19 from django.contrib.admin.utils import quote 20 20 from django.contrib.admin.views.main import IS_POPUP_VAR 21 21 from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase 22 22 from django.contrib.auth import REDIRECT_FIELD_NAME 23 23 from django.contrib.auth.models import Group, User, Permission, UNUSABLE_PASSWORD 24 24 from django.contrib.contenttypes.models import ContentType 25 from django.forms.util import ErrorList25 from django.forms.utils import ErrorList 26 26 from django.template import context as context_module 27 27 from django.template.response import TemplateResponse 28 28 from django.test import TestCase -
tests/regressiontests/db_typecasts/tests.py
diff --git a/tests/regressiontests/db_typecasts/tests.py b/tests/regressiontests/db_typecasts/tests.py index 83bd1e6..c905a6d 100644
a b 2 2 3 3 import datetime 4 4 5 from django.db.backends import util as typecasts5 from django.db.backends import utils as typecasts 6 6 from django.utils import unittest 7 7 8 8 -
tests/regressiontests/forms/tests/__init__.py
diff --git a/tests/regressiontests/forms/tests/__init__.py b/tests/regressiontests/forms/tests/__init__.py index 8e2150c..a94b2a0 100644
a b from .media import FormsMediaTestCase, StaticFormsMediaTestCase 15 15 from .models import (TestTicket12510, ModelFormCallableModelDefault, 16 16 FormsModelTestCase, RelatedModelFormTests) 17 17 from .regressions import FormsRegressionsTestCase 18 from .util import FormsUtilTestCase18 from .utils import FormsUtilTestCase 19 19 from .validators import TestFieldWithValidators 20 20 from .widgets import (FormsWidgetTestCase, FormsI18NWidgetsTestCase, 21 21 WidgetTests, ClearableFileInputTests) -
tests/regressiontests/forms/tests/error_messages.py
diff --git a/tests/regressiontests/forms/tests/error_messages.py b/tests/regressiontests/forms/tests/error_messages.py index b7b4e98..e8c8999 100644
a b class FormsErrorMessagesTestCase(TestCase, AssertFormErrorsMixin): 219 219 def clean(self): 220 220 raise ValidationError("I like to be awkward.") 221 221 222 class CustomErrorList(util .ErrorList):222 class CustomErrorList(utils.ErrorList): 223 223 def __unicode__(self): 224 224 return self.as_divs() 225 225 -
tests/regressiontests/forms/tests/extra.py
diff --git a/tests/regressiontests/forms/tests/extra.py b/tests/regressiontests/forms/tests/extra.py index c873af7..87d2c0d 100644
a b import datetime 7 7 from django.conf import settings 8 8 from django.forms import * 9 9 from django.forms.extras import SelectDateWidget 10 from django.forms.util import ErrorList10 from django.forms.utils import ErrorList 11 11 from django.test import TestCase 12 12 from django.utils import translation 13 13 from django.utils.encoding import force_unicode, smart_unicode -
tests/regressiontests/forms/tests/fields.py
diff --git a/tests/regressiontests/forms/tests/fields.py b/tests/regressiontests/forms/tests/fields.py index 03e0ff6..a1aa199 100644
a b class FieldsTests(SimpleTestCase): 999 999 ('/django/forms/formsets.py', 'formsets.py'), 1000 1000 ('/django/forms/models.py', 'models.py'), 1001 1001 ('/django/forms/util.py', 'util.py'), 1002 ('/django/forms/utils.py', 'utils.py'), 1002 1003 ('/django/forms/widgets.py', 'widgets.py') 1003 1004 ] 1004 1005 for exp, got in zip(expected, fix_os_paths(f.choices)): … … class FieldsTests(SimpleTestCase): 1019 1020 ('/django/forms/formsets.py', 'formsets.py'), 1020 1021 ('/django/forms/models.py', 'models.py'), 1021 1022 ('/django/forms/util.py', 'util.py'), 1023 ('/django/forms/utils.py', 'utils.py'), 1022 1024 ('/django/forms/widgets.py', 'widgets.py') 1023 1025 ] 1024 1026 for exp, got in zip(expected, fix_os_paths(f.choices)): … … class FieldsTests(SimpleTestCase): 1039 1041 ('/django/forms/formsets.py', 'formsets.py'), 1040 1042 ('/django/forms/models.py', 'models.py'), 1041 1043 ('/django/forms/util.py', 'util.py'), 1044 ('/django/forms/utils.py', 'utils.py'), 1042 1045 ('/django/forms/widgets.py', 'widgets.py') 1043 1046 ] 1044 1047 for exp, got in zip(expected, fix_os_paths(f.choices)): -
deleted file tests/regressiontests/forms/tests/util.py
diff --git a/tests/regressiontests/forms/tests/util.py b/tests/regressiontests/forms/tests/util.py deleted file mode 100644 index dddb8c7..0000000
+ - 1 # -*- coding: utf-8 -*-2 from django.core.exceptions import ValidationError3 from django.forms.util import flatatt, ErrorDict, ErrorList4 from django.test import TestCase5 from django.utils.safestring import mark_safe6 from django.utils.translation import ugettext_lazy7 8 9 class FormsUtilTestCase(TestCase):10 # Tests for forms/util.py module.11 12 def test_flatatt(self):13 ###########14 # flatatt #15 ###########16 17 self.assertEqual(flatatt({'id': "header"}), u' id="header"')18 self.assertEqual(flatatt({'class': "news", 'title': "Read this"}), u' class="news" title="Read this"')19 self.assertEqual(flatatt({}), u'')20 21 def test_validation_error(self):22 ###################23 # ValidationError #24 ###################25 26 # Can take a string.27 self.assertHTMLEqual(str(ErrorList(ValidationError("There was an error.").messages)),28 '<ul class="errorlist"><li>There was an error.</li></ul>')29 30 # Can take a unicode string.31 self.assertHTMLEqual(unicode(ErrorList(ValidationError(u"Not \u03C0.").messages)),32 u'<ul class="errorlist"><li>Not π.</li></ul>')33 34 # Can take a lazy string.35 self.assertHTMLEqual(str(ErrorList(ValidationError(ugettext_lazy("Error.")).messages)),36 '<ul class="errorlist"><li>Error.</li></ul>')37 38 # Can take a list.39 self.assertHTMLEqual(str(ErrorList(ValidationError(["Error one.", "Error two."]).messages)),40 '<ul class="errorlist"><li>Error one.</li><li>Error two.</li></ul>')41 42 # Can take a mixture in a list.43 self.assertHTMLEqual(str(ErrorList(ValidationError(["First error.", u"Not \u03C0.", ugettext_lazy("Error.")]).messages)),44 '<ul class="errorlist"><li>First error.</li><li>Not π.</li><li>Error.</li></ul>')45 46 class VeryBadError:47 def __unicode__(self): return u"A very bad error."48 49 # Can take a non-string.50 self.assertHTMLEqual(str(ErrorList(ValidationError(VeryBadError()).messages)),51 '<ul class="errorlist"><li>A very bad error.</li></ul>')52 53 # Escapes non-safe input but not input marked safe.54 example = 'Example of link: <a href="http://www.example.com/">example</a>'55 self.assertHTMLEqual(str(ErrorList([example])),56 '<ul class="errorlist"><li>Example of link: <a href="http://www.example.com/">example</a></li></ul>')57 self.assertHTMLEqual(str(ErrorList([mark_safe(example)])),58 '<ul class="errorlist"><li>Example of link: <a href="http://www.example.com/">example</a></li></ul>')59 self.assertHTMLEqual(str(ErrorDict({'name': example})),60 '<ul class="errorlist"><li>nameExample of link: <a href="http://www.example.com/">example</a></li></ul>')61 self.assertHTMLEqual(str(ErrorDict({'name': mark_safe(example)})),62 '<ul class="errorlist"><li>nameExample of link: <a href="http://www.example.com/">example</a></li></ul>') -
new file tests/regressiontests/forms/tests/utils.py
diff --git a/tests/regressiontests/forms/tests/utils.py b/tests/regressiontests/forms/tests/utils.py new file mode 100644 index 0000000..ab827e6
- + 1 # -*- coding: utf-8 -*- 2 from django.core.exceptions import ValidationError 3 from django.forms.utils import flatatt, ErrorDict, ErrorList 4 from django.test import TestCase 5 from django.utils.safestring import mark_safe 6 from django.utils.translation import ugettext_lazy 7 8 9 class FormsUtilTestCase(TestCase): 10 # Tests for forms/util.py module. 11 12 def test_flatatt(self): 13 ########### 14 # flatatt # 15 ########### 16 17 self.assertEqual(flatatt({'id': "header"}), u' id="header"') 18 self.assertEqual(flatatt({'class': "news", 'title': "Read this"}), u' class="news" title="Read this"') 19 self.assertEqual(flatatt({}), u'') 20 21 def test_validation_error(self): 22 ################### 23 # ValidationError # 24 ################### 25 26 # Can take a string. 27 self.assertHTMLEqual(str(ErrorList(ValidationError("There was an error.").messages)), 28 '<ul class="errorlist"><li>There was an error.</li></ul>') 29 30 # Can take a unicode string. 31 self.assertHTMLEqual(unicode(ErrorList(ValidationError(u"Not \u03C0.").messages)), 32 u'<ul class="errorlist"><li>Not π.</li></ul>') 33 34 # Can take a lazy string. 35 self.assertHTMLEqual(str(ErrorList(ValidationError(ugettext_lazy("Error.")).messages)), 36 '<ul class="errorlist"><li>Error.</li></ul>') 37 38 # Can take a list. 39 self.assertHTMLEqual(str(ErrorList(ValidationError(["Error one.", "Error two."]).messages)), 40 '<ul class="errorlist"><li>Error one.</li><li>Error two.</li></ul>') 41 42 # Can take a mixture in a list. 43 self.assertHTMLEqual(str(ErrorList(ValidationError(["First error.", u"Not \u03C0.", ugettext_lazy("Error.")]).messages)), 44 '<ul class="errorlist"><li>First error.</li><li>Not π.</li><li>Error.</li></ul>') 45 46 class VeryBadError: 47 def __unicode__(self): return u"A very bad error." 48 49 # Can take a non-string. 50 self.assertHTMLEqual(str(ErrorList(ValidationError(VeryBadError()).messages)), 51 '<ul class="errorlist"><li>A very bad error.</li></ul>') 52 53 # Escapes non-safe input but not input marked safe. 54 example = 'Example of link: <a href="http://www.example.com/">example</a>' 55 self.assertHTMLEqual(str(ErrorList([example])), 56 '<ul class="errorlist"><li>Example of link: <a href="http://www.example.com/">example</a></li></ul>') 57 self.assertHTMLEqual(str(ErrorList([mark_safe(example)])), 58 '<ul class="errorlist"><li>Example of link: <a href="http://www.example.com/">example</a></li></ul>') 59 self.assertHTMLEqual(str(ErrorDict({'name': example})), 60 '<ul class="errorlist"><li>nameExample of link: <a href="http://www.example.com/">example</a></li></ul>') 61 self.assertHTMLEqual(str(ErrorDict({'name': mark_safe(example)})), 62 '<ul class="errorlist"><li>nameExample of link: <a href="http://www.example.com/">example</a></li></ul>') -
tests/regressiontests/localflavor/uy/tests.py
diff --git a/tests/regressiontests/localflavor/uy/tests.py b/tests/regressiontests/localflavor/uy/tests.py index eda0068..b1fdc19 100644
a b 1 1 from django.contrib.localflavor.uy.forms import UYDepartamentSelect, UYCIField 2 from django.contrib.localflavor.uy.util import get_validation_digit2 from django.contrib.localflavor.uy.utils import get_validation_digit 3 3 4 4 from django.test import SimpleTestCase 5 5 -
tests/regressiontests/model_formsets_regress/tests.py
diff --git a/tests/regressiontests/model_formsets_regress/tests.py b/tests/regressiontests/model_formsets_regress/tests.py index d058f1d..ecdf72e 100644
a b from __future__ import absolute_import, with_statement 2 2 3 3 from django import forms 4 4 from django.forms.formsets import BaseFormSet, DELETION_FIELD_NAME 5 from django.forms.util import ErrorDict, ErrorList5 from django.forms.utils import ErrorDict, ErrorList 6 6 from django.forms.models import modelform_factory, inlineformset_factory, modelformset_factory, BaseModelFormSet 7 7 from django.test import TestCase 8 8