Ticket #12385: 12385-class-attribute-for-i18n.diff
File 12385-class-attribute-for-i18n.diff, 19.6 KB (added by , 15 years ago) |
---|
-
django/contrib/admindocs/tests/__init__.py
diff -r 783b8c4c26f8 django/contrib/admindocs/tests/__init__.py
a b 1 1 import unittest 2 import fields 2 3 from django.contrib.admindocs import views 3 importfields4 from django.db.models import fields as builtin_fields 4 5 5 from django.db.models import fields as builtin_fields6 6 7 7 class TestFieldType(unittest.TestCase): 8 8 def setUp(self): 9 9 pass 10 10 11 11 def test_field_name(self): 12 12 self.assertRaises(AttributeError, 13 13 views.get_readable_field_data_type, "NotAField" 14 14 ) 15 15 16 16 def test_builtin_fields(self): 17 17 self.assertEqual( 18 18 views.get_readable_field_data_type(builtin_fields.BooleanField()), 19 19 u'Boolean (Either True or False)' 20 20 ) 21 21 22 22 def test_custom_fields(self): 23 23 self.assertEqual( 24 24 views.get_readable_field_data_type(fields.CustomField()), 25 25 u'A custom field type' 26 26 ) 27 27 self.assertEqual( 28 views.get_readable_field_data_type(fields.D ocstringLackingField()),29 u'Field of type: D ocstringLackingField'28 views.get_readable_field_data_type(fields.DescriptionLackingField()), 29 u'Field of type: DescriptionLackingField' 30 30 ) 31 32 def test_multiline_custom_field_truncation(self):33 self.assertEqual(34 views.get_readable_field_data_type(fields.ManyLineDocstringField()),35 u'Many-line custom field'36 ) -
django/contrib/admindocs/tests/fields.py
diff -r 783b8c4c26f8 django/contrib/admindocs/tests/fields.py
a b 1 1 from django.db import models 2 2 3 3 class CustomField(models.Field): 4 """A custom field type""" 5 6 class ManyLineDocstringField(models.Field): 7 """Many-line custom field 8 9 This docstring has many lines. Lorum ipsem etc. etc. Four score 10 and seven years ago, and so on and so forth.""" 4 description = "A custom field type" 11 5 12 class D ocstringLackingField(models.Field):6 class DescriptionLackingField(models.Field): 13 7 pass -
django/contrib/admindocs/views.py
diff -r 783b8c4c26f8 django/contrib/admindocs/views.py
a b 327 327 return '' 328 328 329 329 def get_readable_field_data_type(field): 330 """Returns the first line of a doc string for a given field type, if it 331 exists. Fields' docstrings can contain format strings, which will be 332 interpolated against the values of Field.__dict__ before being output. 333 If no docstring is given, a sensible value will be auto-generated from 334 the field's class name.""" 330 """Returns the description for a given field type, if it exists, 331 Fields' descriptions can contain format strings, which will be interpolated 332 against the values of field.__dict__ before being output.""" 335 333 336 if field.__doc__: 337 doc = field.__doc__.split('\n')[0] 338 return _(doc) % field.__dict__ 339 else: 340 return _(u'Field of type: %(field_type)s') % { 341 'field_type': field.__class__.__name__ 342 } 334 return field.description % field.__dict__ 343 335 344 336 def extract_views_from_urlpatterns(urlpatterns, base=''): 345 337 """ -
django/contrib/gis/db/models/fields/__init__.py
diff -r 783b8c4c26f8 django/contrib/gis/db/models/fields/__init__.py
a b 1 from django.utils.translation import ugettext_lazy as _ 1 2 from django.contrib.gis import forms 2 3 # Getting the SpatialBackend container and the geographic quoting method. 3 4 from django.contrib.gis.db.backend import SpatialBackend, gqn … … 30 31 return _srid_cache[srid] 31 32 32 33 class GeometryField(SpatialBackend.Field): 33 " ""The base GIS field -- maps to the OpenGIS Specification Geometry type."""34 "The base GIS field -- maps to the OpenGIS Specification Geometry type." 34 35 35 36 # The OpenGIS Geometry name. 36 37 geom_type = 'GEOMETRY' … … 38 39 # Geodetic units. 39 40 geodetic_units = ('Decimal Degree', 'degree') 40 41 42 description = _("The base GIS field -- maps to the OpenGIS Specification Geometry type.") 43 41 44 def __init__(self, verbose_name=None, srid=4326, spatial_index=True, dim=2, **kwargs): 42 45 """ 43 46 The initialization function for geometry fields. Takes the following … … 257 260 258 261 # The OpenGIS Geometry Type Fields 259 262 class PointField(GeometryField): 260 """Point"""261 263 geom_type = 'POINT' 264 description = _("Point") 262 265 263 266 class LineStringField(GeometryField): 264 """Line string"""265 267 geom_type = 'LINESTRING' 268 description = _("Line string") 266 269 267 270 class PolygonField(GeometryField): 268 """Polygon"""269 271 geom_type = 'POLYGON' 272 description = _("Polygon") 270 273 271 274 class MultiPointField(GeometryField): 272 """Multi-point"""273 275 geom_type = 'MULTIPOINT' 276 description = _("Multi-point") 274 277 275 278 class MultiLineStringField(GeometryField): 276 """Multi-line string"""277 279 geom_type = 'MULTILINESTRING' 280 description = _("Multi-line string") 278 281 279 282 class MultiPolygonField(GeometryField): 280 """Multi polygon"""281 283 geom_type = 'MULTIPOLYGON' 284 description = _("Multi polygon") 282 285 283 286 class GeometryCollectionField(GeometryField): 284 """Geometry collection"""285 287 geom_type = 'GEOMETRYCOLLECTION' 288 description = _("Geometry collection") -
django/contrib/localflavor/us/models.py
diff -r 783b8c4c26f8 django/contrib/localflavor/us/models.py
a b 1 1 from django.conf import settings 2 from django.utils.translation import ugettext_lazy as _ 2 3 from django.db.models.fields import Field, CharField 3 4 from django.contrib.localflavor.us.us_states import STATE_CHOICES 4 5 5 6 class USStateField(CharField): 6 """U.S. state (two uppercase letters)""" 7 8 description = _("U.S. state (two uppercase letters)") 9 7 10 def __init__(self, *args, **kwargs): 8 11 kwargs['choices'] = STATE_CHOICES 9 12 kwargs['max_length'] = 2 10 13 super(USStateField, self).__init__(*args, **kwargs) 11 14 12 15 class PhoneNumberField(Field): 13 """Phone number""" 16 17 description = _("Phone number") 18 14 19 def get_internal_type(self): 15 20 return "PhoneNumberField" 16 21 -
django/db/models/fields/__init__.py
diff -r 783b8c4c26f8 django/db/models/fields/__init__.py
a b 49 49 # getattr(obj, opts.pk.attname) 50 50 51 51 class Field(object): 52 """Base class for all field types"""53 54 52 # Designates whether empty strings fundamentally are allowed at the 55 53 # database level. 56 54 empty_strings_allowed = True … … 61 59 creation_counter = 0 62 60 auto_creation_counter = -1 63 61 62 # Generic field type description, usually overriden by subclasses 63 def _description(self): 64 return _(u'Field of type: %(field_type)s') % { 65 'field_type': self.__class__.__name__ 66 } 67 description = property(_description) 68 64 69 def __init__(self, verbose_name=None, name=None, primary_key=False, 65 70 max_length=None, unique=False, blank=False, null=False, 66 71 db_index=False, rel=None, default=NOT_PROVIDED, editable=True, … … 342 347 return getattr(obj, self.attname) 343 348 344 349 class AutoField(Field): 345 """Integer""" 346 350 description = ugettext_lazy("Integer") 347 351 empty_strings_allowed = False 348 349 352 def __init__(self, *args, **kwargs): 350 353 assert kwargs.get('primary_key', False) is True, "%ss must have primary_key=True." % self.__class__.__name__ 351 354 kwargs['blank'] = True … … 375 378 return None 376 379 377 380 class BooleanField(Field): 378 """Boolean (Either True or False)"""379 380 381 empty_strings_allowed = False 381 382 description = ugettext_lazy("Boolean (Either True or False)") 382 383 def __init__(self, *args, **kwargs): 383 384 kwargs['blank'] = True 384 385 if 'default' not in kwargs and not kwargs.get('null'): … … 421 422 return super(BooleanField, self).formfield(**defaults) 422 423 423 424 class CharField(Field): 424 """String (up to %(max_length)s)""" 425 425 description = ugettext_lazy("String (up to %(max_length)s)") 426 426 def get_internal_type(self): 427 427 return "CharField" 428 428 … … 444 444 445 445 # TODO: Maybe move this into contrib, because it's specialized. 446 446 class CommaSeparatedIntegerField(CharField): 447 """Comma-separated integers""" 448 447 description = ugettext_lazy("Comma-separated integers") 449 448 def formfield(self, **kwargs): 450 449 defaults = { 451 450 'form_class': forms.RegexField, … … 461 460 ansi_date_re = re.compile(r'^\d{4}-\d{1,2}-\d{1,2}$') 462 461 463 462 class DateField(Field): 464 """Date (without time)""" 465 463 description = ugettext_lazy("Date (without time)") 466 464 empty_strings_allowed = False 467 468 465 def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs): 469 466 self.auto_now, self.auto_now_add = auto_now, auto_now_add 470 467 #HACKs : auto_now_add/auto_now should be done as a default or a pre_save. … … 539 536 return super(DateField, self).formfield(**defaults) 540 537 541 538 class DateTimeField(DateField): 542 """Date (with time)""" 543 539 description = ugettext_lazy("Date (with time)") 544 540 def get_internal_type(self): 545 541 return "DateTimeField" 546 542 … … 600 596 return super(DateTimeField, self).formfield(**defaults) 601 597 602 598 class DecimalField(Field): 603 """Decimal number"""604 605 599 empty_strings_allowed = False 606 600 description = ugettext_lazy("Decimal number") 607 601 def __init__(self, verbose_name=None, name=None, max_digits=None, decimal_places=None, **kwargs): 608 602 self.max_digits, self.decimal_places = max_digits, decimal_places 609 603 Field.__init__(self, verbose_name, name, **kwargs) … … 657 651 return super(DecimalField, self).formfield(**defaults) 658 652 659 653 class EmailField(CharField): 660 """E-mail address""" 661 654 description = ugettext_lazy("E-mail address") 662 655 def __init__(self, *args, **kwargs): 663 656 kwargs['max_length'] = kwargs.get('max_length', 75) 664 657 CharField.__init__(self, *args, **kwargs) … … 669 662 return super(EmailField, self).formfield(**defaults) 670 663 671 664 class FilePathField(Field): 672 """File path""" 673 665 description = ugettext_lazy("File path") 674 666 def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs): 675 667 self.path, self.match, self.recursive = path, match, recursive 676 668 kwargs['max_length'] = kwargs.get('max_length', 100) … … 690 682 return "FilePathField" 691 683 692 684 class FloatField(Field): 693 """Floating point number"""694 695 685 empty_strings_allowed = False 686 description = ugettext_lazy("Floating point number") 696 687 697 688 def get_db_prep_value(self, value): 698 689 if value is None: … … 717 708 return super(FloatField, self).formfield(**defaults) 718 709 719 710 class IntegerField(Field): 720 """Integer"""721 722 711 empty_strings_allowed = False 723 712 description = ugettext_lazy("Integer") 724 713 def get_db_prep_value(self, value): 725 714 if value is None: 726 715 return None … … 744 733 return super(IntegerField, self).formfield(**defaults) 745 734 746 735 class IPAddressField(Field): 747 """IP address"""748 749 736 empty_strings_allowed = False 750 737 description = ugettext_lazy("IP address") 751 738 def __init__(self, *args, **kwargs): 752 739 kwargs['max_length'] = 15 753 740 Field.__init__(self, *args, **kwargs) … … 761 748 return super(IPAddressField, self).formfield(**defaults) 762 749 763 750 class NullBooleanField(Field): 764 """Boolean (Either True, False or None)"""765 766 751 empty_strings_allowed = False 767 752 description = ugettext_lazy("Boolean (Either True, False or None)") 768 753 def __init__(self, *args, **kwargs): 769 754 kwargs['null'] = True 770 755 Field.__init__(self, *args, **kwargs) … … 804 789 return super(NullBooleanField, self).formfield(**defaults) 805 790 806 791 class PositiveIntegerField(IntegerField): 807 """Integer""" 808 792 description = ugettext_lazy("Integer") 809 793 def get_internal_type(self): 810 794 return "PositiveIntegerField" 811 795 … … 815 799 return super(PositiveIntegerField, self).formfield(**defaults) 816 800 817 801 class PositiveSmallIntegerField(IntegerField): 818 """Integer""" 819 802 description = ugettext_lazy("Integer") 820 803 def get_internal_type(self): 821 804 return "PositiveSmallIntegerField" 822 805 … … 826 809 return super(PositiveSmallIntegerField, self).formfield(**defaults) 827 810 828 811 class SlugField(CharField): 829 """String (up to %(max_length)s)""" 830 812 description = ugettext_lazy("String (up to %(max_length)s)") 831 813 def __init__(self, *args, **kwargs): 832 814 kwargs['max_length'] = kwargs.get('max_length', 50) 833 815 # Set db_index=True unless it's been set manually. … … 844 826 return super(SlugField, self).formfield(**defaults) 845 827 846 828 class SmallIntegerField(IntegerField): 847 """Integer""" 848 829 description = ugettext_lazy("Integer") 849 830 def get_internal_type(self): 850 831 return "SmallIntegerField" 851 832 852 833 class TextField(Field): 853 """Text""" 854 834 description = ugettext_lazy("Text") 855 835 def get_internal_type(self): 856 836 return "TextField" 857 837 … … 861 841 return super(TextField, self).formfield(**defaults) 862 842 863 843 class TimeField(Field): 864 """Time""" 865 844 description = ugettext_lazy("Time") 866 845 empty_strings_allowed = False 867 868 846 def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs): 869 847 self.auto_now, self.auto_now_add = auto_now, auto_now_add 870 848 if auto_now or auto_now_add: … … 936 914 return super(TimeField, self).formfield(**defaults) 937 915 938 916 class URLField(CharField): 939 """URL""" 940 917 description = ugettext_lazy("URL") 941 918 def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs): 942 919 kwargs['max_length'] = kwargs.get('max_length', 200) 943 920 self.verify_exists = verify_exists … … 949 926 return super(URLField, self).formfield(**defaults) 950 927 951 928 class XMLField(TextField): 952 """XML text""" 953 929 description = ugettext_lazy("XML text") 954 930 def __init__(self, verbose_name=None, name=None, schema_path=None, **kwargs): 955 931 self.schema_path = schema_path 956 932 Field.__init__(self, verbose_name, name, **kwargs) -
django/db/models/fields/files.py
diff -r 783b8c4c26f8 django/db/models/fields/files.py
a b 209 209 instance.__dict__[self.field.name] = value 210 210 211 211 class FileField(Field): 212 """File path"""213 214 212 # The class to wrap instance attributes in. Accessing the file object off 215 213 # the instance will always return an instance of attr_class. 216 214 attr_class = FieldFile … … 218 216 # The descriptor to use for accessing the attribute off of the class. 219 217 descriptor_class = FileDescriptor 220 218 219 description = ugettext_lazy("File path") 220 221 221 def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, **kwargs): 222 222 for arg in ('primary_key', 'unique'): 223 223 if arg in kwargs: … … 325 325 super(ImageFieldFile, self).delete(save) 326 326 327 327 class ImageField(FileField): 328 """File path"""329 330 328 attr_class = ImageFieldFile 331 329 descriptor_class = ImageFileDescriptor 330 description = ugettext_lazy("File path") 332 331 333 332 def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs): 334 333 self.width_field, self.height_field = width_field, height_field -
django/db/models/fields/related.py
diff -r 783b8c4c26f8 django/db/models/fields/related.py
a b 691 691 return self.to._meta.pk 692 692 693 693 class ForeignKey(RelatedField, Field): 694 """Foreign Key (type determined by related field)"""695 696 694 empty_strings_allowed = False 695 description = ugettext_lazy("Foreign Key (type determined by related field)") 697 696 def __init__(self, to, to_field=None, rel_class=ManyToOneRel, **kwargs): 698 697 try: 699 698 to_name = to._meta.object_name.lower() … … 790 789 return rel_field.db_type() 791 790 792 791 class OneToOneField(ForeignKey): 793 """One-to-one relationship 794 792 """ 795 793 A OneToOneField is essentially the same as a ForeignKey, with the exception 796 794 that always carries a "unique" constraint with it and the reverse relation 797 795 always returns the object pointed to (since there will only ever be one), 798 rather than returning a list.""" 799 796 rather than returning a list. 797 """ 798 description = ugettext_lazy("One-to-one relationship") 800 799 def __init__(self, to, to_field=None, **kwargs): 801 800 kwargs['unique'] = True 802 801 super(OneToOneField, self).__init__(to, to_field, OneToOneRel, **kwargs) … … 850 849 }) 851 850 852 851 class ManyToManyField(RelatedField, Field): 853 """Many-to-many relationship""" 854 852 description = ugettext_lazy("Many-to-many relationship") 855 853 def __init__(self, to, **kwargs): 856 854 try: 857 855 assert not to._meta.abstract, "%s cannot define a relation with abstract class %s" % (self.__class__.__name__, to._meta.object_name) -
docs/howto/custom-model-fields.txt
diff -r 783b8c4c26f8 docs/howto/custom-model-fields.txt
a b 5 5 =========================== 6 6 7 7 .. versionadded:: 1.0 8 .. currentmodule:: django.db.models 8 9 9 10 Introduction 10 11 ============ … … 165 166 from django.db import models 166 167 167 168 class HandField(models.Field): 168 """A hand of cards (bridge style)""" 169 170 description = "A hand of cards (bridge style)" 169 171 170 172 def __init__(self, *args, **kwargs): 171 173 kwargs['max_length'] = 104 … … 248 250 For example:: 249 251 250 252 class HandField(models.Field): 251 """A hand of cards (bridge style)""" 253 254 description = "A hand of cards (bridge style)" 252 255 253 256 __metaclass__ = models.SubfieldBase 254 257 … … 262 265 Documenting your Custom Field 263 266 ----------------------------- 264 267 268 .. class:: django.db.models.Field 269 270 .. attribute:: description 271 265 272 As always, you should document your field type, so users will know what it is. 266 The best way to do this is to simply provide a docstring for it. This will 267 automatically be picked up by ``django.contrib.admindocs``, if you have it 268 installed, and the first line of it will show up as the field type in the 269 documentation for any model that uses your field. In the above examples, it 270 will show up as 'A hand of cards (bridge style)'. Note that if you provide a 271 more verbose docstring, only the first line will show up in 272 ``django.contrib.admindocs``. The full docstring will, of course, still be 273 available through ``pydoc`` or the interactive interpreter's ``help()`` 274 function. 273 In addition to providing a docstring for it, which is useful for developers, 274 you can also allow users of the admin app to see a short description of the 275 field type via the ``django.contrib.admindocs`` application if you have it 276 installed, in a way similar to how the fields builtin to Django` are show. For 277 this you need to provide such a descriptive text in a ``description`` class 278 attribute of your custom field. In the above examples, it will show up as 279 'A hand of cards (bridge style)'. 275 280 276 281 Useful methods 277 282 --------------