class FlatPage(models.Model): url = models.CharField(_('URL'), max_length=100, db_index=True) title = models.CharField(_('title'), max_length=200) content = models.TextField(_('content'), blank=True) enable_comments = models.BooleanField(_('enable comments'), default=False) template_name = models.CharField( _('template name'), max_length=70, blank=True, help_text=_( "Example: 'flatpages/contact_page.html'. If this isn't provided, " "the system will use 'flatpages/default.html'."), ) registration_required = models.BooleanField( _('registration required'), help_text= _("If this is checked, only logged-in users will be able to view the page." ), default=False, ) sites = models.ManyToManyField(Site, verbose_name=_('sites')) class Meta: db_table = 'django_flatpage' verbose_name = _('flat page') verbose_name_plural = _('flat pages') ordering = ('url', ) def __str__(self): return "%s -- %s" % (self.url, self.title) def get_absolute_url(self): # Handle script prefix manually because we bypass reverse() return iri_to_uri(get_script_prefix().rstrip('/') + self.url)
class JSONField(CheckFieldDefaultMixin, Field): empty_strings_allowed = False description = _('A JSON object') default_error_messages = { 'invalid': _("Value must be valid JSON."), } _default_hint = ('dict', '{}') def __init__(self, verbose_name=None, name=None, encoder=None, **kwargs): if encoder and not callable(encoder): raise ValueError( "The encoder parameter must be a callable object.") self.encoder = encoder super().__init__(verbose_name, name, **kwargs) def db_type(self, connection): return 'jsonb' def deconstruct(self): name, path, args, kwargs = super().deconstruct() if self.encoder is not None: kwargs['encoder'] = self.encoder return name, path, args, kwargs def get_transform(self, name): transform = super().get_transform(name) if transform: return transform return KeyTransformFactory(name) def get_prep_value(self, value): if value is not None: return JsonAdapter(value, encoder=self.encoder) return value def validate(self, value, model_instance): super().validate(value, model_instance) options = {'cls': self.encoder} if self.encoder else {} try: json.dumps(value, **options) except TypeError: raise exceptions.ValidationError( self.error_messages['invalid'], code='invalid', params={'value': value}, ) def value_to_string(self, obj): return self.value_from_object(obj) def formfield(self, **kwargs): return super().formfield(**{ 'form_class': forms.JSONField, **kwargs, })
class Model(models.Model): field = models.CharField( max_length=10, choices=[ [ _('knights'), [['L', _('Lancelot')], ['G', _('Galahad')]] ], ['R', _('Random character')], ], )
def P(self): """ Time, in 12-hour hours, minutes and 'a.m.'/'p.m.', with minutes left off if they're zero and the strings 'midnight' and 'noon' if appropriate. Examples: '1 a.m.', '1:30 p.m.', 'midnight', 'noon', '12:30 p.m.' Proprietary extension. """ if self.data.minute == 0 and self.data.hour == 0: return _('midnight') if self.data.minute == 0 and self.data.hour == 12: return _('noon') return '%s %s' % (self.f(), self.a())
def test_naturalday(self): today = datetime.date.today() yesterday = today - datetime.timedelta(days=1) tomorrow = today + datetime.timedelta(days=1) someday = today - datetime.timedelta(days=10) notdate = "I'm not a date value" test_list = (today, yesterday, tomorrow, someday, notdate, None) someday_result = defaultfilters.date(someday) result_list = (_('today'), _('yesterday'), _('tomorrow'), someday_result, "I'm not a date value", None) self.humanize_tester(test_list, result_list, 'naturalday')
class PostgresConfig(AppConfig): name = 'djmodels.contrib.postgres' verbose_name = _('PostgreSQL extensions') def ready(self): # Connections may already exist before we are called. for conn in connections.all(): if conn.vendor == 'postgresql': conn.introspection.data_types_reverse.update({ 3802: 'djmodels.contrib.postgres.fields.JSONField', 3904: 'djmodels.contrib.postgres.fields.IntegerRangeField', 3906: 'djmodels.contrib.postgres.fields.FloatRangeField', 3910: 'djmodels.contrib.postgres.fields.DateTimeRangeField', 3912: 'djmodels.contrib.postgres.fields.DateRangeField', 3926: 'djmodels.contrib.postgres.fields.BigIntegerRangeField', }) if conn.connection is not None: register_type_handlers(conn) connection_created.connect(register_type_handlers) CharField.register_lookup(Unaccent) TextField.register_lookup(Unaccent) CharField.register_lookup(SearchLookup) TextField.register_lookup(SearchLookup) CharField.register_lookup(TrigramSimilar) TextField.register_lookup(TrigramSimilar)
def clean_ipv6_address(ip_str, unpack_ipv4=False, error_message=_("This is not a valid IPv6 address.")): """ Clean an IPv6 address string. Raise ValidationError if the address is invalid. Replace the longest continuous zero-sequence with "::", remove leading zeroes, and make sure all hextets are lowercase. Args: ip_str: A valid IPv6 address. unpack_ipv4: if an IPv4-mapped address is found, return the plain IPv4 address (default=False). error_message: An error message used in the ValidationError. Return a compressed IPv6 address or the same value. """ try: addr = ipaddress.IPv6Address(int(ipaddress.IPv6Address(ip_str))) except ValueError: raise ValidationError(error_message, code='invalid') if unpack_ipv4 and addr.ipv4_mapped: return str(addr.ipv4_mapped) elif addr.ipv4_mapped: return '::ffff:%s' % str(addr.ipv4_mapped) return str(addr)
class MinValueValidator(BaseValidator): message = _( 'Ensure this value is greater than or equal to %(limit_value)s.') code = 'min_value' def compare(self, a, b): return a < b
class RangeMaxValueValidator(MaxValueValidator): def compare(self, a, b): return a.upper is None or a.upper > b message = _( 'Ensure that this range is completely less than or equal to %(limit_value)s.' )
class FileExtensionValidator: message = _("File extension '%(extension)s' is not allowed. " "Allowed extensions are: '%(allowed_extensions)s'.") code = 'invalid_extension' def __init__(self, allowed_extensions=None, message=None, code=None): if allowed_extensions is not None: allowed_extensions = [ allowed_extension.lower() for allowed_extension in allowed_extensions ] self.allowed_extensions = allowed_extensions if message is not None: self.message = message if code is not None: self.code = code def __call__(self, value): extension = Path(value.name).suffix[1:].lower() if self.allowed_extensions is not None and extension not in self.allowed_extensions: raise ValidationError(self.message, code=self.code, params={ 'extension': extension, 'allowed_extensions': ', '.join(self.allowed_extensions) }) def __eq__(self, other): return (isinstance(other, self.__class__) and self.allowed_extensions == other.allowed_extensions and self.message == other.message and self.code == other.code)
class RangeMinValueValidator(MinValueValidator): def compare(self, a, b): return a.lower is None or a.lower < b message = _( 'Ensure that this range is completely greater than or equal to %(limit_value)s.' )
class BaseValidator: message = _('Ensure this value is %(limit_value)s (it is %(show_value)s).') code = 'limit_value' def __init__(self, limit_value, message=None): self.limit_value = limit_value if message: self.message = message def __call__(self, value): cleaned = self.clean(value) params = { 'limit_value': self.limit_value, 'show_value': cleaned, 'value': value } if self.compare(cleaned, self.limit_value): raise ValidationError(self.message, code=self.code, params=params) def __eq__(self, other): return (isinstance(other, self.__class__) and self.limit_value == other.limit_value and self.message == other.message and self.code == other.code) def compare(self, a, b): return a is not b def clean(self, x): return x
def apnumber(value): """ For numbers 1-9, return the number spelled out. Otherwise, return the number. This follows Associated Press style. """ try: value = int(value) except (TypeError, ValueError): return value if not 0 < value < 10: return value return (_('one'), _('two'), _('three'), _('four'), _('five'), _('six'), _('seven'), _('eight'), _('nine'))[value - 1]
def validate_ipv46_address(value): try: validate_ipv4_address(value) except ValidationError: try: validate_ipv6_address(value) except ValidationError: raise ValidationError(_('Enter a valid IPv4 or IPv6 address.'), code='invalid')
class ContentTypesConfig(AppConfig): name = 'djmodels.contrib.contenttypes' verbose_name = _("Content Types") def ready(self): pre_migrate.connect(inject_rename_contenttypes_operations, sender=self) post_migrate.connect(create_contenttypes) checks.register(check_generic_foreign_keys, checks.Tags.models) checks.register(check_model_name_lengths, checks.Tags.models)
def feed(request, url, feed_dict=None): """Provided for backwards compatibility.""" if not feed_dict: raise Http404(_("No feeds are registered.")) slug = url.partition('/')[0] try: f = feed_dict[slug] except KeyError: raise Http404(_("Slug %r isn't registered.") % slug) instance = f() instance.feed_url = getattr(f, 'feed_url', None) or request.path instance.title_template = f.title_template or ('feeds/%s_title.html' % slug) instance.description_template = f.description_template or ( 'feeds/%s_description.html' % slug) return instance(request)
class ExtentField(Field): "Used as a return value from an extent aggregate" description = _("Extent Aggregate Field") def get_internal_type(self): return "ExtentField" def select_format(self, compiler, sql, params): select = compiler.connection.ops.select_extent return select % sql if select else sql, params
class FlatPageAdmin(admin.ModelAdmin): form = FlatpageForm fieldsets = ( (None, { 'fields': ('url', 'title', 'content', 'sites') }), (_('Advanced options'), { 'classes': ('collapse', ), 'fields': ('registration_required', 'template_name'), }), ) list_display = ('url', 'title') list_filter = ('sites', 'registration_required') search_fields = ('url', 'title')
class KeysValidator: """A validator designed for HStore to require/restrict keys.""" messages = { 'missing_keys': _('Some keys were missing: %(keys)s'), 'extra_keys': _('Some unknown keys were provided: %(keys)s'), } strict = False def __init__(self, keys, strict=False, messages=None): self.keys = set(keys) self.strict = strict if messages is not None: self.messages = {**self.messages, **messages} def __call__(self, value): keys = set(value) missing_keys = self.keys - keys if missing_keys: raise ValidationError( self.messages['missing_keys'], code='missing_keys', params={'keys': ', '.join(missing_keys)}, ) if self.strict: extra_keys = keys - self.keys if extra_keys: raise ValidationError( self.messages['extra_keys'], code='extra_keys', params={'keys': ', '.join(extra_keys)}, ) def __eq__(self, other): return (isinstance(other, self.__class__) and self.keys == other.keys and self.messages == other.messages and self.strict == other.strict)
def naturalday(value, arg=None): """ For date values that are tomorrow, today or yesterday compared to present day return representing string. Otherwise, return a string formatted according to settings.DATE_FORMAT. """ try: tzinfo = getattr(value, 'tzinfo', None) value = date(value.year, value.month, value.day) except AttributeError: # Passed value wasn't a date object return value except ValueError: # Date arguments out of range return value today = datetime.now(tzinfo).date() delta = value - today if delta.days == 0: return _('today') elif delta.days == 1: return _('tomorrow') elif delta.days == -1: return _('yesterday') return defaultfilters.date(value, arg)
class RegexValidator: regex = '' message = _('Enter a valid value.') code = 'invalid' inverse_match = False flags = 0 def __init__(self, regex=None, message=None, code=None, inverse_match=None, flags=None): if regex is not None: self.regex = regex if message is not None: self.message = message if code is not None: self.code = code if inverse_match is not None: self.inverse_match = inverse_match if flags is not None: self.flags = flags if self.flags and not isinstance(self.regex, str): raise TypeError( "If the flags are set, regex must be a regular expression string." ) self.regex = _lazy_re_compile(self.regex, self.flags) def __call__(self, value): """ Validate that the input contains (or does *not* contain, if inverse_match is True) a match for the regular expression. """ regex_matches = self.regex.search(str(value)) invalid_input = regex_matches if self.inverse_match else not regex_matches if invalid_input: raise ValidationError(self.message, code=self.code) def __eq__(self, other): return (isinstance(other, RegexValidator) and self.regex.pattern == other.regex.pattern and self.regex.flags == other.regex.flags and (self.message == other.message) and (self.code == other.code) and (self.inverse_match == other.inverse_match))
class ContentType(models.Model): app_label = models.CharField(max_length=100) model = models.CharField(_('python model class name'), max_length=100) objects = ContentTypeManager() class Meta: verbose_name = _('content type') verbose_name_plural = _('content types') db_table = 'django_content_type' unique_together = (('app_label', 'model'), ) def __str__(self): return self.name @property def name(self): model = self.model_class() if not model: return self.model return str(model._meta.verbose_name) def model_class(self): """Return the model class for this type of content.""" try: return apps.get_model(self.app_label, self.model) except LookupError: return None def get_object_for_this_type(self, **kwargs): """ Return an object of this type for the keyword arguments given. Basically, this is a proxy around this object_type's get_object() model method. The ObjectNotExist exception, if thrown, will not be caught, so code that calls this method should catch it. """ return self.model_class()._base_manager.using( self._state.db).get(**kwargs) def get_all_objects_for_this_type(self, **kwargs): """ Return all objects of this type for the keyword arguments given. """ return self.model_class()._base_manager.using( self._state.db).filter(**kwargs) def natural_key(self): return (self.app_label, self.model)
class ProhibitNullCharactersValidator: """Validate that the string doesn't contain the null character.""" message = _('Null characters are not allowed.') code = 'null_characters_not_allowed' def __init__(self, message=None, code=None): if message is not None: self.message = message if code is not None: self.code = code def __call__(self, value): if '\x00' in str(value): raise ValidationError(self.message, code=self.code) def __eq__(self, other): return (isinstance(other, self.__class__) and self.message == other.message and self.code == other.code)
def get_text_list(list_, last_word=gettext_lazy('or')): """ >>> get_text_list(['a', 'b', 'c', 'd']) 'a, b, c or d' >>> get_text_list(['a', 'b', 'c'], 'and') 'a, b and c' >>> get_text_list(['a', 'b'], 'and') 'a and b' >>> get_text_list(['a']) 'a' >>> get_text_list([]) '' """ if not list_: return '' if len(list_) == 1: return str(list_[0]) return '%s %s %s' % ( # Translators: This string is used as a separator between list elements _(', ').join(str(i) for i in list_[:-1]), str(last_word), str(list_[-1]) )
class RasterField(BaseSpatialField): """ Raster field for GeoDjango -- evaluates into GDALRaster objects. """ description = _("Raster Field") geom_type = 'RASTER' geography = False def _check_connection(self, connection): # Make sure raster fields are used only on backends with raster support. if not connection.features.gis_enabled or not connection.features.supports_raster: raise ImproperlyConfigured( 'Raster fields require backends with raster support.') def db_type(self, connection): self._check_connection(connection) return super().db_type(connection) def from_db_value(self, value, expression, connection): return connection.ops.parse_raster(value) def contribute_to_class(self, cls, name, **kwargs): super().contribute_to_class(cls, name, **kwargs) # Setup for lazy-instantiated Raster object. For large querysets, the # instantiation of all GDALRasters can potentially be expensive. This # delays the instantiation of the objects to the moment of evaluation # of the raster attribute. setattr(cls, self.attname, SpatialProxy(gdal.GDALRaster, self)) def get_transform(self, name): from djmodels.contrib.gis.db.models.lookups import RasterBandTransform try: band_index = int(name) return type('SpecificRasterBandTransform', (RasterBandTransform, ), {'band_index': band_index}) except ValueError: pass return super().get_transform(name)
class GISConfig(AppConfig): name = 'djmodels.contrib.gis' verbose_name = _("GIS") def ready(self): serializers.BUILTIN_SERIALIZERS.setdefault('geojson', 'djmodels.contrib.gis.serializers.geojson')
"Commonly-used date structures" from djmodels.utils.translation import gettext_lazy as _, pgettext_lazy WEEKDAYS = { 0: _('Monday'), 1: _('Tuesday'), 2: _('Wednesday'), 3: _('Thursday'), 4: _('Friday'), 5: _('Saturday'), 6: _('Sunday') } WEEKDAYS_ABBR = { 0: _('Mon'), 1: _('Tue'), 2: _('Wed'), 3: _('Thu'), 4: _('Fri'), 5: _('Sat'), 6: _('Sun') } MONTHS = { 1: _('January'), 2: _('February'), 3: _('March'), 4: _('April'), 5: _('May'), 6: _('June'), 7: _('July'), 8: _('August'),
class ArrayField(CheckFieldDefaultMixin, Field): empty_strings_allowed = False default_error_messages = { 'item_invalid': _('Item %(nth)s in the array did not validate:'), 'nested_array_mismatch': _('Nested arrays must have the same length.'), } _default_hint = ('list', '[]') def __init__(self, base_field, size=None, **kwargs): self.base_field = base_field self.size = size if self.size: self.default_validators = self.default_validators[:] self.default_validators.append(ArrayMaxLengthValidator(self.size)) # For performance, only add a from_db_value() method if the base field # implements it. if hasattr(self.base_field, 'from_db_value'): self.from_db_value = self._from_db_value super().__init__(**kwargs) @property def model(self): try: return self.__dict__['model'] except KeyError: raise AttributeError("'%s' object has no attribute 'model'" % self.__class__.__name__) @model.setter def model(self, model): self.__dict__['model'] = model self.base_field.model = model def check(self, **kwargs): errors = super().check(**kwargs) if self.base_field.remote_field: errors.append( checks.Error('Base field for array cannot be a related field.', obj=self, id='postgres.E002')) else: # Remove the field name checks as they are not needed here. base_errors = self.base_field.check() if base_errors: messages = '\n '.join('%s (%s)' % (error.msg, error.id) for error in base_errors) errors.append( checks.Error('Base field for array has errors:\n %s' % messages, obj=self, id='postgres.E001')) return errors def set_attributes_from_name(self, name): super().set_attributes_from_name(name) self.base_field.set_attributes_from_name(name) @property def description(self): return 'Array of %s' % self.base_field.description def db_type(self, connection): size = self.size or '' return '%s[%s]' % (self.base_field.db_type(connection), size) def get_placeholder(self, value, compiler, connection): return '%s::{}'.format(self.db_type(connection)) def get_db_prep_value(self, value, connection, prepared=False): if isinstance(value, (list, tuple)): return [ self.base_field.get_db_prep_value(i, connection, prepared=False) for i in value ] return value def deconstruct(self): name, path, args, kwargs = super().deconstruct() if path == 'djmodels.contrib.postgres.fields.array.ArrayField': path = 'djmodels.contrib.postgres.fields.ArrayField' kwargs.update({ 'base_field': self.base_field.clone(), 'size': self.size, }) return name, path, args, kwargs def to_python(self, value): if isinstance(value, str): # Assume we're deserializing vals = json.loads(value) value = [self.base_field.to_python(val) for val in vals] return value def _from_db_value(self, value, expression, connection): if value is None: return value return [ self.base_field.from_db_value(item, expression, connection, {}) if func_supports_parameter(self.base_field.from_db_value, 'context') # RemovedInDjango30Warning else self.base_field.from_db_value(item, expression, connection) for item in value ] def value_to_string(self, obj): values = [] vals = self.value_from_object(obj) base_field = self.base_field for val in vals: if val is None: values.append(None) else: obj = AttributeSetter(base_field.attname, val) values.append(base_field.value_to_string(obj)) return json.dumps(values) def get_transform(self, name): transform = super().get_transform(name) if transform: return transform if '_' not in name: try: index = int(name) except ValueError: pass else: index += 1 # postgres uses 1-indexing return IndexTransformFactory(index, self.base_field) try: start, end = name.split('_') start = int(start) + 1 end = int( end) # don't add one here because postgres slices are weird except ValueError: pass else: return SliceTransformFactory(start, end) def validate(self, value, model_instance): super().validate(value, model_instance) for index, part in enumerate(value): try: self.base_field.validate(part, model_instance) except exceptions.ValidationError as error: raise prefix_validation_error( error, prefix=self.error_messages['item_invalid'], code='item_invalid', params={'nth': index + 1}, ) if isinstance(self.base_field, ArrayField): if len({len(i) for i in value}) > 1: raise exceptions.ValidationError( self.error_messages['nested_array_mismatch'], code='nested_array_mismatch', ) def run_validators(self, value): super().run_validators(value) for index, part in enumerate(value): try: self.base_field.run_validators(part) except exceptions.ValidationError as error: raise prefix_validation_error( error, prefix=self.error_messages['item_invalid'], code='item_invalid', params={'nth': index + 1}, ) def formfield(self, **kwargs): return super().formfield( **{ 'form_class': SimpleArrayField, 'base_field': self.base_field.formfield(), 'max_length': self.size, **kwargs, })
class TestModel(models.Model): text = models.CharField(max_length=10, default=_('Anything'))
class Meta: verbose_name = _('Company')