예제 #1
0
파일: models.py 프로젝트: iMerica/dj-models
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)
예제 #2
0
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,
        })
예제 #3
0
 class Model(models.Model):
     field = models.CharField(
         max_length=10,
         choices=[
             [
                 _('knights'),
                 [['L', _('Lancelot')], ['G', _('Galahad')]]
             ],
             ['R', _('Random character')],
         ],
     )
예제 #4
0
 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())
예제 #5
0
    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')
예제 #6
0
파일: apps.py 프로젝트: iMerica/dj-models
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)
예제 #7
0
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)
예제 #8
0
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
예제 #9
0
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.'
    )
예제 #10
0
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)
예제 #11
0
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.'
    )
예제 #12
0
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
예제 #13
0
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]
예제 #14
0
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')
예제 #15
0
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)
예제 #16
0
파일: views.py 프로젝트: iMerica/dj-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)
예제 #17
0
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
예제 #18
0
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')
예제 #19
0
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)
예제 #20
0
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)
예제 #21
0
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))
예제 #22
0
파일: models.py 프로젝트: iMerica/dj-models
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)
예제 #23
0
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)
예제 #24
0
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])
    )
예제 #25
0
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)
예제 #26
0
class GISConfig(AppConfig):
    name = 'djmodels.contrib.gis'
    verbose_name = _("GIS")

    def ready(self):
        serializers.BUILTIN_SERIALIZERS.setdefault('geojson', 'djmodels.contrib.gis.serializers.geojson')
예제 #27
0
파일: dates.py 프로젝트: iMerica/dj-models
"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'),
예제 #28
0
파일: array.py 프로젝트: iMerica/dj-models
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,
            })
예제 #29
0
class TestModel(models.Model):
    text = models.CharField(max_length=10, default=_('Anything'))
예제 #30
0
 class Meta:
     verbose_name = _('Company')