applegrew / django-select2

This is a Django integration for Select2

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ModelSelect2Widget initial value is not selected

nikolaysm opened this issue · comments

Hi,

I am using django-select2==6.0.2 with django 1.11.

So i add ModelSelect2Widget in __init__.


class ParticipantSelect2Widget(ModelSelect2Widget):

    def label_from_instance(self, obj):
        job = obj.job
        title = "Job ID: %s" % job.pk if job else _("No job")
        return "%s - %s" % (obj.full_name, title)

    def filter_queryset(self, term, queryset=None, **dependent_fields):
        return super(ParticipantSelect2Widget, self).filter_queryset(term, queryset, **dependent_fields).distinct("email")

class MeetingForm(forms.ModelForm):
    ......
    def __init__(self, *args, **kwargs):
        user = kwargs.pop('user', None)
        super(MeetingForm, self).__init__(*args, **kwargs)
        if not user.is_staff:
            queryset = Meeting.objects.filter(company__pk__in=user.contact_set.values_list("business_id", flat=True))
        else:
            queryset = Meeting.objects.all()
        import pdb; pdb.set_trace()
        self.fields["participant"].widget = ParticipantSelect2Widget(
            queryset=queryset, search_fields = ["firstname__icontains", "lastname__icontains"],
            attrs={'data-theme':'material', 'class':'browser-default material-ignore', 'data-minimum-input-length': 3,
                'data-allow-clear':'false', 'data-placeholder':_("Choose an Participant")})

The problem is that instance values are not selected. And dropdown field is empty.
It works perfectly when I add it via widgets but not with __init__.

widgets = {
            'participant': ParticipantSelect2Widget(model=Participant, search_fields = ["firstname__icontains", "lastname__icontains"],
            attrs={'data-theme':'material', 'class':'browser-default material-ignore', 'data-minimum-input-length': 3,
               'data-allow-clear':'false', 'data-placeholder':_("Choose an Participant")})
}

The only solution that I see now is to create a custom AutoResponseView for ModelSelect2Widget, and add ModelSelect2Widget before __init__.

Are there other options?

Thanks

Hi @nikolaysm,

Thanks for reaching out. I am not 100% certain I understood your problem, but I am just going to guess. Let me know if my guess is wrong and please provide me with more detail about your problem, rather than your current shot at a solution.

So my guess is, you are trying to display different options depending on the authenticated user, correct?

If so all you need to do is to override the filter_queryset method. The first argument the method gets is the current request and the second is the search term for that request. In other words whatever the user is currently typing into the Select2 search field.

So a solution could look similar to something like this:

from django_select2.forms import ModelSelect2Widget


class MyWidget(ModelSelect2Widget):
    def filter_queryset(self, request, term, queryset=None, **dependent_fields):
        if request.user.is_authenticated:
            queryset = queryset.filter(user=request.user)
        return super().filter_queryset(self, request, term, queryset=queryset, **dependent_fields)

If hope this example helps. Let me know if you need any further assistance.

Best
-Joe

Hi @codingjoe, Thanks for your quick response.

I am using django-select2==6.0.2, and def filter_queryset has no request yet.
Screenshot 2020-04-03 at 17 01 30

Do you have any other option?

Thanks,
Nikolay

Hi @nikolaysm,

as I mentioned before I am just guessing your problem. To further assist you I really need a more detailed description of what you are trying to achieve and your form code including all widgets.

Best
-Joe

My problem is that form field "participant" value is not selected. My select2 dropdown is empty, you can see it on provided screenshot.

My code

class ParticipantSelect2Widget(ModelSelect2Widget):
    model = Participant
    search_fields = ["firstname__icontains", "lastname__icontains"]

    def label_from_instance(self, obj):
        job = obj.job
        title = "Job ID: %s" % job.pk if job else _("No job")
        return "%s - %s" % (obj.full_name, title)

class MeetingForm(forms.ModelForm):
    class Meta:
        model = Meeting
        fields = [
            "company", "topic", "agenda", "participant",
            "type_meeting", "start_time", "duration",
            "password", "join_before_host","mute_upon_entry"
        ]

    def __init__(self, *args, **kwargs):
        user = kwargs.pop('user', None)  
        super(MeetingForm, self).__init__(*args, **kwargs)
        if not user.is_staff:
            queryset = Participant.objects.filter(company__pk__in=user.contact_set.values_list("business_id", flat=True))
        else:
            queryset = Participant.objects.all()
        self.fields["participant"].widget = ParticipantSelect2Widget(
            queryset=queryset, 
            attrs = {
                'data-theme':'material', 'class':'browser-default material-ignore',
                'data-minimum-input-length': 3, 'data-allow-clear':'false',
                'data-placeholder':_("Choose an Participant")
            }
)

Any help is appreciated
Nikolay

My problem was solved by adding selected value to field.choices.

I have added below part code in def __init__

sltd_participant = self.data.get("participant") or self.initial.get("participant")
if sltd_participant:
    self.fields["participant"].choices = [(sltd_participant, queryset.get(pk=sltd_participant))]

Maybe that would be interesting for ModelSelect2Widget by default adding field value to self.fields ["field"].choices. And if no field value, then empty self.fields ["field"].choices.

It would be more interested if Queryset is too large.
Then you don't need to render all the choices(select>options).

Or am I missing something?

Best,
Nikolay

@nikolaysm glad you found a solution. I would advise a little change though. You see, the widget choices are set by default, you are just overwriting the widget where the choices were set.
The trick is to the correct widget before the form is instantiated.

Here an example, that should work for your use case:

class ParticipantSelect2Widget(ModelSelect2Widget):
    model = Participant
    search_fields = ["firstname__icontains", "lastname__icontains"]

    def label_from_instance(self, obj):
        job = obj.job
        title = "Job ID: %s" % job.pk if job else _("No job")
        return "%s - %s" % (obj.full_name, title)

    def filter_queryset(self, request, term, queryset=None, **dependent_fields):
        if request.user.is_authenticated:
            queryset = queryset.filter(company__in=request.user.user.contact_set.all())
        return super().filter_queryset(self, request, queryset, **dependent_fields)


class MeetingForm(forms.ModelForm):
    class Meta:
        model = Meeting
        fields = [
            "company", "topic", "agenda", "participant",
            "type_meeting", "start_time", "duration",
            "password", "join_before_host","mute_upon_entry"
        ]
        widgets = {
            "participant": ParticipantSelect2Widget(attrs={
                'data-theme': 'material', 'class': 'browser-default material-ignore',
                'data-minimum-input-length': 3, 'data-allow-clear': 'false',
                'data-placeholder': _("Choose an Participant")
            })
        }

I hope that helps.

Best
-Joe