Ticket #7977: admindocs_field_types.diff

File admindocs_field_types.diff, 15.4 KB (added by jcd, 6 years ago)

Patch that allows fields to define type in docstrings

  • django/db/models/fields/__init__.py

     
    4949#     getattr(obj, opts.pk.attname)
    5050
    5151class Field(object):
     52    """Base class for all field types"""
     53   
    5254    # Designates whether empty strings fundamentally are allowed at the
    5355    # database level.
    5456    empty_strings_allowed = True
     
    340342        return getattr(obj, self.attname)
    341343
    342344class AutoField(Field):
     345    """Integer"""
     346   
    343347    empty_strings_allowed = False
     348
    344349    def __init__(self, *args, **kwargs):
    345350        assert kwargs.get('primary_key', False) is True, "%ss must have primary_key=True." % self.__class__.__name__
    346351        kwargs['blank'] = True
     
    370375        return None
    371376
    372377class BooleanField(Field):
     378    """Boolean (Either True or False)"""
     379
    373380    empty_strings_allowed = False
     381
    374382    def __init__(self, *args, **kwargs):
    375383        kwargs['blank'] = True
    376384        if 'default' not in kwargs and not kwargs.get('null'):
     
    413421        return super(BooleanField, self).formfield(**defaults)
    414422
    415423class CharField(Field):
     424    """String (up to %(max_length)s)"""
     425   
    416426    def get_internal_type(self):
    417427        return "CharField"
    418428
     
    434444
    435445# TODO: Maybe move this into contrib, because it's specialized.
    436446class CommaSeparatedIntegerField(CharField):
     447    """Comma-separated integers"""
     448   
    437449    def formfield(self, **kwargs):
    438450        defaults = {
    439451            'form_class': forms.RegexField,
     
    449461ansi_date_re = re.compile(r'^\d{4}-\d{1,2}-\d{1,2}$')
    450462
    451463class DateField(Field):
     464    """Date (without time)"""
     465   
    452466    empty_strings_allowed = False
     467
    453468    def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs):
    454469        self.auto_now, self.auto_now_add = auto_now, auto_now_add
    455470        #HACKs : auto_now_add/auto_now should be done as a default or a pre_save.
     
    524539        return super(DateField, self).formfield(**defaults)
    525540
    526541class DateTimeField(DateField):
     542    """Date (with time)"""
     543   
    527544    def get_internal_type(self):
    528545        return "DateTimeField"
    529546
     
    583600        return super(DateTimeField, self).formfield(**defaults)
    584601
    585602class DecimalField(Field):
     603    """Decimal number"""
     604   
    586605    empty_strings_allowed = False
     606
    587607    def __init__(self, verbose_name=None, name=None, max_digits=None, decimal_places=None, **kwargs):
    588608        self.max_digits, self.decimal_places = max_digits, decimal_places
    589609        Field.__init__(self, verbose_name, name, **kwargs)
     
    637657        return super(DecimalField, self).formfield(**defaults)
    638658
    639659class EmailField(CharField):
     660    """E-mail address"""
     661   
    640662    def __init__(self, *args, **kwargs):
    641663        kwargs['max_length'] = kwargs.get('max_length', 75)
    642664        CharField.__init__(self, *args, **kwargs)
     
    647669        return super(EmailField, self).formfield(**defaults)
    648670
    649671class FilePathField(Field):
     672    """File path"""
     673   
    650674    def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
    651675        self.path, self.match, self.recursive = path, match, recursive
    652676        kwargs['max_length'] = kwargs.get('max_length', 100)
     
    666690        return "FilePathField"
    667691
    668692class FloatField(Field):
     693    """Floating point number"""
     694   
    669695    empty_strings_allowed = False
    670696
    671697    def get_db_prep_value(self, value):
     
    691717        return super(FloatField, self).formfield(**defaults)
    692718
    693719class IntegerField(Field):
     720    """Integer"""
     721   
    694722    empty_strings_allowed = False
     723
    695724    def get_db_prep_value(self, value):
    696725        if value is None:
    697726            return None
     
    715744        return super(IntegerField, self).formfield(**defaults)
    716745
    717746class IPAddressField(Field):
     747    """IP address"""
     748   
    718749    empty_strings_allowed = False
     750
    719751    def __init__(self, *args, **kwargs):
    720752        kwargs['max_length'] = 15
    721753        Field.__init__(self, *args, **kwargs)
     
    729761        return super(IPAddressField, self).formfield(**defaults)
    730762
    731763class NullBooleanField(Field):
     764    """Boolean (Either True, False or None)"""
     765
    732766    empty_strings_allowed = False
     767
    733768    def __init__(self, *args, **kwargs):
    734769        kwargs['null'] = True
    735770        Field.__init__(self, *args, **kwargs)
     
    769804        return super(NullBooleanField, self).formfield(**defaults)
    770805
    771806class PositiveIntegerField(IntegerField):
     807    """Integer"""
     808   
    772809    def get_internal_type(self):
    773810        return "PositiveIntegerField"
    774811
     
    778815        return super(PositiveIntegerField, self).formfield(**defaults)
    779816
    780817class PositiveSmallIntegerField(IntegerField):
     818    """Integer"""
     819
    781820    def get_internal_type(self):
    782821        return "PositiveSmallIntegerField"
    783822
     
    787826        return super(PositiveSmallIntegerField, self).formfield(**defaults)
    788827
    789828class SlugField(CharField):
     829    """String (up to %(max_length)s)"""
     830
    790831    def __init__(self, *args, **kwargs):
    791832        kwargs['max_length'] = kwargs.get('max_length', 50)
    792833        # Set db_index=True unless it's been set manually.
     
    803844        return super(SlugField, self).formfield(**defaults)
    804845
    805846class SmallIntegerField(IntegerField):
     847    """Integer"""
     848   
    806849    def get_internal_type(self):
    807850        return "SmallIntegerField"
    808851
    809852class TextField(Field):
     853    """Text"""
     854   
    810855    def get_internal_type(self):
    811856        return "TextField"
    812857
     
    816861        return super(TextField, self).formfield(**defaults)
    817862
    818863class TimeField(Field):
     864    """Time"""
     865   
    819866    empty_strings_allowed = False
     867
    820868    def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs):
    821869        self.auto_now, self.auto_now_add = auto_now, auto_now_add
    822870        if auto_now or auto_now_add:
     
    888936        return super(TimeField, self).formfield(**defaults)
    889937
    890938class URLField(CharField):
     939    """URL"""
     940   
    891941    def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs):
    892942        kwargs['max_length'] = kwargs.get('max_length', 200)
    893943        self.verify_exists = verify_exists
     
    899949        return super(URLField, self).formfield(**defaults)
    900950
    901951class XMLField(TextField):
     952    """XML text"""
     953   
    902954    def __init__(self, verbose_name=None, name=None, schema_path=None, **kwargs):
    903955        self.schema_path = schema_path
    904956        Field.__init__(self, verbose_name, name, **kwargs)
  • django/db/models/fields/related.py

     
    682682        return self.to._meta.pk
    683683
    684684class ForeignKey(RelatedField, Field):
     685    """Foreign Key (type determined by related field)"""
     686   
    685687    empty_strings_allowed = False
    686688    def __init__(self, to, to_field=None, rel_class=ManyToOneRel, **kwargs):
    687689        try:
     
    771773        return rel_field.db_type()
    772774
    773775class OneToOneField(ForeignKey):
    774     """
    775     A OneToOneField is essentially the same as a ForeignKey, with the exception
    776     that always carries a "unique" constraint with it and the reverse relation
    777     always returns the object pointed to (since there will only ever be one),
    778     rather than returning a list.
    779     """
     776    """One-to-one relationship"""
     777   
     778    # A OneToOneField is essentially the same as a ForeignKey, with the exception
     779    # that always carries a "unique" constraint with it and the reverse relation
     780    # always returns the object pointed to (since there will only ever be one),
     781    # rather than returning a list.
     782
    780783    def __init__(self, to, to_field=None, **kwargs):
    781784        kwargs['unique'] = True
    782785        super(OneToOneField, self).__init__(to, to_field, OneToOneRel, **kwargs)
     
    791794        return super(OneToOneField, self).formfield(**kwargs)
    792795
    793796class ManyToManyField(RelatedField, Field):
     797    """Many-to-many relationship"""
     798   
    794799    def __init__(self, to, **kwargs):
    795800        try:
    796801            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

     
    209209        instance.__dict__[self.field.name] = value
    210210
    211211class FileField(Field):
     212    """File path"""
     213   
    212214    # The class to wrap instance attributes in. Accessing the file object off
    213215    # the instance will always return an instance of attr_class.
    214216    attr_class = FieldFile
     
    323325        super(ImageFieldFile, self).delete(save)
    324326
    325327class ImageField(FileField):
     328    """File path"""
     329   
    326330    attr_class = ImageFieldFile
    327331    descriptor_class = ImageFileDescriptor
    328332
  • django/contrib/gis/db/models/fields/__init__.py

     
    3030    return _srid_cache[srid]
    3131
    3232class 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."""
    3434
    3535    # The OpenGIS Geometry name.
    3636    geom_type = 'GEOMETRY'
     
    257257
    258258# The OpenGIS Geometry Type Fields
    259259class PointField(GeometryField):
     260    """Point"""
    260261    geom_type = 'POINT'
    261262
    262263class LineStringField(GeometryField):
     264    """Line string"""
    263265    geom_type = 'LINESTRING'
    264266
    265267class PolygonField(GeometryField):
     268    """Polygon"""
    266269    geom_type = 'POLYGON'
    267270
    268271class MultiPointField(GeometryField):
     272    """Multi-point"""
    269273    geom_type = 'MULTIPOINT'
    270274
    271275class MultiLineStringField(GeometryField):
     276    """Multi-line string"""
    272277    geom_type = 'MULTILINESTRING'
    273278
    274279class MultiPolygonField(GeometryField):
     280    """Multi polygon"""
    275281    geom_type = 'MULTIPOLYGON'
    276282
    277283class GeometryCollectionField(GeometryField):
     284    """Geometry collection"""
    278285    geom_type = 'GEOMETRYCOLLECTION'
  • django/contrib/admindocs/views.py

     
    307307            return 'Integer'
    308308    return ''
    309309
    310 # Maps Field objects to their human-readable data types, as strings.
    311 # Column-type strings can contain format strings; they'll be interpolated
    312 # against the values of Field.__dict__ before being output.
    313 # If a column type is set to None, it won't be included in the output.
    314 DATA_TYPE_MAPPING = {
    315     'AutoField'                 : _('Integer'),
    316     'BooleanField'              : _('Boolean (Either True or False)'),
    317     'CharField'                 : _('String (up to %(max_length)s)'),
    318     'CommaSeparatedIntegerField': _('Comma-separated integers'),
    319     'DateField'                 : _('Date (without time)'),
    320     'DateTimeField'             : _('Date (with time)'),
    321     'DecimalField'              : _('Decimal number'),
    322     'EmailField'                : _('E-mail address'),
    323     'FileField'                 : _('File path'),
    324     'FilePathField'             : _('File path'),
    325     'FloatField'                : _('Floating point number'),
    326     'ForeignKey'                : _('Integer'),
    327     'ImageField'                : _('File path'),
    328     'IntegerField'              : _('Integer'),
    329     'IPAddressField'            : _('IP address'),
    330     'ManyToManyField'           : '',
    331     'NullBooleanField'          : _('Boolean (Either True, False or None)'),
    332     'OneToOneField'             : _('Relation to parent model'),
    333     'PhoneNumberField'          : _('Phone number'),
    334     'PositiveIntegerField'      : _('Integer'),
    335     'PositiveSmallIntegerField' : _('Integer'),
    336     'SlugField'                 : _('String (up to %(max_length)s)'),
    337     'SmallIntegerField'         : _('Integer'),
    338     'TextField'                 : _('Text'),
    339     'TimeField'                 : _('Time'),
    340     'URLField'                  : _('URL'),
    341     'USStateField'              : _('U.S. state (two uppercase letters)'),
    342     'XMLField'                  : _('XML text'),
    343 }
    344 
    345310def get_readable_field_data_type(field):
    346     return DATA_TYPE_MAPPING[field.get_internal_type()] % field.__dict__
     311    """Returns the doc string for a given field type, if it exists,
     312    Fields' docstrings can contain format strings, which will be interpolated
     313    against the values of Field.__dict__ before being output.  If no docstring
     314    is given, a sensible value will be auto-generated from the field's class
     315    name."""
    347316
     317    if field.__doc__:
     318        return _(field.__doc__) % field.__dict__
     319    else:
     320        return _(u'Field of type: %(field_type)s') % {
     321            'field_type': field.__class__.__name__
     322        }
     323
    348324def extract_views_from_urlpatterns(urlpatterns, base=''):
    349325    """
    350326    Return a list of views from a list of urlpatterns.
  • django/contrib/admindocs/tests.py

     
     1import unittest
     2import views
     3from django.db.models import fields as builtin_fields
     4#import django.contrib.gis.db.models.fields as gis_fields
     5import models
     6
     7
     8class TestFieldType(unittest.TestCase):
     9    def setUp(self):
     10        pass
     11       
     12    def test_field_name(self):
     13        self.assertRaises(AttributeError,
     14            views.get_readable_field_data_type, "NotAField"
     15        )
     16       
     17    def test_builtin_fields(self):
     18        self.assertEqual(
     19            views.get_readable_field_data_type(builtin_fields.BooleanField()),
     20            u'Boolean (Either True or False)'
     21        )
     22   
     23    #def test_gis_fields(self):
     24    #    self.assertEqual(
     25    #        views.get_readable_field_data_type(gis_fields.PolygonField),
     26    #        u'Polygon!'
     27    #    )
     28       
     29    def test_custom_fields(self):
     30        self.assertEqual(
     31            views.get_readable_field_data_type(models.CustomField()),
     32            u'A custom field type'
     33        )
     34        self.assertEqual(
     35            views.get_readable_field_data_type(models.DocstringLackingField()),
     36            u'Field of type: DocstringLackingField'
     37        )
  • django/contrib/admindocs/models.py

     
     1
     2from django.db import models
     3
     4class CustomField(models.Field):
     5    """A custom field type"""
     6   
     7class DocstringLackingField(models.Field):
     8    pass
  • django/contrib/localflavor/us/models.py

     
    22from django.db.models.fields import Field
    33
    44class USStateField(Field):
     5    """U.S. state (two uppercase letters)"""
    56    def get_internal_type(self):
    67        return "USStateField"
    78       
     
    1819        return super(USStateField, self).formfield(**defaults)
    1920
    2021class PhoneNumberField(Field):
     22    """Phone number"""
    2123    def get_internal_type(self):
    2224        return "PhoneNumberField"
    2325
Back to Top