from django import forms
from django.core.exceptions import ValidationError
from django.utils.translation import ngettext
from shuup.utils.django_compat import force_text
[docs]
class RelaxedModelChoiceField(forms.ModelChoiceField):
# `RelaxedModelChoiceField`s allow manually setting `choices` with full validation
# as an improvement over the normal `ModelChoiceField`.
[docs]
def to_python(self, value):
try:
return super().to_python(value)
except ValidationError as verr:
if verr.code == "invalid_choice":
# If the original code declared this as invalid, see if we have custom choices.
if hasattr(self, "_choices"):
# Stringly [sic] typed comparison...
value = force_text(value)
key = self.to_field_name or "pk"
for pk, obj in self._choices:
if force_text(pk) == value or force_text(getattr(obj, key, "")) == value:
if obj is None or isinstance(obj, self.queryset.model):
return obj
raise verr # Just reraise the original exception then, but from here for clarity
[docs]
class TypedMultipleChoiceWithLimitField(forms.TypedMultipleChoiceField):
[docs]
def __init__(self, min_limit=None, max_limit=None, **kwargs):
self.min_limit = min_limit
self.max_limit = max_limit
super().__init__(**kwargs)
[docs]
def clean(self, value):
value = super().clean(value)
if self.min_limit is not None and len(value) < self.min_limit:
error_message = ngettext(
"You can't select less than {min_limit} item.",
"You can't select less than {min_limit} items.",
self.min_limit,
)
raise forms.ValidationError(error_message.format(min_limit=self.min_limit))
if self.max_limit is not None and len(value) > self.max_limit:
error_message = ngettext(
"You can't select more than {max_limit} item.",
"You can't select more than {max_limit} items.",
self.max_limit,
)
raise forms.ValidationError(error_message.format(max_limit=self.max_limit))
return value