from decimal import Decimal
from numbers import Number
from django.core.exceptions import ValidationError
from django.forms import DecimalField, Field, MultipleChoiceField, Select, SelectMultiple
from django.utils.translation import gettext_lazy as _
from shuup.utils.django_compat import force_text
[docs]
class PercentageField(DecimalField):
MULTIPLIER = Decimal(100)
[docs]
def prepare_value(self, value):
# Percentage values are 0..1 in database, so multiply by 100
if value is not None and isinstance(value, Number):
value *= self.MULTIPLIER
return super().prepare_value(value)
[docs]
def to_python(self, value):
value = super().to_python(value)
if value is not None:
# We got a value, so divide it by 100 to get the 0..1 range value
value /= self.MULTIPLIER
return value
[docs]
class Select2ModelField(Field):
"""
This form field class is deprecated and it will be removed on version 3.
Use ObjectSelect2ModelField class instead.
"""
widget = Select
[docs]
def __init__(self, model, *args, **kwargs):
self.model = model
super().__init__(*args, **kwargs)
[docs]
def prepare_value(self, value):
return getattr(value, "pk", value)
[docs]
def to_python(self, value):
if value:
return self.model.objects.filter(pk=value).first()
[docs]
class Select2MultipleField(Field):
"""
This form field class is deprecated and it will be removed on version 3.
Use ObjectSelect2MultipleField class instead.
"""
widget = SelectMultiple
[docs]
def __init__(self, model, search_mode=None, *args, **kwargs):
self.model = model
if search_mode:
self.search_mode = search_mode
super().__init__(*args, **kwargs)
[docs]
def prepare_value(self, value):
values = [getattr(v, "pk", v) for v in value or []]
# make sure to add the initial values as choices to the field
if values and not self.widget.choices:
from django.utils.encoding import force_text
self.widget.choices = [
(instance.pk, force_text(instance)) for instance in self.model.objects.filter(pk__in=values)
]
return values
[docs]
def to_python(self, value):
value = super().to_python(value)
# Here we have sometimes None which will cause errors when
# saving related fields so let's fallback to empty list
return value or []
[docs]
class Select2ModelMultipleField(Select2MultipleField):
"""
Just like Select2MultipleField, but return instances instead of ids.
This form field class is deprecated and it will be removed on version 3.
Use ObjectSelect2ModelMultipleField class instead.
"""
[docs]
def prepare_value(self, value):
return [getattr(v, "pk", v) for v in value or []]
[docs]
def to_python(self, value):
if value and isinstance(value, (list, tuple)):
value = [v for v in value if v]
if value:
return self.model.objects.filter(pk__in=value)
return []
[docs]
class Select2MultipleMainProductField(Select2MultipleField):
"""
Search only from parent and normal products.
This form field class is deprecated and it will be removed on version 3.
Use ObjectSelect2MultipleMainProductField class instead.
"""
[docs]
def widget_attrs(self, widget):
attrs = super().widget_attrs(widget)
attrs.update({"data-search-mode": "main"})
return attrs
[docs]
class WeekdaysSelectMultiple(SelectMultiple):
[docs]
class WeekdayField(MultipleChoiceField):
widget = WeekdaysSelectMultiple
DAYS_OF_THE_WEEK = [
(0, _("Monday")),
(1, _("Tuesday")),
(2, _("Wednesday")),
(3, _("Thursday")),
(4, _("Friday")),
(5, _("Saturday")),
(6, _("Sunday")),
]
[docs]
def __init__(
self,
choices=(),
required=True,
widget=None,
label=None,
initial=None,
help_text="",
*args,
**kwargs,
):
if not choices:
choices = self.DAYS_OF_THE_WEEK
super().__init__(
choices=choices,
required=required,
widget=widget,
label=label,
initial=initial,
help_text=help_text,
**kwargs,
)
[docs]
def clean(self, value):
return ",".join(super().clean(value))
[docs]
class ObjectSelect2ModelField(Select2ModelField):
"""
Class for select2 form fields.
Replacement for the class Select2ModelField.
"""
[docs]
def __init__(self, model, selector=None, search_mode=None, *args, **kwargs):
super().__init__(model, *args, **kwargs)
self.selector = selector
[docs]
def prepare_value(self, value):
if self.model:
return super().prepare_value(value)
return value
[docs]
def to_python(self, value):
if self.model:
return super().to_python(value)
return value
[docs]
class ObjectSelect2MultipleField(Select2MultipleField):
"""
Class for select2 form fields.
Replacement for the class Select2MultipleField.
"""
[docs]
def __init__(self, model, selector=None, search_mode=None, *args, **kwargs):
super().__init__(model, *args, **kwargs)
self.selector = selector
[docs]
def prepare_value(self, value):
if self.model:
return super().prepare_value(value)
return value
[docs]
def to_python(self, value):
if self.model:
return super().to_python(value)
if not value:
return []
elif not isinstance(value, (list, tuple)):
raise ValidationError(self.error_messages["invalid_list"], code="invalid_list")
return [str(val) for val in value]
[docs]
class ObjectSelect2ModelMultipleField(Select2ModelMultipleField):
"""
Class for select2 form fields.
Replacement for the class Select2ModelMultipleField.
"""
[docs]
def __init__(self, model, selector=None, search_mode=None, *args, **kwargs):
super().__init__(model, *args, **kwargs)
self.selector = selector
[docs]
def prepare_value(self, value):
if self.model:
return super().prepare_value(value)
return list(value or [])
[docs]
def to_python(self, value):
if self.model:
return super().to_python(value)
if value and isinstance(value, (list, tuple)):
return value
return []
[docs]
class ObjectSelect2MultipleMainProductField(Select2MultipleMainProductField):
"""
Class for select2 form fields.
Replacement for the class Select2MultipleMainProductField.
"""
[docs]
def __init__(self, model, selector=None, search_mode=None, *args, **kwargs):
super().__init__(model, *args, **kwargs)
self.selector = selector
[docs]
def prepare_value(self, value):
if self.model:
return super().prepare_value(value)
return list(value or [])
[docs]
def to_python(self, value):
if self.model:
return super().to_python(value)
if value and isinstance(value, (list, tuple)):
return value
return []
[docs]
def widget_attrs(self, widget):
if self.model:
attrs = super().widget_attrs(widget)
else:
attrs = super(Select2MultipleField, self).widget_attrs(widget)
attrs["data-model"] = self.selector
if getattr(self, "search_mode", None):
attrs.update({"data-search-mode": self.search_mode})
if not self.required:
attrs["data-allow-clear"] = "true"
return attrs
attrs["class"] = "object-selector"
return attrs