Ticket #7977: admindocs_field_types_revised.diff
File admindocs_field_types_revised.diff, 17.2 KB (added by , 15 years ago) |
---|
-
django/db/models/fields/__init__.py
49 49 # getattr(obj, opts.pk.attname) 50 50 51 51 class Field(object): 52 """Base class for all field types""" 53 52 54 # Designates whether empty strings fundamentally are allowed at the 53 55 # database level. 54 56 empty_strings_allowed = True … … 340 342 return getattr(obj, self.attname) 341 343 342 344 class AutoField(Field): 345 """Integer""" 346 343 347 empty_strings_allowed = False 348 344 349 def __init__(self, *args, **kwargs): 345 350 assert kwargs.get('primary_key', False) is True, "%ss must have primary_key=True." % self.__class__.__name__ 346 351 kwargs['blank'] = True … … 370 375 return None 371 376 372 377 class BooleanField(Field): 378 """Boolean (Either True or False)""" 379 373 380 empty_strings_allowed = False 381 374 382 def __init__(self, *args, **kwargs): 375 383 kwargs['blank'] = True 376 384 if 'default' not in kwargs and not kwargs.get('null'): … … 413 421 return super(BooleanField, self).formfield(**defaults) 414 422 415 423 class CharField(Field): 424 """String (up to %(max_length)s)""" 425 416 426 def get_internal_type(self): 417 427 return "CharField" 418 428 … … 434 444 435 445 # TODO: Maybe move this into contrib, because it's specialized. 436 446 class CommaSeparatedIntegerField(CharField): 447 """Comma-separated integers""" 448 437 449 def formfield(self, **kwargs): 438 450 defaults = { 439 451 'form_class': forms.RegexField, … … 449 461 ansi_date_re = re.compile(r'^\d{4}-\d{1,2}-\d{1,2}$') 450 462 451 463 class DateField(Field): 464 """Date (without time)""" 465 452 466 empty_strings_allowed = False 467 453 468 def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs): 454 469 self.auto_now, self.auto_now_add = auto_now, auto_now_add 455 470 #HACKs : auto_now_add/auto_now should be done as a default or a pre_save. … … 524 539 return super(DateField, self).formfield(**defaults) 525 540 526 541 class DateTimeField(DateField): 542 """Date (with time)""" 543 527 544 def get_internal_type(self): 528 545 return "DateTimeField" 529 546 … … 583 600 return super(DateTimeField, self).formfield(**defaults) 584 601 585 602 class DecimalField(Field): 603 """Decimal number""" 604 586 605 empty_strings_allowed = False 606 587 607 def __init__(self, verbose_name=None, name=None, max_digits=None, decimal_places=None, **kwargs): 588 608 self.max_digits, self.decimal_places = max_digits, decimal_places 589 609 Field.__init__(self, verbose_name, name, **kwargs) … … 637 657 return super(DecimalField, self).formfield(**defaults) 638 658 639 659 class EmailField(CharField): 660 """E-mail address""" 661 640 662 def __init__(self, *args, **kwargs): 641 663 kwargs['max_length'] = kwargs.get('max_length', 75) 642 664 CharField.__init__(self, *args, **kwargs) … … 647 669 return super(EmailField, self).formfield(**defaults) 648 670 649 671 class FilePathField(Field): 672 """File path""" 673 650 674 def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs): 651 675 self.path, self.match, self.recursive = path, match, recursive 652 676 kwargs['max_length'] = kwargs.get('max_length', 100) … … 666 690 return "FilePathField" 667 691 668 692 class FloatField(Field): 693 """Floating point number""" 694 669 695 empty_strings_allowed = False 670 696 671 697 def get_db_prep_value(self, value): … … 691 717 return super(FloatField, self).formfield(**defaults) 692 718 693 719 class IntegerField(Field): 720 """Integer""" 721 694 722 empty_strings_allowed = False 723 695 724 def get_db_prep_value(self, value): 696 725 if value is None: 697 726 return None … … 715 744 return super(IntegerField, self).formfield(**defaults) 716 745 717 746 class IPAddressField(Field): 747 """IP address""" 748 718 749 empty_strings_allowed = False 750 719 751 def __init__(self, *args, **kwargs): 720 752 kwargs['max_length'] = 15 721 753 Field.__init__(self, *args, **kwargs) … … 729 761 return super(IPAddressField, self).formfield(**defaults) 730 762 731 763 class NullBooleanField(Field): 764 """Boolean (Either True, False or None)""" 765 732 766 empty_strings_allowed = False 767 733 768 def __init__(self, *args, **kwargs): 734 769 kwargs['null'] = True 735 770 Field.__init__(self, *args, **kwargs) … … 769 804 return super(NullBooleanField, self).formfield(**defaults) 770 805 771 806 class PositiveIntegerField(IntegerField): 807 """Integer""" 808 772 809 def get_internal_type(self): 773 810 return "PositiveIntegerField" 774 811 … … 778 815 return super(PositiveIntegerField, self).formfield(**defaults) 779 816 780 817 class PositiveSmallIntegerField(IntegerField): 818 """Integer""" 819 781 820 def get_internal_type(self): 782 821 return "PositiveSmallIntegerField" 783 822 … … 787 826 return super(PositiveSmallIntegerField, self).formfield(**defaults) 788 827 789 828 class SlugField(CharField): 829 """String (up to %(max_length)s)""" 830 790 831 def __init__(self, *args, **kwargs): 791 832 kwargs['max_length'] = kwargs.get('max_length', 50) 792 833 # Set db_index=True unless it's been set manually. … … 803 844 return super(SlugField, self).formfield(**defaults) 804 845 805 846 class SmallIntegerField(IntegerField): 847 """Integer""" 848 806 849 def get_internal_type(self): 807 850 return "SmallIntegerField" 808 851 809 852 class TextField(Field): 853 """Text""" 854 810 855 def get_internal_type(self): 811 856 return "TextField" 812 857 … … 816 861 return super(TextField, self).formfield(**defaults) 817 862 818 863 class TimeField(Field): 864 """Time""" 865 819 866 empty_strings_allowed = False 867 820 868 def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs): 821 869 self.auto_now, self.auto_now_add = auto_now, auto_now_add 822 870 if auto_now or auto_now_add: … … 888 936 return super(TimeField, self).formfield(**defaults) 889 937 890 938 class URLField(CharField): 939 """URL""" 940 891 941 def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs): 892 942 kwargs['max_length'] = kwargs.get('max_length', 200) 893 943 self.verify_exists = verify_exists … … 899 949 return super(URLField, self).formfield(**defaults) 900 950 901 951 class XMLField(TextField): 952 """XML text""" 953 902 954 def __init__(self, verbose_name=None, name=None, schema_path=None, **kwargs): 903 955 self.schema_path = schema_path 904 956 Field.__init__(self, verbose_name, name, **kwargs) -
django/db/models/fields/related.py
691 691 return self.to._meta.pk 692 692 693 693 class ForeignKey(RelatedField, Field): 694 """Foreign Key (type determined by related field)""" 695 694 696 empty_strings_allowed = False 695 697 def __init__(self, to, to_field=None, rel_class=ManyToOneRel, **kwargs): 696 698 try: … … 788 790 return rel_field.db_type() 789 791 790 792 class OneToOneField(ForeignKey): 791 """ 793 """One-to-one relationship 794 792 795 A OneToOneField is essentially the same as a ForeignKey, with the exception 793 796 that always carries a "unique" constraint with it and the reverse relation 794 797 always returns the object pointed to (since there will only ever be one), 795 rather than returning a list. 796 """ 798 rather than returning a list.""" 799 797 800 def __init__(self, to, to_field=None, **kwargs): 798 801 kwargs['unique'] = True 799 802 super(OneToOneField, self).__init__(to, to_field, OneToOneRel, **kwargs) … … 847 850 }) 848 851 849 852 class ManyToManyField(RelatedField, Field): 853 """Many-to-many relationship""" 854 850 855 def __init__(self, to, **kwargs): 851 856 try: 852 857 assert not to._meta.abstract, "%s cannot define a relation with abstract class %s" % (self.__class__.__name__, to._meta.object_name) -
django/db/models/fields/files.py
209 209 instance.__dict__[self.field.name] = value 210 210 211 211 class FileField(Field): 212 """File path""" 213 212 214 # The class to wrap instance attributes in. Accessing the file object off 213 215 # the instance will always return an instance of attr_class. 214 216 attr_class = FieldFile … … 323 325 super(ImageFieldFile, self).delete(save) 324 326 325 327 class ImageField(FileField): 328 """File path""" 329 326 330 attr_class = ImageFieldFile 327 331 descriptor_class = ImageFileDescriptor 328 332 -
django/contrib/gis/db/models/fields/__init__.py
30 30 return _srid_cache[srid] 31 31 32 32 class GeometryField(SpatialBackend.Field): 33 " The base GIS field -- maps to the OpenGIS Specification Geometry type."33 """The base GIS field -- maps to the OpenGIS Specification Geometry type.""" 34 34 35 35 # The OpenGIS Geometry name. 36 36 geom_type = 'GEOMETRY' … … 257 257 258 258 # The OpenGIS Geometry Type Fields 259 259 class PointField(GeometryField): 260 """Point""" 260 261 geom_type = 'POINT' 261 262 262 263 class LineStringField(GeometryField): 264 """Line string""" 263 265 geom_type = 'LINESTRING' 264 266 265 267 class PolygonField(GeometryField): 268 """Polygon""" 266 269 geom_type = 'POLYGON' 267 270 268 271 class MultiPointField(GeometryField): 272 """Multi-point""" 269 273 geom_type = 'MULTIPOINT' 270 274 271 275 class MultiLineStringField(GeometryField): 276 """Multi-line string""" 272 277 geom_type = 'MULTILINESTRING' 273 278 274 279 class MultiPolygonField(GeometryField): 280 """Multi polygon""" 275 281 geom_type = 'MULTIPOLYGON' 276 282 277 283 class GeometryCollectionField(GeometryField): 284 """Geometry collection""" 278 285 geom_type = 'GEOMETRYCOLLECTION' -
django/contrib/admindocs/views.py
326 326 return 'Integer' 327 327 return '' 328 328 329 # Maps Field objects to their human-readable data types, as strings.330 # Column-type strings can contain format strings; they'll be interpolated331 # against the values of Field.__dict__ before being output.332 # If a column type is set to None, it won't be included in the output.333 DATA_TYPE_MAPPING = {334 'AutoField' : _('Integer'),335 'BooleanField' : _('Boolean (Either True or False)'),336 'CharField' : _('String (up to %(max_length)s)'),337 'CommaSeparatedIntegerField': _('Comma-separated integers'),338 'DateField' : _('Date (without time)'),339 'DateTimeField' : _('Date (with time)'),340 'DecimalField' : _('Decimal number'),341 'EmailField' : _('E-mail address'),342 'FileField' : _('File path'),343 'FilePathField' : _('File path'),344 'FloatField' : _('Floating point number'),345 'ForeignKey' : _('Integer'),346 'ImageField' : _('File path'),347 'IntegerField' : _('Integer'),348 'IPAddressField' : _('IP address'),349 'ManyToManyField' : '',350 'NullBooleanField' : _('Boolean (Either True, False or None)'),351 'OneToOneField' : _('Relation to parent model'),352 'PhoneNumberField' : _('Phone number'),353 'PositiveIntegerField' : _('Integer'),354 'PositiveSmallIntegerField' : _('Integer'),355 'SlugField' : _('String (up to %(max_length)s)'),356 'SmallIntegerField' : _('Integer'),357 'TextField' : _('Text'),358 'TimeField' : _('Time'),359 'URLField' : _('URL'),360 'USStateField' : _('U.S. state (two uppercase letters)'),361 'XMLField' : _('XML text'),362 }363 364 329 def get_readable_field_data_type(field): 365 return DATA_TYPE_MAPPING[field.get_internal_type()] % field.__dict__ 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.""" 366 335 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 } 343 367 344 def extract_views_from_urlpatterns(urlpatterns, base=''): 368 345 """ 369 346 Return a list of views from a list of urlpatterns. -
django/contrib/admindocs/tests.py
1 import unittest 2 import views 3 from django.db.models import fields as builtin_fields 4 import models 5 6 7 class TestFieldType(unittest.TestCase): 8 def setUp(self): 9 pass 10 11 def test_field_name(self): 12 self.assertRaises(AttributeError, 13 views.get_readable_field_data_type, "NotAField" 14 ) 15 16 def test_builtin_fields(self): 17 self.assertEqual( 18 views.get_readable_field_data_type(builtin_fields.BooleanField()), 19 u'Boolean (Either True or False)' 20 ) 21 22 def test_custom_fields(self): 23 self.assertEqual( 24 views.get_readable_field_data_type(models.CustomField()), 25 u'A custom field type' 26 ) 27 self.assertEqual( 28 views.get_readable_field_data_type(models.DocstringLackingField()), 29 u'Field of type: DocstringLackingField' 30 ) 31 32 def test_multiline_custom_field_truncation(self): 33 self.assertEqual( 34 views.get_readable_field_data_type(models.ManyLineDocstringField()), 35 u'Many-line custom field' 36 ) -
django/contrib/admindocs/models.py
1 2 from django.db import models 3 4 class CustomField(models.Field): 5 """A custom field type""" 6 7 class ManyLineDocstringField(models.Field): 8 """Many-line custom field 9 10 This docstring has many lines. Lorum ipsem etc. etc. Four score 11 and seven years ago, and so on and so forth.""" 12 13 class DocstringLackingField(models.Field): 14 pass -
django/contrib/localflavor/us/models.py
2 2 from django.db.models.fields import Field 3 3 4 4 class USStateField(Field): 5 """U.S. state (two uppercase letters)""" 5 6 def get_internal_type(self): 6 7 return "USStateField" 7 8 … … 18 19 return super(USStateField, self).formfield(**defaults) 19 20 20 21 class PhoneNumberField(Field): 22 """Phone number""" 21 23 def get_internal_type(self): 22 24 return "PhoneNumberField" 23 25 -
docs/howto/custom-model-fields.txt
39 39 something like this:: 40 40 41 41 class Hand(object): 42 """A hand of cards (bridge style)""" 43 42 44 def __init__(self, north, east, south, west): 43 45 # Input parameters are lists of cards ('Ah', '9s', etc) 44 46 self.north = north … … 163 165 from django.db import models 164 166 165 167 class HandField(models.Field): 168 """A hand of cards (bridge style)""" 169 166 170 def __init__(self, *args, **kwargs): 167 171 kwargs['max_length'] = 104 168 172 super(HandField, self).__init__(*args, **kwargs) … … 244 248 For example:: 245 249 246 250 class HandField(models.Field): 251 """A hand of cards (bridge style)""" 252 247 253 __metaclass__ = models.SubfieldBase 248 254 249 255 def __init__(self, *args, **kwargs): … … 252 258 This ensures that the :meth:`to_python` method, documented below, will always be 253 259 called when the attribute is initialized. 254 260 261 262 Documenting your Custom Field 263 ----------------------------- 264 265 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. 275 255 276 Useful methods 256 277 -------------- 257 278