Fixed #12385: Made built-in field type descriptions in admindocs translatable again. Many thanks to Ramiro for the problem report and patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@11878 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
4e81086021
commit
833df0afaa
|
@ -1,9 +1,9 @@
|
||||||
import unittest
|
import unittest
|
||||||
from django.contrib.admindocs import views
|
|
||||||
import fields
|
import fields
|
||||||
|
from django.contrib.admindocs import views
|
||||||
from django.db.models import fields as builtin_fields
|
from django.db.models import fields as builtin_fields
|
||||||
|
|
||||||
|
|
||||||
class TestFieldType(unittest.TestCase):
|
class TestFieldType(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
pass
|
pass
|
||||||
|
@ -25,12 +25,6 @@ class TestFieldType(unittest.TestCase):
|
||||||
u'A custom field type'
|
u'A custom field type'
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
views.get_readable_field_data_type(fields.DocstringLackingField()),
|
views.get_readable_field_data_type(fields.DescriptionLackingField()),
|
||||||
u'Field of type: DocstringLackingField'
|
u'Field of type: DescriptionLackingField'
|
||||||
)
|
|
||||||
|
|
||||||
def test_multiline_custom_field_truncation(self):
|
|
||||||
self.assertEqual(
|
|
||||||
views.get_readable_field_data_type(fields.ManyLineDocstringField()),
|
|
||||||
u'Many-line custom field'
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
class CustomField(models.Field):
|
class CustomField(models.Field):
|
||||||
"""A custom field type"""
|
description = "A custom field type"
|
||||||
|
|
||||||
class ManyLineDocstringField(models.Field):
|
class DescriptionLackingField(models.Field):
|
||||||
"""Many-line custom field
|
|
||||||
|
|
||||||
This docstring has many lines. Lorum ipsem etc. etc. Four score
|
|
||||||
and seven years ago, and so on and so forth."""
|
|
||||||
|
|
||||||
class DocstringLackingField(models.Field):
|
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -327,19 +327,11 @@ def get_return_data_type(func_name):
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def get_readable_field_data_type(field):
|
def get_readable_field_data_type(field):
|
||||||
"""Returns the first line of a doc string for a given field type, if it
|
"""Returns the description for a given field type, if it exists,
|
||||||
exists. Fields' docstrings can contain format strings, which will be
|
Fields' descriptions can contain format strings, which will be interpolated
|
||||||
interpolated against the values of Field.__dict__ before being output.
|
against the values of field.__dict__ before being output."""
|
||||||
If no docstring is given, a sensible value will be auto-generated from
|
|
||||||
the field's class name."""
|
|
||||||
|
|
||||||
if field.__doc__:
|
return field.description % field.__dict__
|
||||||
doc = field.__doc__.split('\n')[0]
|
|
||||||
return _(doc) % field.__dict__
|
|
||||||
else:
|
|
||||||
return _(u'Field of type: %(field_type)s') % {
|
|
||||||
'field_type': field.__class__.__name__
|
|
||||||
}
|
|
||||||
|
|
||||||
def extract_views_from_urlpatterns(urlpatterns, base=''):
|
def extract_views_from_urlpatterns(urlpatterns, base=''):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.contrib.gis import forms
|
from django.contrib.gis import forms
|
||||||
# Getting the SpatialBackend container and the geographic quoting method.
|
# Getting the SpatialBackend container and the geographic quoting method.
|
||||||
from django.contrib.gis.db.backend import SpatialBackend, gqn
|
from django.contrib.gis.db.backend import SpatialBackend, gqn
|
||||||
|
@ -30,7 +31,7 @@ def get_srid_info(srid):
|
||||||
return _srid_cache[srid]
|
return _srid_cache[srid]
|
||||||
|
|
||||||
class GeometryField(SpatialBackend.Field):
|
class GeometryField(SpatialBackend.Field):
|
||||||
"""The base GIS field -- maps to the OpenGIS Specification Geometry type."""
|
"The base GIS field -- maps to the OpenGIS Specification Geometry type."
|
||||||
|
|
||||||
# The OpenGIS Geometry name.
|
# The OpenGIS Geometry name.
|
||||||
geom_type = 'GEOMETRY'
|
geom_type = 'GEOMETRY'
|
||||||
|
@ -38,6 +39,8 @@ class GeometryField(SpatialBackend.Field):
|
||||||
# Geodetic units.
|
# Geodetic units.
|
||||||
geodetic_units = ('Decimal Degree', 'degree')
|
geodetic_units = ('Decimal Degree', 'degree')
|
||||||
|
|
||||||
|
description = _("The base GIS field -- maps to the OpenGIS Specification Geometry type.")
|
||||||
|
|
||||||
def __init__(self, verbose_name=None, srid=4326, spatial_index=True, dim=2, **kwargs):
|
def __init__(self, verbose_name=None, srid=4326, spatial_index=True, dim=2, **kwargs):
|
||||||
"""
|
"""
|
||||||
The initialization function for geometry fields. Takes the following
|
The initialization function for geometry fields. Takes the following
|
||||||
|
@ -257,29 +260,29 @@ class GeometryField(SpatialBackend.Field):
|
||||||
|
|
||||||
# The OpenGIS Geometry Type Fields
|
# The OpenGIS Geometry Type Fields
|
||||||
class PointField(GeometryField):
|
class PointField(GeometryField):
|
||||||
"""Point"""
|
|
||||||
geom_type = 'POINT'
|
geom_type = 'POINT'
|
||||||
|
description = _("Point")
|
||||||
|
|
||||||
class LineStringField(GeometryField):
|
class LineStringField(GeometryField):
|
||||||
"""Line string"""
|
|
||||||
geom_type = 'LINESTRING'
|
geom_type = 'LINESTRING'
|
||||||
|
description = _("Line string")
|
||||||
|
|
||||||
class PolygonField(GeometryField):
|
class PolygonField(GeometryField):
|
||||||
"""Polygon"""
|
|
||||||
geom_type = 'POLYGON'
|
geom_type = 'POLYGON'
|
||||||
|
description = _("Polygon")
|
||||||
|
|
||||||
class MultiPointField(GeometryField):
|
class MultiPointField(GeometryField):
|
||||||
"""Multi-point"""
|
|
||||||
geom_type = 'MULTIPOINT'
|
geom_type = 'MULTIPOINT'
|
||||||
|
description = _("Multi-point")
|
||||||
|
|
||||||
class MultiLineStringField(GeometryField):
|
class MultiLineStringField(GeometryField):
|
||||||
"""Multi-line string"""
|
|
||||||
geom_type = 'MULTILINESTRING'
|
geom_type = 'MULTILINESTRING'
|
||||||
|
description = _("Multi-line string")
|
||||||
|
|
||||||
class MultiPolygonField(GeometryField):
|
class MultiPolygonField(GeometryField):
|
||||||
"""Multi polygon"""
|
|
||||||
geom_type = 'MULTIPOLYGON'
|
geom_type = 'MULTIPOLYGON'
|
||||||
|
description = _("Multi polygon")
|
||||||
|
|
||||||
class GeometryCollectionField(GeometryField):
|
class GeometryCollectionField(GeometryField):
|
||||||
"""Geometry collection"""
|
|
||||||
geom_type = 'GEOMETRYCOLLECTION'
|
geom_type = 'GEOMETRYCOLLECTION'
|
||||||
|
description = _("Geometry collection")
|
||||||
|
|
|
@ -1,16 +1,21 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.db.models.fields import Field, CharField
|
from django.db.models.fields import Field, CharField
|
||||||
from django.contrib.localflavor.us.us_states import STATE_CHOICES
|
from django.contrib.localflavor.us.us_states import STATE_CHOICES
|
||||||
|
|
||||||
class USStateField(CharField):
|
class USStateField(CharField):
|
||||||
"""U.S. state (two uppercase letters)"""
|
|
||||||
|
description = _("U.S. state (two uppercase letters)")
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs['choices'] = STATE_CHOICES
|
kwargs['choices'] = STATE_CHOICES
|
||||||
kwargs['max_length'] = 2
|
kwargs['max_length'] = 2
|
||||||
super(USStateField, self).__init__(*args, **kwargs)
|
super(USStateField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
class PhoneNumberField(Field):
|
class PhoneNumberField(Field):
|
||||||
"""Phone number"""
|
|
||||||
|
description = _("Phone number")
|
||||||
|
|
||||||
def get_internal_type(self):
|
def get_internal_type(self):
|
||||||
return "PhoneNumberField"
|
return "PhoneNumberField"
|
||||||
|
|
||||||
|
|
|
@ -49,8 +49,6 @@ class FieldDoesNotExist(Exception):
|
||||||
# getattr(obj, opts.pk.attname)
|
# getattr(obj, opts.pk.attname)
|
||||||
|
|
||||||
class Field(object):
|
class Field(object):
|
||||||
"""Base class for all field types"""
|
|
||||||
|
|
||||||
# Designates whether empty strings fundamentally are allowed at the
|
# Designates whether empty strings fundamentally are allowed at the
|
||||||
# database level.
|
# database level.
|
||||||
empty_strings_allowed = True
|
empty_strings_allowed = True
|
||||||
|
@ -61,6 +59,13 @@ class Field(object):
|
||||||
creation_counter = 0
|
creation_counter = 0
|
||||||
auto_creation_counter = -1
|
auto_creation_counter = -1
|
||||||
|
|
||||||
|
# Generic field type description, usually overriden by subclasses
|
||||||
|
def _description(self):
|
||||||
|
return _(u'Field of type: %(field_type)s') % {
|
||||||
|
'field_type': self.__class__.__name__
|
||||||
|
}
|
||||||
|
description = property(_description)
|
||||||
|
|
||||||
def __init__(self, verbose_name=None, name=None, primary_key=False,
|
def __init__(self, verbose_name=None, name=None, primary_key=False,
|
||||||
max_length=None, unique=False, blank=False, null=False,
|
max_length=None, unique=False, blank=False, null=False,
|
||||||
db_index=False, rel=None, default=NOT_PROVIDED, editable=True,
|
db_index=False, rel=None, default=NOT_PROVIDED, editable=True,
|
||||||
|
@ -342,10 +347,8 @@ class Field(object):
|
||||||
return getattr(obj, self.attname)
|
return getattr(obj, self.attname)
|
||||||
|
|
||||||
class AutoField(Field):
|
class AutoField(Field):
|
||||||
"""Integer"""
|
description = ugettext_lazy("Integer")
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
assert kwargs.get('primary_key', False) is True, "%ss must have primary_key=True." % self.__class__.__name__
|
assert kwargs.get('primary_key', False) is True, "%ss must have primary_key=True." % self.__class__.__name__
|
||||||
kwargs['blank'] = True
|
kwargs['blank'] = True
|
||||||
|
@ -375,10 +378,8 @@ class AutoField(Field):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
class BooleanField(Field):
|
class BooleanField(Field):
|
||||||
"""Boolean (Either True or False)"""
|
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
description = ugettext_lazy("Boolean (Either True or False)")
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs['blank'] = True
|
kwargs['blank'] = True
|
||||||
if 'default' not in kwargs and not kwargs.get('null'):
|
if 'default' not in kwargs and not kwargs.get('null'):
|
||||||
|
@ -421,8 +422,7 @@ class BooleanField(Field):
|
||||||
return super(BooleanField, self).formfield(**defaults)
|
return super(BooleanField, self).formfield(**defaults)
|
||||||
|
|
||||||
class CharField(Field):
|
class CharField(Field):
|
||||||
"""String (up to %(max_length)s)"""
|
description = ugettext_lazy("String (up to %(max_length)s)")
|
||||||
|
|
||||||
def get_internal_type(self):
|
def get_internal_type(self):
|
||||||
return "CharField"
|
return "CharField"
|
||||||
|
|
||||||
|
@ -444,8 +444,7 @@ class CharField(Field):
|
||||||
|
|
||||||
# TODO: Maybe move this into contrib, because it's specialized.
|
# TODO: Maybe move this into contrib, because it's specialized.
|
||||||
class CommaSeparatedIntegerField(CharField):
|
class CommaSeparatedIntegerField(CharField):
|
||||||
"""Comma-separated integers"""
|
description = ugettext_lazy("Comma-separated integers")
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
def formfield(self, **kwargs):
|
||||||
defaults = {
|
defaults = {
|
||||||
'form_class': forms.RegexField,
|
'form_class': forms.RegexField,
|
||||||
|
@ -461,10 +460,8 @@ class CommaSeparatedIntegerField(CharField):
|
||||||
ansi_date_re = re.compile(r'^\d{4}-\d{1,2}-\d{1,2}$')
|
ansi_date_re = re.compile(r'^\d{4}-\d{1,2}-\d{1,2}$')
|
||||||
|
|
||||||
class DateField(Field):
|
class DateField(Field):
|
||||||
"""Date (without time)"""
|
description = ugettext_lazy("Date (without time)")
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
|
||||||
def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs):
|
def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs):
|
||||||
self.auto_now, self.auto_now_add = auto_now, auto_now_add
|
self.auto_now, self.auto_now_add = auto_now, auto_now_add
|
||||||
#HACKs : auto_now_add/auto_now should be done as a default or a pre_save.
|
#HACKs : auto_now_add/auto_now should be done as a default or a pre_save.
|
||||||
|
@ -539,8 +536,7 @@ class DateField(Field):
|
||||||
return super(DateField, self).formfield(**defaults)
|
return super(DateField, self).formfield(**defaults)
|
||||||
|
|
||||||
class DateTimeField(DateField):
|
class DateTimeField(DateField):
|
||||||
"""Date (with time)"""
|
description = ugettext_lazy("Date (with time)")
|
||||||
|
|
||||||
def get_internal_type(self):
|
def get_internal_type(self):
|
||||||
return "DateTimeField"
|
return "DateTimeField"
|
||||||
|
|
||||||
|
@ -600,10 +596,8 @@ class DateTimeField(DateField):
|
||||||
return super(DateTimeField, self).formfield(**defaults)
|
return super(DateTimeField, self).formfield(**defaults)
|
||||||
|
|
||||||
class DecimalField(Field):
|
class DecimalField(Field):
|
||||||
"""Decimal number"""
|
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
description = ugettext_lazy("Decimal number")
|
||||||
def __init__(self, verbose_name=None, name=None, max_digits=None, decimal_places=None, **kwargs):
|
def __init__(self, verbose_name=None, name=None, max_digits=None, decimal_places=None, **kwargs):
|
||||||
self.max_digits, self.decimal_places = max_digits, decimal_places
|
self.max_digits, self.decimal_places = max_digits, decimal_places
|
||||||
Field.__init__(self, verbose_name, name, **kwargs)
|
Field.__init__(self, verbose_name, name, **kwargs)
|
||||||
|
@ -657,8 +651,7 @@ class DecimalField(Field):
|
||||||
return super(DecimalField, self).formfield(**defaults)
|
return super(DecimalField, self).formfield(**defaults)
|
||||||
|
|
||||||
class EmailField(CharField):
|
class EmailField(CharField):
|
||||||
"""E-mail address"""
|
description = ugettext_lazy("E-mail address")
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs['max_length'] = kwargs.get('max_length', 75)
|
kwargs['max_length'] = kwargs.get('max_length', 75)
|
||||||
CharField.__init__(self, *args, **kwargs)
|
CharField.__init__(self, *args, **kwargs)
|
||||||
|
@ -669,8 +662,7 @@ class EmailField(CharField):
|
||||||
return super(EmailField, self).formfield(**defaults)
|
return super(EmailField, self).formfield(**defaults)
|
||||||
|
|
||||||
class FilePathField(Field):
|
class FilePathField(Field):
|
||||||
"""File path"""
|
description = ugettext_lazy("File path")
|
||||||
|
|
||||||
def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
|
def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
|
||||||
self.path, self.match, self.recursive = path, match, recursive
|
self.path, self.match, self.recursive = path, match, recursive
|
||||||
kwargs['max_length'] = kwargs.get('max_length', 100)
|
kwargs['max_length'] = kwargs.get('max_length', 100)
|
||||||
|
@ -690,9 +682,8 @@ class FilePathField(Field):
|
||||||
return "FilePathField"
|
return "FilePathField"
|
||||||
|
|
||||||
class FloatField(Field):
|
class FloatField(Field):
|
||||||
"""Floating point number"""
|
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
description = ugettext_lazy("Floating point number")
|
||||||
|
|
||||||
def get_db_prep_value(self, value):
|
def get_db_prep_value(self, value):
|
||||||
if value is None:
|
if value is None:
|
||||||
|
@ -717,10 +708,8 @@ class FloatField(Field):
|
||||||
return super(FloatField, self).formfield(**defaults)
|
return super(FloatField, self).formfield(**defaults)
|
||||||
|
|
||||||
class IntegerField(Field):
|
class IntegerField(Field):
|
||||||
"""Integer"""
|
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
description = ugettext_lazy("Integer")
|
||||||
def get_db_prep_value(self, value):
|
def get_db_prep_value(self, value):
|
||||||
if value is None:
|
if value is None:
|
||||||
return None
|
return None
|
||||||
|
@ -744,10 +733,8 @@ class IntegerField(Field):
|
||||||
return super(IntegerField, self).formfield(**defaults)
|
return super(IntegerField, self).formfield(**defaults)
|
||||||
|
|
||||||
class IPAddressField(Field):
|
class IPAddressField(Field):
|
||||||
"""IP address"""
|
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
description = ugettext_lazy("IP address")
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs['max_length'] = 15
|
kwargs['max_length'] = 15
|
||||||
Field.__init__(self, *args, **kwargs)
|
Field.__init__(self, *args, **kwargs)
|
||||||
|
@ -761,10 +748,8 @@ class IPAddressField(Field):
|
||||||
return super(IPAddressField, self).formfield(**defaults)
|
return super(IPAddressField, self).formfield(**defaults)
|
||||||
|
|
||||||
class NullBooleanField(Field):
|
class NullBooleanField(Field):
|
||||||
"""Boolean (Either True, False or None)"""
|
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
description = ugettext_lazy("Boolean (Either True, False or None)")
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs['null'] = True
|
kwargs['null'] = True
|
||||||
Field.__init__(self, *args, **kwargs)
|
Field.__init__(self, *args, **kwargs)
|
||||||
|
@ -804,8 +789,7 @@ class NullBooleanField(Field):
|
||||||
return super(NullBooleanField, self).formfield(**defaults)
|
return super(NullBooleanField, self).formfield(**defaults)
|
||||||
|
|
||||||
class PositiveIntegerField(IntegerField):
|
class PositiveIntegerField(IntegerField):
|
||||||
"""Integer"""
|
description = ugettext_lazy("Integer")
|
||||||
|
|
||||||
def get_internal_type(self):
|
def get_internal_type(self):
|
||||||
return "PositiveIntegerField"
|
return "PositiveIntegerField"
|
||||||
|
|
||||||
|
@ -815,8 +799,7 @@ class PositiveIntegerField(IntegerField):
|
||||||
return super(PositiveIntegerField, self).formfield(**defaults)
|
return super(PositiveIntegerField, self).formfield(**defaults)
|
||||||
|
|
||||||
class PositiveSmallIntegerField(IntegerField):
|
class PositiveSmallIntegerField(IntegerField):
|
||||||
"""Integer"""
|
description = ugettext_lazy("Integer")
|
||||||
|
|
||||||
def get_internal_type(self):
|
def get_internal_type(self):
|
||||||
return "PositiveSmallIntegerField"
|
return "PositiveSmallIntegerField"
|
||||||
|
|
||||||
|
@ -826,8 +809,7 @@ class PositiveSmallIntegerField(IntegerField):
|
||||||
return super(PositiveSmallIntegerField, self).formfield(**defaults)
|
return super(PositiveSmallIntegerField, self).formfield(**defaults)
|
||||||
|
|
||||||
class SlugField(CharField):
|
class SlugField(CharField):
|
||||||
"""String (up to %(max_length)s)"""
|
description = ugettext_lazy("String (up to %(max_length)s)")
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs['max_length'] = kwargs.get('max_length', 50)
|
kwargs['max_length'] = kwargs.get('max_length', 50)
|
||||||
# Set db_index=True unless it's been set manually.
|
# Set db_index=True unless it's been set manually.
|
||||||
|
@ -844,14 +826,12 @@ class SlugField(CharField):
|
||||||
return super(SlugField, self).formfield(**defaults)
|
return super(SlugField, self).formfield(**defaults)
|
||||||
|
|
||||||
class SmallIntegerField(IntegerField):
|
class SmallIntegerField(IntegerField):
|
||||||
"""Integer"""
|
description = ugettext_lazy("Integer")
|
||||||
|
|
||||||
def get_internal_type(self):
|
def get_internal_type(self):
|
||||||
return "SmallIntegerField"
|
return "SmallIntegerField"
|
||||||
|
|
||||||
class TextField(Field):
|
class TextField(Field):
|
||||||
"""Text"""
|
description = ugettext_lazy("Text")
|
||||||
|
|
||||||
def get_internal_type(self):
|
def get_internal_type(self):
|
||||||
return "TextField"
|
return "TextField"
|
||||||
|
|
||||||
|
@ -861,10 +841,8 @@ class TextField(Field):
|
||||||
return super(TextField, self).formfield(**defaults)
|
return super(TextField, self).formfield(**defaults)
|
||||||
|
|
||||||
class TimeField(Field):
|
class TimeField(Field):
|
||||||
"""Time"""
|
description = ugettext_lazy("Time")
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
|
||||||
def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs):
|
def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs):
|
||||||
self.auto_now, self.auto_now_add = auto_now, auto_now_add
|
self.auto_now, self.auto_now_add = auto_now, auto_now_add
|
||||||
if auto_now or auto_now_add:
|
if auto_now or auto_now_add:
|
||||||
|
@ -936,8 +914,7 @@ class TimeField(Field):
|
||||||
return super(TimeField, self).formfield(**defaults)
|
return super(TimeField, self).formfield(**defaults)
|
||||||
|
|
||||||
class URLField(CharField):
|
class URLField(CharField):
|
||||||
"""URL"""
|
description = ugettext_lazy("URL")
|
||||||
|
|
||||||
def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs):
|
def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs):
|
||||||
kwargs['max_length'] = kwargs.get('max_length', 200)
|
kwargs['max_length'] = kwargs.get('max_length', 200)
|
||||||
self.verify_exists = verify_exists
|
self.verify_exists = verify_exists
|
||||||
|
@ -949,8 +926,7 @@ class URLField(CharField):
|
||||||
return super(URLField, self).formfield(**defaults)
|
return super(URLField, self).formfield(**defaults)
|
||||||
|
|
||||||
class XMLField(TextField):
|
class XMLField(TextField):
|
||||||
"""XML text"""
|
description = ugettext_lazy("XML text")
|
||||||
|
|
||||||
def __init__(self, verbose_name=None, name=None, schema_path=None, **kwargs):
|
def __init__(self, verbose_name=None, name=None, schema_path=None, **kwargs):
|
||||||
self.schema_path = schema_path
|
self.schema_path = schema_path
|
||||||
Field.__init__(self, verbose_name, name, **kwargs)
|
Field.__init__(self, verbose_name, name, **kwargs)
|
||||||
|
|
|
@ -209,8 +209,6 @@ class FileDescriptor(object):
|
||||||
instance.__dict__[self.field.name] = value
|
instance.__dict__[self.field.name] = value
|
||||||
|
|
||||||
class FileField(Field):
|
class FileField(Field):
|
||||||
"""File path"""
|
|
||||||
|
|
||||||
# The class to wrap instance attributes in. Accessing the file object off
|
# The class to wrap instance attributes in. Accessing the file object off
|
||||||
# the instance will always return an instance of attr_class.
|
# the instance will always return an instance of attr_class.
|
||||||
attr_class = FieldFile
|
attr_class = FieldFile
|
||||||
|
@ -218,6 +216,8 @@ class FileField(Field):
|
||||||
# The descriptor to use for accessing the attribute off of the class.
|
# The descriptor to use for accessing the attribute off of the class.
|
||||||
descriptor_class = FileDescriptor
|
descriptor_class = FileDescriptor
|
||||||
|
|
||||||
|
description = ugettext_lazy("File path")
|
||||||
|
|
||||||
def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, **kwargs):
|
def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, **kwargs):
|
||||||
for arg in ('primary_key', 'unique'):
|
for arg in ('primary_key', 'unique'):
|
||||||
if arg in kwargs:
|
if arg in kwargs:
|
||||||
|
@ -325,10 +325,9 @@ class ImageFieldFile(ImageFile, FieldFile):
|
||||||
super(ImageFieldFile, self).delete(save)
|
super(ImageFieldFile, self).delete(save)
|
||||||
|
|
||||||
class ImageField(FileField):
|
class ImageField(FileField):
|
||||||
"""File path"""
|
|
||||||
|
|
||||||
attr_class = ImageFieldFile
|
attr_class = ImageFieldFile
|
||||||
descriptor_class = ImageFileDescriptor
|
descriptor_class = ImageFileDescriptor
|
||||||
|
description = ugettext_lazy("File path")
|
||||||
|
|
||||||
def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs):
|
def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs):
|
||||||
self.width_field, self.height_field = width_field, height_field
|
self.width_field, self.height_field = width_field, height_field
|
||||||
|
|
|
@ -691,9 +691,8 @@ class ManyToManyRel(object):
|
||||||
return self.to._meta.pk
|
return self.to._meta.pk
|
||||||
|
|
||||||
class ForeignKey(RelatedField, Field):
|
class ForeignKey(RelatedField, Field):
|
||||||
"""Foreign Key (type determined by related field)"""
|
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
description = ugettext_lazy("Foreign Key (type determined by related field)")
|
||||||
def __init__(self, to, to_field=None, rel_class=ManyToOneRel, **kwargs):
|
def __init__(self, to, to_field=None, rel_class=ManyToOneRel, **kwargs):
|
||||||
try:
|
try:
|
||||||
to_name = to._meta.object_name.lower()
|
to_name = to._meta.object_name.lower()
|
||||||
|
@ -790,13 +789,13 @@ class ForeignKey(RelatedField, Field):
|
||||||
return rel_field.db_type()
|
return rel_field.db_type()
|
||||||
|
|
||||||
class OneToOneField(ForeignKey):
|
class OneToOneField(ForeignKey):
|
||||||
"""One-to-one relationship
|
"""
|
||||||
|
|
||||||
A OneToOneField is essentially the same as a ForeignKey, with the exception
|
A OneToOneField is essentially the same as a ForeignKey, with the exception
|
||||||
that always carries a "unique" constraint with it and the reverse relation
|
that always carries a "unique" constraint with it and the reverse relation
|
||||||
always returns the object pointed to (since there will only ever be one),
|
always returns the object pointed to (since there will only ever be one),
|
||||||
rather than returning a list."""
|
rather than returning a list.
|
||||||
|
"""
|
||||||
|
description = ugettext_lazy("One-to-one relationship")
|
||||||
def __init__(self, to, to_field=None, **kwargs):
|
def __init__(self, to, to_field=None, **kwargs):
|
||||||
kwargs['unique'] = True
|
kwargs['unique'] = True
|
||||||
super(OneToOneField, self).__init__(to, to_field, OneToOneRel, **kwargs)
|
super(OneToOneField, self).__init__(to, to_field, OneToOneRel, **kwargs)
|
||||||
|
@ -850,8 +849,7 @@ def create_many_to_many_intermediary_model(field, klass):
|
||||||
})
|
})
|
||||||
|
|
||||||
class ManyToManyField(RelatedField, Field):
|
class ManyToManyField(RelatedField, Field):
|
||||||
"""Many-to-many relationship"""
|
description = ugettext_lazy("Many-to-many relationship")
|
||||||
|
|
||||||
def __init__(self, to, **kwargs):
|
def __init__(self, to, **kwargs):
|
||||||
try:
|
try:
|
||||||
assert not to._meta.abstract, "%s cannot define a relation with abstract class %s" % (self.__class__.__name__, to._meta.object_name)
|
assert not to._meta.abstract, "%s cannot define a relation with abstract class %s" % (self.__class__.__name__, to._meta.object_name)
|
||||||
|
|
|
@ -5,6 +5,7 @@ Writing custom model fields
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
.. versionadded:: 1.0
|
.. versionadded:: 1.0
|
||||||
|
.. currentmodule:: django.db.models
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
============
|
============
|
||||||
|
@ -165,7 +166,8 @@ behave like any existing field, so we'll subclass directly from
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
class HandField(models.Field):
|
class HandField(models.Field):
|
||||||
"""A hand of cards (bridge style)"""
|
|
||||||
|
description = "A hand of cards (bridge style)"
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs['max_length'] = 104
|
kwargs['max_length'] = 104
|
||||||
|
@ -248,7 +250,8 @@ simple: make sure your field subclass uses a special metaclass:
|
||||||
For example::
|
For example::
|
||||||
|
|
||||||
class HandField(models.Field):
|
class HandField(models.Field):
|
||||||
"""A hand of cards (bridge style)"""
|
|
||||||
|
description = "A hand of cards (bridge style)"
|
||||||
|
|
||||||
__metaclass__ = models.SubfieldBase
|
__metaclass__ = models.SubfieldBase
|
||||||
|
|
||||||
|
@ -262,16 +265,17 @@ called when the attribute is initialized.
|
||||||
Documenting your Custom Field
|
Documenting your Custom Field
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
|
.. class:: django.db.models.Field
|
||||||
|
|
||||||
|
.. attribute:: description
|
||||||
|
|
||||||
As always, you should document your field type, so users will know what it is.
|
As always, you should document your field type, so users will know what it is.
|
||||||
The best way to do this is to simply provide a docstring for it. This will
|
In addition to providing a docstring for it, which is useful for developers,
|
||||||
automatically be picked up by ``django.contrib.admindocs``, if you have it
|
you can also allow users of the admin app to see a short description of the
|
||||||
installed, and the first line of it will show up as the field type in the
|
field type via the ``django.contrib.admindocs`` application. To do this simply
|
||||||
documentation for any model that uses your field. In the above examples, it
|
provide descriptive text in a ``description`` class attribute of your custom field.
|
||||||
will show up as 'A hand of cards (bridge style)'. Note that if you provide a
|
In the above example, the type description displayed by the ``admindocs`` application
|
||||||
more verbose docstring, only the first line will show up in
|
for a ``HandField`` will be 'A hand of cards (bridge style)'.
|
||||||
``django.contrib.admindocs``. The full docstring will, of course, still be
|
|
||||||
available through ``pydoc`` or the interactive interpreter's ``help()``
|
|
||||||
function.
|
|
||||||
|
|
||||||
Useful methods
|
Useful methods
|
||||||
--------------
|
--------------
|
||||||
|
|
Loading…
Reference in New Issue