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