Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

__init__.py 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import six
  2. from django.core.exceptions import ImproperlyConfigured
  3. from django.db.models.fields import CharField, DecimalField, Field
  4. from django.db.models import SubfieldBase
  5. from django.utils import six as django_six
  6. from django.utils.translation import ugettext_lazy as _
  7. from django.core.validators import MaxLengthValidator
  8. from oscar.core import validators
  9. from oscar.forms import fields
  10. import oscar.core.phonenumber as phonenumber
  11. # allow importing as oscar.models.fields.AutoSlugField
  12. from .autoslugfield import AutoSlugField
  13. AutoSlugField = AutoSlugField
  14. try:
  15. from south.modelsinspector import add_introspection_rules
  16. except ImportError:
  17. pass
  18. else:
  19. add_introspection_rules([], ["^oscar\.models\.fields\.ExtendedURLField$"])
  20. add_introspection_rules([], [
  21. "^oscar\.models\.fields\.PositiveDecimalField$"])
  22. add_introspection_rules([], [
  23. "^oscar\.models\.fields\.UppercaseCharField$"])
  24. add_introspection_rules([], [
  25. "^oscar\.models\.fields\.NullCharField$"])
  26. add_introspection_rules([], [
  27. "^oscar\.models\.fields\.PhoneNumberField$"])
  28. add_introspection_rules([], [
  29. "^oscar\.models\.fields\.AutoSlugField$"])
  30. class ExtendedURLField(CharField):
  31. description = _("URL")
  32. def __init__(self, verbose_name=None, name=None,
  33. verify_exists=None, **kwargs):
  34. kwargs['max_length'] = kwargs.get('max_length', 200)
  35. CharField.__init__(self, verbose_name, name, **kwargs)
  36. # 'verify_exists' was deprecated in Django 1.4. To ensure backwards
  37. # compatibility, it is still accepted here, but only passed
  38. # on to the parent class if it was specified.
  39. self.verify_exists = verify_exists
  40. if verify_exists is not None:
  41. validator = validators.ExtendedURLValidator(
  42. verify_exists=verify_exists)
  43. else:
  44. validator = validators.ExtendedURLValidator()
  45. self.validators.append(validator)
  46. def formfield(self, **kwargs):
  47. # As with CharField, this will cause URL validation to be performed
  48. # twice.
  49. defaults = {
  50. 'form_class': fields.ExtendedURLField,
  51. 'verify_exists': self.verify_exists
  52. }
  53. defaults.update(kwargs)
  54. return super(ExtendedURLField, self).formfield(**defaults)
  55. class PositiveDecimalField(DecimalField):
  56. """
  57. A simple subclass of ``django.db.models.fields.DecimalField`` that
  58. restricts values to be non-negative.
  59. """
  60. def formfield(self, **kwargs):
  61. return super(PositiveDecimalField, self).formfield(min_value=0)
  62. class UppercaseCharField(django_six.with_metaclass(SubfieldBase, CharField)):
  63. """
  64. A simple subclass of ``django.db.models.fields.CharField`` that
  65. restricts all text to be uppercase.
  66. Defined with the with_metaclass helper so that to_python is called
  67. https://docs.djangoproject.com/en/1.6/howto/custom-model-fields/#the-subfieldbase-metaclass # NOQA
  68. """
  69. def to_python(self, value):
  70. val = super(UppercaseCharField, self).to_python(value)
  71. if isinstance(val, six.string_types):
  72. return val.upper()
  73. else:
  74. return val
  75. class NullCharField(django_six.with_metaclass(SubfieldBase, CharField)):
  76. """
  77. CharField that stores '' as None and returns None as ''
  78. Useful when using unique=True and forms. Implies null==blank==True.
  79. When a ModelForm with a CharField with null=True gets saved, the field will
  80. be set to '': https://code.djangoproject.com/ticket/9590
  81. This breaks usage with unique=True, as '' is considered equal to another
  82. field set to ''.
  83. """
  84. description = "CharField that stores '' as None and returns None as ''"
  85. def __init__(self, *args, **kwargs):
  86. if not kwargs.get('null', True) or not kwargs.get('blank', True):
  87. raise ImproperlyConfigured(
  88. "NullCharField implies null==blank==True")
  89. kwargs['null'] = kwargs['blank'] = True
  90. super(NullCharField, self).__init__(*args, **kwargs)
  91. def to_python(self, value):
  92. val = super(NullCharField, self).to_python(value)
  93. return val if val is not None else u''
  94. def get_prep_value(self, value):
  95. prepped = super(NullCharField, self).get_prep_value(value)
  96. return prepped if prepped != u"" else None
  97. class PhoneNumberField(Field):
  98. """
  99. An international phone number.
  100. * Validates a wide range of phone number formats
  101. * Displays it nicely formatted
  102. * Can be given a hint for the country, so that it can accept local numbers,
  103. that are not in an international format
  104. Notes
  105. -----
  106. This field is based on work in django-phonenumber-field
  107. https://github.com/maikhoepfel/django-phonenumber-field/
  108. See ``oscar/core/phonenumber.py`` for the relevant copyright and
  109. permission notice.
  110. """
  111. attr_class = phonenumber.PhoneNumber
  112. descriptor_class = phonenumber.PhoneNumberDescriptor
  113. default_validators = [phonenumber.validate_international_phonenumber]
  114. description = _("Phone number")
  115. def __init__(self, *args, **kwargs):
  116. if kwargs.get('null', False):
  117. raise ImproperlyConfigured(
  118. "null=True is not supported on PhoneNumberField")
  119. kwargs['max_length'] = kwargs.get('max_length', 128)
  120. super(PhoneNumberField, self).__init__(*args, **kwargs)
  121. self.validators.append(MaxLengthValidator(self.max_length))
  122. def get_internal_type(self):
  123. return "CharField"
  124. def get_prep_value(self, value):
  125. """
  126. Returns field's value prepared for saving into a database.
  127. """
  128. value = phonenumber.to_python(value)
  129. if value is None:
  130. return u''
  131. return value.as_e164 if value.is_valid() else value.raw_input
  132. def contribute_to_class(self, cls, name):
  133. super(PhoneNumberField, self).contribute_to_class(cls, name)
  134. setattr(cls, self.name, self.descriptor_class(self))