1
0
mirror of https://github.com/django/django.git synced 2025-07-05 02:09:13 +00:00

unicode: Fixed a number of problems where lazily translated objects were not

being converted back to unicode strings correctly. Fixed #4359 and #4361.


git-svn-id: http://code.djangoproject.com/svn/django/branches/unicode@5320 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2007-05-23 03:46:57 +00:00
parent d72f630fdb
commit b25f6e9526
8 changed files with 84 additions and 29 deletions

View File

@ -78,7 +78,7 @@ def result_headers(cl):
# attribute "short_description". If that doesn't exist, fall back # attribute "short_description". If that doesn't exist, fall back
# to the method name. And __str__ and __unicode__ are special-cases. # to the method name. And __str__ and __unicode__ are special-cases.
if field_name == '__unicode__': if field_name == '__unicode__':
header = smart_unicode(lookup_opts.verbose_name) header = force_unicode(lookup_opts.verbose_name)
elif field_name == '__str__': elif field_name == '__str__':
header = smart_str(lookup_opts.verbose_name) header = smart_str(lookup_opts.verbose_name)
else: else:

View File

@ -12,7 +12,7 @@ from django.db.models.query import handle_legacy_orderlist, QuerySet
from django.http import Http404, HttpResponse, HttpResponseRedirect from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.utils.html import escape from django.utils.html import escape
from django.utils.text import capfirst, get_text_list from django.utils.text import capfirst, get_text_list
from django.utils.encoding import smart_unicode, smart_str from django.utils.encoding import force_unicode, smart_str
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
import operator import operator
@ -127,11 +127,11 @@ class AdminBoundField(object):
if max([bool(f.errors()) for f in self.form_fields]): if max([bool(f.errors()) for f in self.form_fields]):
classes.append('error') classes.append('error')
if classes: if classes:
self.cell_class_attribute = ' class="%s" ' % ' '.join(classes) self.cell_class_attribute = u' class="%s" ' % ' '.join(classes)
self._repr_filled = False self._repr_filled = False
if field.rel: if field.rel:
self.related_url = '../../../%s/%s/' % (field.rel.to._meta.app_label, field.rel.to._meta.object_name.lower()) self.related_url = u'../../../%s/%s/' % (field.rel.to._meta.app_label, field.rel.to._meta.object_name.lower())
def original_value(self): def original_value(self):
if self.original: if self.original:
@ -144,7 +144,7 @@ class AdminBoundField(object):
if isinstance(self.field.rel, models.ManyToOneRel): if isinstance(self.field.rel, models.ManyToOneRel):
self._display = getattr(self.original, self.field.name) self._display = getattr(self.original, self.field.name)
elif isinstance(self.field.rel, models.ManyToManyRel): elif isinstance(self.field.rel, models.ManyToManyRel):
self._display = u", ".join([smart_unicode(obj) for obj in getattr(self.original, self.field.name).all()]) self._display = u", ".join([force_unicode(obj) for obj in getattr(self.original, self.field.name).all()])
return self._display return self._display
def __repr__(self): def __repr__(self):
@ -255,7 +255,7 @@ def add_stage(request, app_label, model_name, show_delete=False, form_url='', po
if not errors: if not errors:
new_object = manipulator.save(new_data) new_object = manipulator.save(new_data)
pk_value = new_object._get_pk_val() pk_value = new_object._get_pk_val()
LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, smart_unicode(new_object), ADDITION) LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, force_unicode(new_object), ADDITION)
msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': opts.verbose_name, 'obj': new_object} msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': opts.verbose_name, 'obj': new_object}
# Here, we distinguish between different save types by checking for # Here, we distinguish between different save types by checking for
# the presence of keys in request.POST. # the presence of keys in request.POST.
@ -268,7 +268,7 @@ def add_stage(request, app_label, model_name, show_delete=False, form_url='', po
if type(pk_value) is str: # Quote if string, so JavaScript doesn't think it's a variable. if type(pk_value) is str: # Quote if string, so JavaScript doesn't think it's a variable.
pk_value = '"%s"' % pk_value.replace('"', '\\"') pk_value = '"%s"' % pk_value.replace('"', '\\"')
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %s, "%s");</script>' % \ return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %s, "%s");</script>' % \
(pk_value, smart_unicode(new_object).replace('"', '\\"'))) (pk_value, force_unicode(new_object).replace('"', '\\"')))
elif "_addanother" in request.POST: elif "_addanother" in request.POST:
request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name)) request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
return HttpResponseRedirect(request.path) return HttpResponseRedirect(request.path)
@ -342,7 +342,7 @@ def change_stage(request, app_label, model_name, object_id):
change_message = ' '.join(change_message) change_message = ' '.join(change_message)
if not change_message: if not change_message:
change_message = _('No fields changed.') change_message = _('No fields changed.')
LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, smart_unicode(new_object), CHANGE, change_message) LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, force_unicode(new_object), CHANGE, change_message)
msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': opts.verbose_name, 'obj': new_object} msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': opts.verbose_name, 'obj': new_object}
if "_continue" in request.POST: if "_continue" in request.POST:
@ -431,10 +431,10 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
if related.field.rel.edit_inline or not related.opts.admin: if related.field.rel.edit_inline or not related.opts.admin:
# Don't display link to edit, because it either has no # Don't display link to edit, because it either has no
# admin or is edited inline. # admin or is edited inline.
nh(deleted_objects, current_depth, ['%s: %s' % (capfirst(related.opts.verbose_name), sub_obj), []]) nh(deleted_objects, current_depth, [u'%s: %s' % (capfirst(related.opts.verbose_name), sub_obj), []])
else: else:
# Display a link to the admin page. # Display a link to the admin page.
nh(deleted_objects, current_depth, ['%s: <a href="../../../../%s/%s/%s/">%s</a>' % \ nh(deleted_objects, current_depth, [u'%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
(capfirst(related.opts.verbose_name), related.opts.app_label, related.opts.object_name.lower(), (capfirst(related.opts.verbose_name), related.opts.app_label, related.opts.object_name.lower(),
sub_obj._get_pk_val(), sub_obj), []]) sub_obj._get_pk_val(), sub_obj), []])
_get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2) _get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2)
@ -445,10 +445,10 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
if related.field.rel.edit_inline or not related.opts.admin: if related.field.rel.edit_inline or not related.opts.admin:
# Don't display link to edit, because it either has no # Don't display link to edit, because it either has no
# admin or is edited inline. # admin or is edited inline.
nh(deleted_objects, current_depth, ['%s: %s' % (capfirst(related.opts.verbose_name), escape(sub_obj)), []]) nh(deleted_objects, current_depth, [u'%s: %s' % (capfirst(related.opts.verbose_name), escape(sub_obj)), []])
else: else:
# Display a link to the admin page. # Display a link to the admin page.
nh(deleted_objects, current_depth, ['%s: <a href="../../../../%s/%s/%s/">%s</a>' % \ nh(deleted_objects, current_depth, [u'%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
(capfirst(related.opts.verbose_name), related.opts.app_label, related.opts.object_name.lower(), sub_obj._get_pk_val(), escape(sub_obj)), []]) (capfirst(related.opts.verbose_name), related.opts.app_label, related.opts.object_name.lower(), sub_obj._get_pk_val(), escape(sub_obj)), []])
_get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2) _get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2)
# If there were related objects, and the user doesn't have # If there were related objects, and the user doesn't have
@ -481,12 +481,12 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
# Display a link to the admin page. # Display a link to the admin page.
nh(deleted_objects, current_depth, [ nh(deleted_objects, current_depth, [
(_('One or more %(fieldname)s in %(name)s:') % {'fieldname': related.field.verbose_name, 'name':related.opts.verbose_name}) + \ (_('One or more %(fieldname)s in %(name)s:') % {'fieldname': related.field.verbose_name, 'name':related.opts.verbose_name}) + \
(' <a href="../../../../%s/%s/%s/">%s</a>' % \ (u' <a href="../../../../%s/%s/%s/">%s</a>' % \
(related.opts.app_label, related.opts.module_name, sub_obj._get_pk_val(), escape(sub_obj))), []]) (related.opts.app_label, related.opts.module_name, sub_obj._get_pk_val(), escape(sub_obj))), []])
# If there were related objects, and the user doesn't have # If there were related objects, and the user doesn't have
# permission to change them, add the missing perm to perms_needed. # permission to change them, add the missing perm to perms_needed.
if related.opts.admin and has_related_objs: if related.opts.admin and has_related_objs:
p = '%s.%s' % (related.opts.app_label, related.opts.get_change_permission()) p = u'%s.%s' % (related.opts.app_label, related.opts.get_change_permission())
if not user.has_perm(p): if not user.has_perm(p):
perms_needed.add(related.opts.verbose_name) perms_needed.add(related.opts.verbose_name)
@ -503,14 +503,14 @@ def delete_stage(request, app_label, model_name, object_id):
# Populate deleted_objects, a data structure of all related objects that # Populate deleted_objects, a data structure of all related objects that
# will also be deleted. # will also be deleted.
deleted_objects = ['%s: <a href="../../%s/">%s</a>' % (capfirst(opts.verbose_name), object_id, escape(obj)), []] deleted_objects = [u'%s: <a href="../../%s/">%s</a>' % (capfirst(opts.verbose_name), object_id, escape(obj)), []]
perms_needed = sets.Set() perms_needed = sets.Set()
_get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1) _get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1)
if request.POST: # The user has already confirmed the deletion. if request.POST: # The user has already confirmed the deletion.
if perms_needed: if perms_needed:
raise PermissionDenied raise PermissionDenied
obj_display = smart_unicode(obj) obj_display = force_unicode(obj)
obj.delete() obj.delete()
LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, object_id, obj_display, DELETION) LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, object_id, obj_display, DELETION)
request.user.message_set.create(message=_('The %(name)s "%(obj)s" was deleted successfully.') % {'name': opts.verbose_name, 'obj': obj_display}) request.user.message_set.create(message=_('The %(name)s "%(obj)s" was deleted successfully.') % {'name': opts.verbose_name, 'obj': obj_display})
@ -600,7 +600,7 @@ class ChangeList(object):
del p[k] del p[k]
elif v is not None: elif v is not None:
p[k] = v p[k] = v
return '?' + '&amp;'.join(['%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20') return '?' + '&amp;'.join([u'%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20')
def get_results(self, request): def get_results(self, request):
paginator = ObjectPaginator(self.query_set, self.lookup_opts.admin.list_per_page) paginator = ObjectPaginator(self.query_set, self.lookup_opts.admin.list_per_page)

View File

@ -3,7 +3,7 @@ from django.core.exceptions import ImproperlyConfigured
from django.db import backend, connection, models from django.db import backend, connection, models
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.utils.encoding import smart_str from django.utils.encoding import smart_str
from django.utils.translation import ugettext_lazy, ugettext as _ from django.utils.translation import ugettext_lazy as _
import datetime import datetime
import urllib import urllib
@ -281,7 +281,7 @@ class AnonymousUser(object):
pass pass
def __unicode__(self): def __unicode__(self):
return ugettext_lazy('AnonymousUser') return _('AnonymousUser')
def __eq__(self, other): def __eq__(self, other):
return isinstance(other, self.__class__) return isinstance(other, self.__class__)

View File

@ -12,7 +12,7 @@ from django.db.models.loading import register_models, get_model
from django.dispatch import dispatcher from django.dispatch import dispatcher
from django.utils.datastructures import SortedDict from django.utils.datastructures import SortedDict
from django.utils.functional import curry from django.utils.functional import curry
from django.utils.encoding import smart_str from django.utils.encoding import smart_str, force_unicode
from django.conf import settings from django.conf import settings
from itertools import izip from itertools import izip
import types import types
@ -88,7 +88,7 @@ class Model(object):
def __str__(self): def __str__(self):
if hasattr(self, '__unicode__'): if hasattr(self, '__unicode__'):
return unicode(self).encode('utf-8') return force_unicode(self).encode('utf-8')
return '%s object' % self.__class__.__name__ return '%s object' % self.__class__.__name__
def __eq__(self, other): def __eq__(self, other):
@ -320,7 +320,7 @@ class Model(object):
def _get_FIELD_display(self, field): def _get_FIELD_display(self, field):
value = getattr(self, field.attname) value = getattr(self, field.attname)
return dict(field.choices).get(value, value) return force_unicode(dict(field.choices).get(value, value))
def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs): def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs):
op = is_next and '>' or '<' op = is_next and '>' or '<'

View File

@ -215,7 +215,7 @@ class AdminOptions(object):
save_on_top=False, list_select_related=False, manager=None, list_per_page=100): save_on_top=False, list_select_related=False, manager=None, list_per_page=100):
self.fields = fields self.fields = fields
self.js = js or [] self.js = js or []
self.list_display = list_display or ['__str__'] self.list_display = list_display or ['__unicode__']
self.list_display_links = list_display_links or [] self.list_display_links = list_display_links or []
self.list_filter = list_filter or [] self.list_filter = list_filter or []
self.date_hierarchy = date_hierarchy self.date_hierarchy = date_hierarchy

View File

@ -58,9 +58,9 @@ import re
from inspect import getargspec from inspect import getargspec
from django.conf import settings from django.conf import settings
from django.template.context import Context, RequestContext, ContextPopException from django.template.context import Context, RequestContext, ContextPopException
from django.utils.functional import curry from django.utils.functional import curry, Promise
from django.utils.text import smart_split from django.utils.text import smart_split
from django.utils.encoding import smart_unicode, smart_str from django.utils.encoding import smart_unicode, smart_str, force_unicode
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
__all__ = ('Template', 'Context', 'RequestContext', 'compile_string') __all__ = ('Template', 'Context', 'RequestContext', 'compile_string')
@ -705,6 +705,8 @@ def resolve_variable(path, context):
else: else:
raise raise
del bits[0] del bits[0]
if isinstance(current, (basestring, Promise)):
current = force_unicode(current)
return current return current
class Node(object): class Node(object):

View File

@ -33,7 +33,7 @@ __test__ = {'API_TESTS':"""
>>> s.gender >>> s.gender
'F' 'F'
>>> a.get_gender_display() >>> a.get_gender_display()
'Male' u'Male'
>>> s.get_gender_display() >>> s.get_gender_display()
'Female' u'Female'
"""} """}

View File

@ -123,6 +123,9 @@ class ListFilterBadOne(models.Model):
class Admin: class Admin:
list_filter = 'first_name' list_filter = 'first_name'
def __unicode__(self):
return self.first_name
model_errors += """invalid_admin_options.listfilterbadone: "admin.list_filter", if given, must be set to a list or tuple. model_errors += """invalid_admin_options.listfilterbadone: "admin.list_filter", if given, must be set to a list or tuple.
""" """
@ -140,6 +143,9 @@ class ListFilterBadTwo(models.Model):
class Admin: class Admin:
list_filter = ['first_name','last_name','full_name'] list_filter = ['first_name','last_name','full_name']
def __unicode__(self):
return self.first_name
model_errors += """invalid_admin_options.listfilterbadtwo: "admin.list_filter" refers to 'last_name', which isn't a field. model_errors += """invalid_admin_options.listfilterbadtwo: "admin.list_filter" refers to 'last_name', which isn't a field.
invalid_admin_options.listfilterbadtwo: "admin.list_filter" refers to 'full_name', which isn't a field. invalid_admin_options.listfilterbadtwo: "admin.list_filter" refers to 'full_name', which isn't a field.
""" """
@ -152,6 +158,9 @@ class DateHierarchyBadOne(models.Model):
class Admin: class Admin:
date_hierarchy = 'first_name' date_hierarchy = 'first_name'
def __unicode__(self):
return self.first_name
# TODO: Date Hierarchy needs to check if field is a date/datetime field. # TODO: Date Hierarchy needs to check if field is a date/datetime field.
#model_errors += """invalid_admin_options.datehierarchybadone: "admin.date_hierarchy" refers to 'first_name', which isn't a date field or datetime field. #model_errors += """invalid_admin_options.datehierarchybadone: "admin.date_hierarchy" refers to 'first_name', which isn't a date field or datetime field.
#""" #"""
@ -164,6 +173,9 @@ class DateHierarchyBadTwo(models.Model):
class Admin: class Admin:
date_hierarchy = 'nonexistent' date_hierarchy = 'nonexistent'
def __unicode__(self):
return self.first_name
model_errors += """invalid_admin_options.datehierarchybadtwo: "admin.date_hierarchy" refers to 'nonexistent', which isn't a field. model_errors += """invalid_admin_options.datehierarchybadtwo: "admin.date_hierarchy" refers to 'nonexistent', which isn't a field.
""" """
@ -175,6 +187,9 @@ class DateHierarchyGood(models.Model):
class Admin: class Admin:
date_hierarchy = 'birth_day' date_hierarchy = 'birth_day'
def __unicode__(self):
return self.first_name
class SearchFieldsBadOne(models.Model): class SearchFieldsBadOne(models.Model):
"Test search_fields, must be a list or tuple." "Test search_fields, must be a list or tuple."
first_name = models.CharField(maxlength=30) first_name = models.CharField(maxlength=30)
@ -182,6 +197,9 @@ class SearchFieldsBadOne(models.Model):
class Admin: class Admin:
search_fields = ('nonexistent') search_fields = ('nonexistent')
def __unicode__(self):
return self.first_name
# TODO: Add search_fields validation # TODO: Add search_fields validation
#model_errors += """invalid_admin_options.seacrhfieldsbadone: "admin.search_fields", if given, must be set to a list or tuple. #model_errors += """invalid_admin_options.seacrhfieldsbadone: "admin.search_fields", if given, must be set to a list or tuple.
#""" #"""
@ -197,6 +215,9 @@ class SearchFieldsBadTwo(models.Model):
class Admin: class Admin:
search_fields = ['first_name','last_name'] search_fields = ['first_name','last_name']
def __unicode__(self):
return self.first_name
# TODO: Add search_fields validation # TODO: Add search_fields validation
#model_errors += """invalid_admin_options.seacrhfieldsbadone: "admin.search_fields" refers to 'last_name', which isn't a field. #model_errors += """invalid_admin_options.seacrhfieldsbadone: "admin.search_fields" refers to 'last_name', which isn't a field.
#""" #"""
@ -209,6 +230,8 @@ class SearchFieldsGood(models.Model):
class Admin: class Admin:
search_fields = ['first_name','last_name'] search_fields = ['first_name','last_name']
def __unicode__(self):
return self.first_name
class JsBadOne(models.Model): class JsBadOne(models.Model):
"Test js, must be a list or tuple" "Test js, must be a list or tuple"
@ -217,6 +240,9 @@ class JsBadOne(models.Model):
class Admin: class Admin:
js = 'test.js' js = 'test.js'
def __unicode__(self):
return self.name
# TODO: Add a js validator # TODO: Add a js validator
#model_errors += """invalid_admin_options.jsbadone: "admin.js", if given, must be set to a list or tuple. #model_errors += """invalid_admin_options.jsbadone: "admin.js", if given, must be set to a list or tuple.
#""" #"""
@ -228,6 +254,9 @@ class SaveAsBad(models.Model):
class Admin: class Admin:
save_as = 'not True or False' save_as = 'not True or False'
def __unicode__(self):
return self.name
# TODO: Add a save_as validator. # TODO: Add a save_as validator.
#model_errors += """invalid_admin_options.saveasbad: "admin.save_as", if given, must be set to True or False. #model_errors += """invalid_admin_options.saveasbad: "admin.save_as", if given, must be set to True or False.
#""" #"""
@ -239,6 +268,9 @@ class SaveOnTopBad(models.Model):
class Admin: class Admin:
save_on_top = 'not True or False' save_on_top = 'not True or False'
def __unicode__(self):
return self.name
# TODO: Add a save_on_top validator. # TODO: Add a save_on_top validator.
#model_errors += """invalid_admin_options.saveontopbad: "admin.save_on_top", if given, must be set to True or False. #model_errors += """invalid_admin_options.saveontopbad: "admin.save_on_top", if given, must be set to True or False.
#""" #"""
@ -250,6 +282,9 @@ class ListSelectRelatedBad(models.Model):
class Admin: class Admin:
list_select_related = 'not True or False' list_select_related = 'not True or False'
def __unicode__(self):
return self.name
# TODO: Add a list_select_related validator. # TODO: Add a list_select_related validator.
#model_errors += """invalid_admin_options.listselectrelatebad: "admin.list_select_related", if given, must be set to True or False. #model_errors += """invalid_admin_options.listselectrelatebad: "admin.list_select_related", if given, must be set to True or False.
#""" #"""
@ -261,6 +296,9 @@ class ListPerPageBad(models.Model):
class Admin: class Admin:
list_per_page = 89.3 list_per_page = 89.3
def __unicode__(self):
return self.name
# TODO: Add a list_per_page validator. # TODO: Add a list_per_page validator.
#model_errors += """invalid_admin_options.listperpagebad: "admin.list_per_page", if given, must be a positive integer. #model_errors += """invalid_admin_options.listperpagebad: "admin.list_per_page", if given, must be a positive integer.
#""" #"""
@ -273,6 +311,9 @@ class FieldsBadOne(models.Model):
class Admin: class Admin:
fields = 'not a tuple' fields = 'not a tuple'
def __unicode__(self):
return self.first_name
# TODO: Add a fields validator. # TODO: Add a fields validator.
#model_errors += """invalid_admin_options.fieldsbadone: "admin.fields", if given, must be a tuple. #model_errors += """invalid_admin_options.fieldsbadone: "admin.fields", if given, must be a tuple.
#""" #"""
@ -285,6 +326,9 @@ class FieldsBadTwo(models.Model):
class Admin: class Admin:
fields = ('Name', {'description': 'this fieldset needs fields'}) fields = ('Name', {'description': 'this fieldset needs fields'})
def __unicode__(self):
return self.first_name
# TODO: Add a fields validator. # TODO: Add a fields validator.
#model_errors += """invalid_admin_options.fieldsbadtwo: "admin.fields" each fieldset must include a 'fields' dict. #model_errors += """invalid_admin_options.fieldsbadtwo: "admin.fields" each fieldset must include a 'fields' dict.
#""" #"""
@ -297,6 +341,9 @@ class FieldsBadThree(models.Model):
class Admin: class Admin:
fields = ('Name', {'fields': ('first_name','last_name'),'badoption': 'verybadoption'}) fields = ('Name', {'fields': ('first_name','last_name'),'badoption': 'verybadoption'})
def __unicode__(self):
return self.first_name
# TODO: Add a fields validator. # TODO: Add a fields validator.
#model_errors += """invalid_admin_options.fieldsbadthree: "admin.fields" fieldset options must be either 'classes' or 'description'. #model_errors += """invalid_admin_options.fieldsbadthree: "admin.fields" fieldset options must be either 'classes' or 'description'.
#""" #"""
@ -313,6 +360,9 @@ class FieldsGood(models.Model):
(None, {'fields': ('birth_day',),'description': 'enter your b-day'}) (None, {'fields': ('birth_day',),'description': 'enter your b-day'})
) )
def __unicode__(self):
return self.first_name
class OrderingBad(models.Model): class OrderingBad(models.Model):
"Test ordering, must be a field." "Test ordering, must be a field."
first_name = models.CharField(maxlength=30) first_name = models.CharField(maxlength=30)
@ -321,6 +371,9 @@ class OrderingBad(models.Model):
class Admin: class Admin:
ordering = 'nonexistent' ordering = 'nonexistent'
def __unicode__(self):
return self.first_name
# TODO: Add a ordering validator. # TODO: Add a ordering validator.
#model_errors += """invalid_admin_options.orderingbad: "admin.ordering" refers to 'nonexistent', which isn't a field. #model_errors += """invalid_admin_options.orderingbad: "admin.ordering" refers to 'nonexistent', which isn't a field.
#""" #"""