The DateTimeField
(documentation)
class in the django.forms
module in the Django
web framework provides a mechanism for safely handling
dates and times as input from HTTP POST requests. The requests are
usually generated by an HTML form
created from a Django web application.
django-filter (project documentation and PyPI page) makes it easier to filter down querysets from the Django ORM by providing common bits of boilerplate code. django-filter is provided as open source.
django-filter / django_filters / fields.py
from collections import namedtuple
from datetime import datetime, time
from django import forms
from django.utils.dateparse import parse_datetime
from django.utils.encoding import force_str
from django.utils.translation import gettext_lazy as _
from .conf import settings
from .constants import EMPTY_VALUES
from .utils import handle_timezone
from .widgets import (
BaseCSVWidget,
CSVWidget,
DateRangeWidget,
LookupChoiceWidget,
RangeWidget
)
class RangeField(forms.MultiValueField):
widget = RangeWidget
def __init__(self, fields=None, *args, **kwargs):
if fields is None:
fields = (
forms.DecimalField(),
forms.DecimalField())
super().__init__(fields, *args, **kwargs)
def compress(self, data_list):
if data_list:
return slice(*data_list)
return None
class DateRangeField(RangeField):
widget = DateRangeWidget
def __init__(self, *args, **kwargs):
fields = (
forms.DateField(),
forms.DateField())
super().__init__(fields, *args, **kwargs)
def compress(self, data_list):
if data_list:
start_date, stop_date = data_list
if start_date:
start_date = handle_timezone(
datetime.combine(start_date, time.min),
False
)
if stop_date:
stop_date = handle_timezone(
datetime.combine(stop_date, time.max),
False
)
return slice(start_date, stop_date)
return None
class DateTimeRangeField(RangeField):
widget = DateRangeWidget
def __init__(self, *args, **kwargs):
fields = (
forms.DateTimeField(),
forms.DateTimeField())
super().__init__(fields, *args, **kwargs)
class IsoDateTimeRangeField(RangeField):
widget = DateRangeWidget
def __init__(self, *args, **kwargs):
fields = (
IsoDateTimeField(),
IsoDateTimeField())
super().__init__(fields, *args, **kwargs)
class TimeRangeField(RangeField):
widget = DateRangeWidget
def __init__(self, *args, **kwargs):
fields = (
forms.TimeField(),
forms.TimeField())
super().__init__(fields, *args, **kwargs)
class Lookup(namedtuple('Lookup', ('value', 'lookup_expr'))):
def __new__(cls, value, lookup_expr):
if value in EMPTY_VALUES or lookup_expr in EMPTY_VALUES:
raise ValueError(
"Empty values ([], (), {}, '', None) are not "
"valid Lookup arguments. Return None instead."
)
return super().__new__(cls, value, lookup_expr)
class LookupChoiceField(forms.MultiValueField):
default_error_messages = {
'lookup_required': _('Select a lookup.'),
}
def __init__(self, field, lookup_choices, *args, **kwargs):
empty_label = kwargs.pop('empty_label', settings.EMPTY_CHOICE_LABEL)
fields = (field, ChoiceField(choices=lookup_choices, empty_label=empty_label))
widget = LookupChoiceWidget(widgets=[f.widget for f in fields])
kwargs['widget'] = widget
kwargs['help_text'] = field.help_text
super().__init__(fields, *args, **kwargs)
def compress(self, data_list):
if len(data_list) == 2:
value, lookup_expr = data_list
if value not in EMPTY_VALUES:
if lookup_expr not in EMPTY_VALUES:
return Lookup(value=value, lookup_expr=lookup_expr)
else:
raise forms.ValidationError(
self.error_messages['lookup_required'],
code='lookup_required')
return None
class IsoDateTimeField(forms.DateTimeField):
"""
Supports 'iso-8601' date format too which is out the scope of
the ``datetime.strptime`` standard library
# ISO 8601: ``http://www.w3.org/TR/NOTE-datetime``
Based on Gist example by David Medina https://gist.github.com/copitux/5773821
"""
ISO_8601 = 'iso-8601'
input_formats = [ISO_8601]
def strptime(self, value, format):
value = force_str(value)
if format == self.ISO_8601:
parsed = parse_datetime(value)
if parsed is None: # Continue with other formats if doesn't match
raise ValueError
return handle_timezone(parsed)
return super().strptime(value, format)
## ... source file continues with no further DateTimeField examples ...
django-floppyforms (project documentation and PyPI page) is a Django code library for better control over rendering HTML forms in your templates.
The django-floppyforms code is provided as open source and maintained by the collaborative developer community group Jazzband.
django-floppyforms / floppyforms / fields.py
import django
from django import forms
import decimal
from .widgets import (TextInput, HiddenInput, CheckboxInput, Select,
ClearableFileInput, SelectMultiple, DateInput,
DateTimeInput, TimeInput, URLInput, NumberInput,
EmailInput, NullBooleanSelect, SlugInput, IPAddressInput,
SplitDateTimeWidget, SplitHiddenDateTimeWidget,
MultipleHiddenInput)
__all__ = (
'Field', 'CharField', 'IntegerField', 'DateField', 'TimeField',
'DateTimeField', 'EmailField', 'FileField', 'ImageField', 'URLField',
'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField',
'FloatField', 'DecimalField', 'SlugField', 'RegexField',
'GenericIPAddressField', 'TypedChoiceField', 'FilePathField',
'TypedMultipleChoiceField', 'ComboField', 'MultiValueField',
'SplitDateTimeField',
)
if django.VERSION < (1, 9):
__all__ += ('IPAddressField',)
class Field(forms.Field):
widget = TextInput
hidden_widget = HiddenInput
class CharField(Field, forms.CharField):
widget = TextInput
def widget_attrs(self, widget):
attrs = super(CharField, self).widget_attrs(widget)
if attrs is None:
attrs = {}
if self.max_length is not None and isinstance(widget, (TextInput, HiddenInput)):
# The HTML attribute is maxlength, not max_length.
attrs.update({'maxlength': str(self.max_length)})
return attrs
class BooleanField(Field, forms.BooleanField):
widget = CheckboxInput
class NullBooleanField(Field, forms.NullBooleanField):
widget = NullBooleanSelect
class ChoiceField(Field, forms.ChoiceField):
widget = Select
class TypedChoiceField(ChoiceField, forms.TypedChoiceField):
widget = Select
class FilePathField(ChoiceField, forms.FilePathField):
widget = Select
class FileField(Field, forms.FileField):
widget = ClearableFileInput
class ImageField(Field, forms.ImageField):
widget = ClearableFileInput
class MultipleChoiceField(Field, forms.MultipleChoiceField):
widget = SelectMultiple
hidden_widget = MultipleHiddenInput
class TypedMultipleChoiceField(MultipleChoiceField,
forms.TypedMultipleChoiceField):
pass
class DateField(Field, forms.DateField):
widget = DateInput
class DateTimeField(Field, forms.DateTimeField):
widget = DateTimeInput
class TimeField(Field, forms.TimeField):
widget = TimeInput
class FloatField(Field, forms.FloatField):
widget = NumberInput
def widget_attrs(self, widget):
attrs = super(FloatField, self).widget_attrs(widget) or {}
if self.min_value is not None:
attrs['min'] = self.min_value
if self.max_value is not None:
attrs['max'] = self.max_value
if 'step' not in widget.attrs:
attrs.setdefault('step', 'any')
return attrs
class IntegerField(Field, forms.IntegerField):
widget = NumberInput
def __init__(self, *args, **kwargs):
kwargs.setdefault('widget', NumberInput if not kwargs.get('localize') else self.widget)
super(IntegerField, self).__init__(*args, **kwargs)
def widget_attrs(self, widget):
attrs = super(IntegerField, self).widget_attrs(widget) or {}
if self.min_value is not None:
attrs['min'] = self.min_value
if self.max_value is not None:
attrs['max'] = self.max_value
return attrs
class DecimalField(Field, forms.DecimalField):
widget = NumberInput
def __init__(self, *args, **kwargs):
kwargs.setdefault('widget', NumberInput if not kwargs.get('localize') else self.widget)
super(DecimalField, self).__init__(*args, **kwargs)
def widget_attrs(self, widget):
attrs = super(DecimalField, self).widget_attrs(widget) or {}
if self.min_value is not None:
attrs['min'] = self.min_value
if self.max_value is not None:
attrs['max'] = self.max_value
if self.decimal_places is not None:
attrs['step'] = decimal.Decimal('0.1') ** self.decimal_places
return attrs
class EmailField(Field, forms.EmailField):
widget = EmailInput
class URLField(Field, forms.URLField):
widget = URLInput
class SlugField(Field, forms.SlugField):
widget = SlugInput
class RegexField(Field, forms.RegexField):
widget = TextInput
def __init__(self, regex, js_regex=None, max_length=None, min_length=None,
error_message=None, *args, **kwargs):
self.js_regex = js_regex
super(RegexField, self).__init__(regex, max_length, min_length,
*args, **kwargs)
def widget_attrs(self, widget):
attrs = super(RegexField, self).widget_attrs(widget) or {}
if self.js_regex is not None:
attrs['pattern'] = self.js_regex
return attrs
if django.VERSION < (1, 9):
class IPAddressField(Field, forms.IPAddressField):
widget = IPAddressInput
class GenericIPAddressField(Field, forms.GenericIPAddressField):
pass
class ComboField(Field, forms.ComboField):
pass
class MultiValueField(Field, forms.MultiValueField):
pass
class SplitDateTimeField(forms.SplitDateTimeField):
widget = SplitDateTimeWidget
hidden_widget = SplitHiddenDateTimeWidget
def __init__(self, *args, **kwargs):
super(SplitDateTimeField, self).__init__(*args, **kwargs)
for widget in self.widget.widgets:
widget.is_required = self.required
django-mongonaut (project documentation and PyPI package information) provides an introspective interface for working with MongoDB via mongoengine. The project has its own new code to map MongoDB to the Django Admin interface.
django-mongonaut's highlighted features include automatic introspection of mongoengine documents, the ability to constrain who sees what and what they can do and full control for adding, editing and deleting documents.
The django-mongonaut project is open sourced under the MIT License and it is maintained by the developer community group Jazzband.
django-mongonaut / mongonaut / forms / widgets.py
# -*- coding: utf-8 -*-
""" Widgets for mongonaut forms"""
from django import forms
from mongoengine.base import ObjectIdField
from mongoengine.fields import BooleanField
from mongoengine.fields import DateTimeField
from mongoengine.fields import EmbeddedDocumentField
from mongoengine.fields import ListField
from mongoengine.fields import ReferenceField
from mongoengine.fields import FloatField
from mongoengine.fields import EmailField
from mongoengine.fields import DecimalField
from mongoengine.fields import URLField
from mongoengine.fields import IntField
from mongoengine.fields import StringField
from mongoengine.fields import GeoPointField
def get_widget(model_field, disabled=False):
"""Choose which widget to display for a field."""
attrs = get_attrs(model_field, disabled)
if hasattr(model_field, "max_length") and not model_field.max_length:
return forms.Textarea(attrs=attrs)
elif isinstance(model_field, DateTimeField):
return forms.DateTimeInput(attrs=attrs)
elif isinstance(model_field, BooleanField):
return forms.CheckboxInput(attrs=attrs)
elif isinstance(model_field, ReferenceField) or model_field.choices:
return forms.Select(attrs=attrs)
elif (isinstance(model_field, ListField) or
isinstance(model_field, EmbeddedDocumentField) or
isinstance(model_field, GeoPointField)):
return None
else:
return forms.TextInput(attrs=attrs)
def get_attrs(model_field, disabled=False):
"""Set attributes on the display widget."""
attrs = {}
attrs['class'] = 'span6 xlarge'
if disabled or isinstance(model_field, ObjectIdField):
attrs['class'] += ' disabled'
attrs['readonly'] = 'readonly'
return attrs
def get_form_field_class(model_field):
"""Gets the default form field for a mongoenigne field."""
FIELD_MAPPING = {
IntField: forms.IntegerField,
StringField: forms.CharField,
FloatField: forms.FloatField,
BooleanField: forms.BooleanField,
DateTimeField: forms.DateTimeField,
DecimalField: forms.DecimalField,
URLField: forms.URLField,
EmailField: forms.EmailField
}
return FIELD_MAPPING.get(model_field.__class__, forms.CharField)