from django import forms
from django.core.exceptions import ValidationError
class EmptyModelChoiceField(forms.ModelChoiceField):
"""
This ModelChoiceField is used for empty or partial querysets.
When the form field is validated, ignore the item is not found in the
queryset.
The item will be searched again during the validation in the manager
object instead of using the queryset
"""
def __init__(self, queryset, manager, *, empty_label="---------",
required=True, widget=None, label=None, initial=None,
help_text='', to_field_name=None, limit_choices_to=None,
blank=False, **kwargs):
super().__init__(queryset=queryset,
empty_label=empty_label,
required=required,
widget=widget,
label=label,
initial=initial,
help_text=help_text,
to_field_name=to_field_name,
limit_choices_to=limit_choices_to,
blank=blank,
**kwargs)
# Manager object to use for future lookups
self.manager = manager
def to_python(self, value):
try:
value = super().to_python(value)
except ValidationError as error:
# Item not found
key = self.to_field_name or 'pk'
# Search again using the the manager object
value = self.manager.filter(**{key: value})
if value.exists():
# Item was found in the manager object
value = value.first()
else:
# Item was not found in the manager object
# Raise the same parent class ValidationError
raise error
return value