Ticket #7977: admindocs_field_types_revised2.diff

File admindocs_field_types_revised2.diff, 17.3 KB (added by jcd, 5 years ago)

Moves tests and related files into tests subdirectory

  • 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

     
    691691        return self.to._meta.pk
    692692
    693693class ForeignKey(RelatedField, Field):
     694    """Foreign Key (type determined by related field)"""
     695   
    694696    empty_strings_allowed = False
    695697    def __init__(self, to, to_field=None, rel_class=ManyToOneRel, **kwargs):
    696698        try:
     
    788790        return rel_field.db_type()
    789791
    790792class OneToOneField(ForeignKey):
    791     """
     793    """One-to-one relationship
     794   
    792795    A OneToOneField is essentially the same as a ForeignKey, with the exception
    793796    that always carries a "unique" constraint with it and the reverse relation
    794797    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
    797800    def __init__(self, to, to_field=None, **kwargs):
    798801        kwargs['unique'] = True
    799802        super(OneToOneField, self).__init__(to, to_field, OneToOneRel, **kwargs)
     
    847850    })
    848851
    849852class ManyToManyField(RelatedField, Field):
     853    """Many-to-many relationship"""
     854   
    850855    def __init__(self, to, **kwargs):
    851856        try:
    852857            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/tests/__init__.py

     
     1import unittest
     2from django.contrib.admindocs import views
     3import fields
     4
     5from django.db.models import fields as builtin_fields
     6
     7class 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(fields.CustomField()),
     25            u'A custom field type'
     26        )
     27        self.assertEqual(
     28            views.get_readable_field_data_type(fields.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(fields.ManyLineDocstringField()),
     35            u'Many-line custom field'
     36        )
  • django/contrib/admindocs/tests/fields.py

     
     1from django.db import models
     2
     3class CustomField(models.Field):
     4    """A custom field type"""
     5   
     6class 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."""
     11
     12class DocstringLackingField(models.Field):
     13    pass
  • django/contrib/admindocs/views.py

     
    326326            return 'Integer'
    327327    return ''
    328328
    329 # Maps Field objects to their human-readable data types, as strings.
    330 # Column-type strings can contain format strings; they'll be interpolated
    331 # 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 
    364329def 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."""
    366335
     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
    367344def extract_views_from_urlpatterns(urlpatterns, base=''):
    368345    """
    369346    Return a list of views from a list of urlpatterns.
  • 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
  • docs/howto/custom-model-fields.txt

     
    3939something like this::
    4040
    4141    class Hand(object):
     42        """A hand of cards (bridge style)"""
     43
    4244        def __init__(self, north, east, south, west):
    4345            # Input parameters are lists of cards ('Ah', '9s', etc)
    4446            self.north = north
     
    163165    from django.db import models
    164166
    165167    class HandField(models.Field):
     168        """A hand of cards (bridge style)"""
     169
    166170        def __init__(self, *args, **kwargs):
    167171            kwargs['max_length'] = 104
    168172            super(HandField, self).__init__(*args, **kwargs)
     
    244248For example::
    245249
    246250    class HandField(models.Field):
     251        """A hand of cards (bridge style)"""
     252
    247253        __metaclass__ = models.SubfieldBase
    248254
    249255        def __init__(self, *args, **kwargs):
     
    252258This ensures that the :meth:`to_python` method, documented below, will always be
    253259called when the attribute is initialized.
    254260
     261
     262Documenting your Custom Field
     263-----------------------------
     264
     265As always, you should document your field type, so users will know what it is.
     266The best way to do this is to simply provide a docstring for it.  This will
     267automatically be picked up by ``django.contrib.admindocs``, if you have it
     268installed, and the first line of it will show up as the field type in the
     269documentation for any model that uses your field.  In the above examples, it
     270will show up as 'A hand of cards (bridge style)'.  Note that if you provide a
     271more verbose docstring, only the first line will show up in
     272``django.contrib.admindocs``.  The full docstring will, of course, still be
     273available through ``pydoc`` or the interactive interpreter's ``help()``
     274function.
     275
    255276Useful methods
    256277--------------
    257278
Back to Top