Ticket #7977: admindocs_field_types_classattr.diff

File admindocs_field_types_classattr.diff, 15.9 KB (added by jcd, 6 years ago)

Patch that allows fields to define type in class attribute

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

     
    5959    creation_counter = 0
    6060    auto_creation_counter = -1
    6161
     62    # Field type description
     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
    6269    def __init__(self, verbose_name=None, name=None, primary_key=False,
    6370            max_length=None, unique=False, blank=False, null=False,
    6471            db_index=False, rel=None, default=NOT_PROVIDED, editable=True,
     
    341348
    342349class AutoField(Field):
    343350    empty_strings_allowed = False
     351    description = u"Integer"
     352
    344353    def __init__(self, *args, **kwargs):
    345354        assert kwargs.get('primary_key', False) is True, "%ss must have primary_key=True." % self.__class__.__name__
    346355        kwargs['blank'] = True
     
    371380
    372381class BooleanField(Field):
    373382    empty_strings_allowed = False
     383    description = u"Boolean (Either True or False)"
     384
    374385    def __init__(self, *args, **kwargs):
    375386        kwargs['blank'] = True
    376387        if 'default' not in kwargs and not kwargs.get('null'):
     
    413424        return super(BooleanField, self).formfield(**defaults)
    414425
    415426class CharField(Field):
     427    description = u"String (up to %(max_length)s)"
     428
    416429    def get_internal_type(self):
    417430        return "CharField"
    418431
     
    434447
    435448# TODO: Maybe move this into contrib, because it's specialized.
    436449class CommaSeparatedIntegerField(CharField):
     450    description = u"Comma-separated integers"
     451
    437452    def formfield(self, **kwargs):
    438453        defaults = {
    439454            'form_class': forms.RegexField,
     
    450465
    451466class DateField(Field):
    452467    empty_strings_allowed = False
     468    description = u"Date (without time)"
     469
    453470    def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs):
    454471        self.auto_now, self.auto_now_add = auto_now, auto_now_add
    455472        #HACKs : auto_now_add/auto_now should be done as a default or a pre_save.
     
    524541        return super(DateField, self).formfield(**defaults)
    525542
    526543class DateTimeField(DateField):
     544    description = u"Date (with time)"
     545
    527546    def get_internal_type(self):
    528547        return "DateTimeField"
    529548
     
    584603
    585604class DecimalField(Field):
    586605    empty_strings_allowed = False
     606    description = u"Decimal number"
     607
    587608    def __init__(self, verbose_name=None, name=None, max_digits=None, decimal_places=None, **kwargs):
    588609        self.max_digits, self.decimal_places = max_digits, decimal_places
    589610        Field.__init__(self, verbose_name, name, **kwargs)
     
    637658        return super(DecimalField, self).formfield(**defaults)
    638659
    639660class EmailField(CharField):
     661    description = u"E-mail address"
     662
    640663    def __init__(self, *args, **kwargs):
    641664        kwargs['max_length'] = kwargs.get('max_length', 75)
    642665        CharField.__init__(self, *args, **kwargs)
     
    647670        return super(EmailField, self).formfield(**defaults)
    648671
    649672class FilePathField(Field):
     673    description = u"File path"
     674
    650675    def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
    651676        self.path, self.match, self.recursive = path, match, recursive
    652677        kwargs['max_length'] = kwargs.get('max_length', 100)
     
    667692
    668693class FloatField(Field):
    669694    empty_strings_allowed = False
     695    description = u"Floating point number"
    670696
    671697    def get_db_prep_value(self, value):
    672698        if value is None:
     
    692718
    693719class IntegerField(Field):
    694720    empty_strings_allowed = False
     721    description = u"Integer"
     722
    695723    def get_db_prep_value(self, value):
    696724        if value is None:
    697725            return None
     
    716744
    717745class IPAddressField(Field):
    718746    empty_strings_allowed = False
     747    description = u"IP address"
     748
    719749    def __init__(self, *args, **kwargs):
    720750        kwargs['max_length'] = 15
    721751        Field.__init__(self, *args, **kwargs)
     
    730760
    731761class NullBooleanField(Field):
    732762    empty_strings_allowed = False
     763    description = u"Boolean (Either True, False or None)"
     764
    733765    def __init__(self, *args, **kwargs):
    734766        kwargs['null'] = True
    735767        Field.__init__(self, *args, **kwargs)
     
    769801        return super(NullBooleanField, self).formfield(**defaults)
    770802
    771803class PositiveIntegerField(IntegerField):
     804
    772805    def get_internal_type(self):
    773806        return "PositiveIntegerField"
    774807
     
    778811        return super(PositiveIntegerField, self).formfield(**defaults)
    779812
    780813class PositiveSmallIntegerField(IntegerField):
     814
    781815    def get_internal_type(self):
    782816        return "PositiveSmallIntegerField"
    783817
     
    787821        return super(PositiveSmallIntegerField, self).formfield(**defaults)
    788822
    789823class SlugField(CharField):
     824
    790825    def __init__(self, *args, **kwargs):
    791826        kwargs['max_length'] = kwargs.get('max_length', 50)
    792827        # Set db_index=True unless it's been set manually.
     
    803838        return super(SlugField, self).formfield(**defaults)
    804839
    805840class SmallIntegerField(IntegerField):
     841
    806842    def get_internal_type(self):
    807843        return "SmallIntegerField"
    808844
    809845class TextField(Field):
     846    description = u"Text"
     847
    810848    def get_internal_type(self):
    811849        return "TextField"
    812850
     
    816854        return super(TextField, self).formfield(**defaults)
    817855
    818856class TimeField(Field):
     857    description = u"Time"
     858
    819859    empty_strings_allowed = False
     860
    820861    def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs):
    821862        self.auto_now, self.auto_now_add = auto_now, auto_now_add
    822863        if auto_now or auto_now_add:
     
    888929        return super(TimeField, self).formfield(**defaults)
    889930
    890931class URLField(CharField):
     932    description = u"URL"
     933
    891934    def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs):
    892935        kwargs['max_length'] = kwargs.get('max_length', 200)
    893936        self.verify_exists = verify_exists
     
    899942        return super(URLField, self).formfield(**defaults)
    900943
    901944class XMLField(TextField):
     945    description = u"XML text"
     946
    902947    def __init__(self, verbose_name=None, name=None, schema_path=None, **kwargs):
    903948        self.schema_path = schema_path
    904949        Field.__init__(self, verbose_name, name, **kwargs)
  • django/db/models/fields/related.py

     
    683683
    684684class ForeignKey(RelatedField, Field):
    685685    empty_strings_allowed = False
     686    description = u"Foreign Key (type determined by related field)"
     687
    686688    def __init__(self, to, to_field=None, rel_class=ManyToOneRel, **kwargs):
    687689        try:
    688690            to_name = to._meta.object_name.lower()
     
    777779    always returns the object pointed to (since there will only ever be one),
    778780    rather than returning a list.
    779781    """
     782
     783    description = u"One-to-one relationship"
     784
    780785    def __init__(self, to, to_field=None, **kwargs):
    781786        kwargs['unique'] = True
    782787        super(OneToOneField, self).__init__(to, to_field, OneToOneRel, **kwargs)
     
    791796        return super(OneToOneField, self).formfield(**kwargs)
    792797
    793798class ManyToManyField(RelatedField, Field):
     799    description = u"Many-to-many relationship"
     800
    794801    def __init__(self, to, **kwargs):
    795802        try:
    796803            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    description = u"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    description = u"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."
    34 
    3533    # The OpenGIS Geometry name.
    3634    geom_type = 'GEOMETRY'
    3735
    3836    # Geodetic units.
    3937    geodetic_units = ('Decimal Degree', 'degree')
    4038
     39    description = u"The base GIS field -- maps to the OpenGIS Specification Geometry type."
     40
    4141    def __init__(self, verbose_name=None, srid=4326, spatial_index=True, dim=2, **kwargs):
    4242        """
    4343        The initialization function for geometry fields.  Takes the following
     
    258258# The OpenGIS Geometry Type Fields
    259259class PointField(GeometryField):
    260260    geom_type = 'POINT'
     261    description = u"Point"
    261262
    262263class LineStringField(GeometryField):
    263264    geom_type = 'LINESTRING'
     265    description = u"Line string"
    264266
    265267class PolygonField(GeometryField):
    266268    geom_type = 'POLYGON'
     269    description = u"Polygon"
    267270
    268271class MultiPointField(GeometryField):
    269272    geom_type = 'MULTIPOINT'
     273    description = u"Multi-point"
    270274
    271275class MultiLineStringField(GeometryField):
    272276    geom_type = 'MULTILINESTRING'
     277    description = u"Multi-line string"
    273278
    274279class MultiPolygonField(GeometryField):
    275280    geom_type = 'MULTIPOLYGON'
     281    description = u"Multi-polygon"
    276282
    277283class GeometryCollectionField(GeometryField):
    278284    geom_type = 'GEOMETRYCOLLECTION'
     285    description = u"Geometry collection"
     286 No newline at end of file
  • django/contrib/admindocs/views.py

     
    179179def model_detail(request, app_label, model_name):
    180180    if not utils.docutils_is_available:
    181181        return missing_docutils_page(request)
    182        
     182
    183183    # Get the model class.
    184184    try:
    185185        app_mod = models.get_app(app_label)
     
    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 description for a given field type, if it exists,
     312    Fields' descriptions can contain format strings, which will be interpolated
     313    against the values of field.__dict__ before being output."""
    347314
     315    return _(field.description) % field.__dict__
     316
    348317def extract_views_from_urlpatterns(urlpatterns, base=''):
    349318    """
    350319    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.DescriptionLackingField()),
     36            u'Field of type: DescriptionLackingField'
     37        )
  • django/contrib/admindocs/models.py

     
     1"""Models for admindocs unittests."""
     2
     3from django.db import models
     4
     5class CustomField(models.Field):
     6    description = u"A custom field type"
     7
     8class DescriptionLackingField(models.Field):
     9    pass
  • django/contrib/localflavor/us/models.py

     
    11from django.conf import settings
    22from django.db.models.fields import Field
    33
    4 class USStateField(Field):
    5     def get_internal_type(self):
    6         return "USStateField"
    7        
     4class USStateField(Field):
     5    description = u"U.S. state (two uppercase letters)"
     6
     7    def get_internal_type(self):
     8        return "USStateField"
     9
    810    def db_type(self):
    911        if settings.DATABASE_ENGINE == 'oracle':
    1012            return 'CHAR(2)'
    1113        else:
    1214            return 'varchar(2)'
    13    
    14     def formfield(self, **kwargs): 
    15         from django.contrib.localflavor.us.forms import USStateSelect 
    16         defaults = {'widget': USStateSelect} 
    17         defaults.update(kwargs) 
     15
     16    def formfield(self, **kwargs):
     17        from django.contrib.localflavor.us.forms import USStateSelect
     18        defaults = {'widget': USStateSelect}
     19        defaults.update(kwargs)
    1820        return super(USStateField, self).formfield(**defaults)
    1921
    2022class PhoneNumberField(Field):
     23    description = u"Phone number"
     24
    2125    def get_internal_type(self):
    2226        return "PhoneNumberField"
    2327
Back to Top