Skip to content

Select2 Initial Values #1076

@CoryADavis

Description

@CoryADavis

I'm working with a large FormWizard, and the way that users will interact with the data after form submission is such that Foreign Key fields in the model would be a problem. So, I'm using the plain Select2, not ModelSelect2.

The Select2 works! You can submit the form, and the selection comes through just fine. But, if you go to edit, the initial values populate for everything but the example Select2 field. It's not just a display issue, if you submit the edit, the value is blanked out in the database.

My question, is this supported and not working as a bug, or implementation failure on my part? Or is this not supported? If not, how might this be accomplished? I've tried setting the initial in the choice field manually, but that didn't appear to be the answer like in other issues I saw while searching my problem.

-- EDIT START --

I solved my problem, it's not supported, using ModelSelect2 is specifically what's required to get the information needed to set the initial values. I used a combination of seemingly hacky nonsense to get it to work without using a foreign key. Is there a more proper way to do this? If so, would that be a good addition to the documentation?

hacky forms.py snippet

class CustomModelChoiceField(forms.ModelChoiceField):
    def to_python(self, value):
        if value in self.empty_values:
            return None
        try:
            key = self.to_field_name or 'pk'
            value = self.queryset.get(**{key: value})
        except (ValueError, TypeError, self.queryset.model.DoesNotExist):
            raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice')
        return value.name

class Form1(autocomplete.FutureModelForm):
    example = CustomModelChoiceField(widget=CustomSelect2(url='autocomplete-example'),
                                  queryset=ExampleChoices.objects.all(),
                                  to_field_name='name')

hacky widgets.py snippet (just the filter_choices_to_render)

class Select2BootstrapWidgetMixin(object):
    class Media:
        extend = True
        css = {'all': ('css/select2-bootstrap4.css',)}

    def build_attrs(self, *args, **kwargs):
        attrs = super(Select2BootstrapWidgetMixin, self).build_attrs(*args, **kwargs)
        attrs.setdefault('data-theme',
                         'bootstrap4')
        return attrs

    def filter_choices_to_render(self, selected_choices):
        """Filter out un-selected choices if choices is a QuerySet."""
        self.choices.queryset = self.choices.queryset.filter(
            choice__in=[c for c in selected_choices if c]

-- EDIT END --

models.py snippet

class Example(models.Model):
    example = models.CharField(max_length=500, blank=True, null=True)

forms.py snippet (CustomSelect2 is just Select2 with media for bootstrap styling)

class Form1(autocomplete.FutureModelForm):
    example = forms.ChoiceField(widget=CustomSelect2(url='autocomplete-site'))

    class Meta:
        model = Example

forms.py alternate snippet (This is the failed setting initial attempt)

class Form1(autocomplete.FutureModelForm):
    def __init__(self, *args, **kwargs):
        super(Form1, self).__init__(*args, **kwargs)
        example = self.initial.get('example', None)
        if example:
            self.fields['example'] = forms.CharField(widget=CustomSelect2(url='autocomplete-site', attrs={'data-placeholder': f'Un-edited Value: {example}'}), initial=example)

views.py snippet

class ExampleAutocomplete(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        qs = Select2Choices.objects.filter(field='example').only('name').order_by('name')
        if self.q:
            qs = qs.filter(choice__istartswith=self.q)

        return qs

    def get_result_value(self, result):
        """Return the value of a result."""
        return str(result.name)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions