Question on Select2ListChoiceField

155 views
Skip to first unread message

pelacables

unread,
Oct 28, 2020, 12:13:28 PM10/28/20
to yourlabs
Hi all,

I'm new to python, Django and, obviously, DAL. So sorry if I'm asking trivial things or misunderstanding some of your docs.

I'm trying to write a small application with a couple of dropdown menus that autocomplete and one depends on the other. 

My model is very simple:

```
class Module(models.Model):
  module_name = models.CharField(max_length=200, primary_key=True)
  packages_available = models.JSONField()
```

module_name will be the name of a software and packages_avaialble the list of packages available for that software. The list can be large, up to 2/3k items, that's why I used JSONField (is there a better approach?)

I then created 2 views for the autocomplete, one to get all the module_names in the DB and the other to get the list of packages once the module has been selected:

```
class ModuleAutocomplete(autocomplete.Select2QuerySetView):
  def get_queryset(self):
    qs = Module.objects.all()
    if self.q:
      qs = qs.filter(name__istartswith=self.q)
    return qs

class PackageAutocomplete(autocomplete.Select2ListView):
  def get_list(self):
    module_selected = self.forwarded.get('module', None)
    pklist = ''
    if module_selected:
      pklist = Module.objects.get(module_name=module_selected).packages_available
    return pklist
```
 
registered in urls:
```
url(r'^modules-autocomplete/$',ModuleAutocomplete.as_view(),name='modules-autocomplete',),
url(r'^packages-autocomplete/$',PackageAutocomplete.as_view(),name='packages-autocomplete',),
```

and checked that both urls can be reversed (the second with a forwared value, of course). All worked, so far so good.

I 'd like my application to ask for a module_name and a list of packages, so I created a form like:

```
class ModuleListForm(forms.Form):
    module = forms.ModelChoiceField(
        queryset=Module.objects.all(),
        widget=autocomplete.ModelSelect2(url='modules-autocomplete'),
        required=True,
    )
    packages = autocomplete.Select2ListChoiceField(
        widget=autocomplete.Select2Multiple(url='packages-autocomplete',
                                            forward=('module',)
                                            ),
    )
```

With all in place, I start the server and I see 2 dropdown select boxes that show exactly what I want and I can select multiple packages:
  https://ibb.co/tm7M4fr         ->         https://ibb.co/RbF6H5N

(for testing purposes the list of packages contains trash data, I still need to test this with thousands of packages).

My problem starts here. When I submit my form it returns an error because the option I select does not exist:

<tr><th><label for="id_packages">Packages:</label></th><td><ul class="errorlist"><li>Select a valid choice. [&#x27;mariposa&#x27;, &#x27;zariguella&#x27;] is not one of the available choices.</li></ul><select name="packages" required id="id_packages" data-autocomplete-light-url="/Rweb/packages-autocomplete/" data-autocomplete-light-function="select2" data-autocomplete-light-language="en" multiple>

As far as I understood that's expected because the ChoiceField validation expects the selected options to be predefined (if that's the word). 
I believe that this is what is explained in autocompleting-based-on-a-list-of-strings, or https://stackoverflow.com/q/23707666/11734894.  This other link provides a full example: https://stackoverflow.com/a/50961215/11734894 

So I think that  in my form the packages field needs a choice_list. Something like:

```
    packages = autocomplete.Select2ListChoiceField(
       choice_list=get_choice_list
        widget=autocomplete.Select2Multiple(url='packages-autocomplete',
                                            forward=('module',)
                                            ),
    )
 ```

BUT, how do I build a function that returns the list of choices if I do not know what options will be available? I have the feeling that I'm missing some important piece of information from the docs, but I don't find it :-(
Are my assumptions right or am I completely wrong?


I had a working solution when adding the choices to the form directly in the main view, something like:

```
Class Index(View):
  form_class = ModuleListForm
  template_name = 'index.html'
  av_choices = []

  def post(self, request, *args, **kwargs):
        modules_list = self.form_class(request.POST)
        packages_selected = request.POST.getlist('packages')
        context = { 'modules_list': modules_list}
       for pck in packages_selected:
            choice=tuple((pck, pck))
            self.av_choices.append(choice)
        modules_list.fields['packages'].choices = [self.av_choices]
```

(I have some problems building the fields list of tuples, but in some cases it worked).

The thing is that I believe that this workaround is not appropriate and that DAL can do it for me.

Thanks for all that read until here :-)

Arnau

Arnau Bria

unread,
Nov 23, 2020, 10:20:53 AM11/23/20
to your...@googlegroups.com
Hi all,

in case someone ends here looking for a solution to a similar problem (the solution I proposed "works", but it's not convenient).
Don't use Select2ListChoiceField, use Select2ListCreateChoiceField:

The solution was in the source code:
class dal_select2.fields.Select2ListCreateChoiceField(choice_list=None, required=True, widget=None, label=None, initial=None, help_text='', *args, **kwargs)[source]¶

Skips validation of choices so any value can be used.

Best,
Arnau

--
You received this message because you are subscribed to a topic in the Google Groups "yourlabs" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/yourlabs/bZs16ob1wHQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to yourlabs+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/yourlabs/413e884b-5911-4622-98bd-a9473a7239abn%40googlegroups.com.


--
Arnau Bria
Reply all
Reply to author
Forward
0 new messages