Django-autocomplete-light: DAL v3: ModelSelect2 with form initial does not respect get_result_label

Created on 26 Feb 2016  Â·  6Comments  Â·  Source: yourlabs/django-autocomplete-light

hello, I'm moving to DAL v3. I wonder if it is possible that the value set to form the initial, is shown as get_result_label

Sample code

views.py
from django.views import generic
from django.db.models import Q
from django.core.urlresolvers import reverse_lazy
from django.contrib.auth.models import User
from dal import autocomplete

from .models import SampleModel
from .forms import SampleForm


class UserAutocomplete(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        # Don't forget to filter out results depending on the visitor !
        if not self.request.user.is_authenticated():
            return User.objects.none()

        qs = User.objects.all()

        if self.q:
            qs = qs.filter(Q(first_name__icontains=self.q) | Q(last_name__icontains=self.q))
        return qs

    def get_result_label(self, result):
        return result.get_full_name().title()


class SampleView(generic.UpdateView):
    form_class = SampleForm
    model = SampleModel

    def get_success_url(self):
        return reverse_lazy('sample_update', {'pk': self.object.pk})

    def get_initial(self):
        initial = super(SampleView, self).get_initial()
        user = getattr(self.request, 'user', None)
        if user and user.is_authenticated():
            initial.update({'selected_user': user})
        return initial
models.py
from django.db import models
from django.contrib.auth.models import User


class SampleModel(models.Model):
    selected_user = models.ForeignKey(to=User,
                                      related_name="%(app_label)s_%(class)s_selected_user", null=True,
                                      blank=True, on_delete=models.SET_NULL)

forms.py
from dal import autocomplete
from django import forms
from django.contrib.auth.models import User
from .models import SampleModel


class SampleForm(forms.ModelForm):
    selected_user = forms.ModelChoiceField(
        queryset=User.objects.all(),
        widget=autocomplete.ModelSelect2(url='user-autocomplete')
    )

    class Meta:
        models = SampleModel
        fields = '__all__'

urls.py
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^sample-update/(?P<pk>\d+)/$',
        views.SampleView.as_view(),
        name='sample_update'
        ),
    url(r'^user-autocomplete/$',
        views.UserAutocomplete.as_view(),
        name='user-autocomplete'
        )
]

Most helpful comment

RESOLVED!!

This is not a problem DAL v3.

it was necessary to create a new class that inherits from forms.ModelChoiceField and create a label_from_instance method which returns the value of the label that need.

look at the end of the ModelChoiceField documentation https://docs.djangoproject.com/es/1.9/ref/forms/fields/#modelchoicefield

this would be a good example to include in the documentation, because I believe it is a common use.

from dal import autocomplete
from django import forms
from django.contrib.auth.models import User
from .models import SampleModel


class UserModelChoiceField(forms.ModelChoiceField):
    def label_from_instance(self, obj):
        return obj.get_full_name().title()

class SampleForm(forms.ModelForm):
    selected_user = UserModelChoiceField(
        queryset=User.objects.all(),
        widget=autocomplete.ModelSelect2(url='user-autocomplete')
    )

    class Meta:
        models = SampleModel
        fields = '__all__'

@jpic thank you for the incredible work.

All 6 comments

RESOLVED!!

This is not a problem DAL v3.

it was necessary to create a new class that inherits from forms.ModelChoiceField and create a label_from_instance method which returns the value of the label that need.

look at the end of the ModelChoiceField documentation https://docs.djangoproject.com/es/1.9/ref/forms/fields/#modelchoicefield

this would be a good example to include in the documentation, because I believe it is a common use.

from dal import autocomplete
from django import forms
from django.contrib.auth.models import User
from .models import SampleModel


class UserModelChoiceField(forms.ModelChoiceField):
    def label_from_instance(self, obj):
        return obj.get_full_name().title()

class SampleForm(forms.ModelForm):
    selected_user = UserModelChoiceField(
        queryset=User.objects.all(),
        widget=autocomplete.ModelSelect2(url='user-autocomplete')
    )

    class Meta:
        models = SampleModel
        fields = '__all__'

@jpic thank you for the incredible work.

This would be pretty cool to add to the docs indeed​ !

Solution is in the docs: https://select2.org/programmatic-control/add-select-clear-items#preselecting-options-in-an-remotely-sourced-ajax-select2

It would be nice to have generic view for this case. At the moment it an be solved like this:

    let page_selects = $(
      '.nested-list-form [data-autocomplete-light-function=select2]',
    )

    page_selects.each(function() {
      let select = $(this)

      $.ajax({
        type: 'GET',
        url: select.data('autocompleteLightUrl'),
        data: {
          forward: JSON.stringify({
            id: select.val(),
          }),
        },
      }).then(function(data) {
        // create the option and append to Select2
        let option = new Option(
          data.results[0].selected_text,
          data.results[0].id,
          true,
          true,
        )
        select.append(option).trigger('change')

        // manually trigger the `select2:select` event
        select.trigger({
          type: 'select2:select',
          params: {
            data: data,
          },
        })
      })
    })

at your view:

    def get_queryset(self):
        # ....
        # Exclude anything but specific item
        page_id = self.forwarded.get("id")
        if page_id:
            qs = qs.filter(pk=page_id)

        if self.q:
            qs = qs.search(self.q, fields=[self.model_field_name])

        return qs

get_result_label and get_selected_result_label stays as is.

Great solution by @pySilver! Works perfect! Would be great to have it in standard library!

@Simanas it should be a little bit different:

// @see: https://github.com/yourlabs/django-autocomplete-light/issues/607#issuecomment-570440273
;(function($) {
  'use strict'
  window.addEventListener('dal-function-registered.select2', function() {
    $(function() {
      $('select[data-autocomplete-light-function=select2]')
        .filter('select[data-autocomplete-light-url]')
        .each(function(i, obj) {
          let select = $(this)
          if (!select.data('autocompleteLightUrl')) {
            return
          }

          let val = select.val()
          if ($.isEmptyObject(val)) {
            return
          }

          let forward = yl.getForwards(select)
          if (forward === undefined) {
            return
          }

          forward = JSON.parse(forward)
          forward['id'] = select.val()
          forward = JSON.stringify(forward)

          $.ajax({
            type: 'GET',
            url: select.data('autocompleteLightUrl'),
            data: {
              forward: forward,
            },
          }).then(function(data) {
            // create the option and append to Select2
            select.empty()
            for (let i = 0; i < data.results.length; i++) {
              let option = new Option(
                data.results[i].selected_text,
                data.results[i].id,
                true,
                true,
              )
              select.append(option).trigger('change')
            }

            // manually trigger the `select2:select` event
            select.trigger({
              type: 'select2:select',
              params: {
                data: data,
              },
            })
          })
        })
    })
  })
})(jQuery)

What is yl.getForwards(select)?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

VagnerNico picture VagnerNico  Â·  4Comments

JMIdeaMaker picture JMIdeaMaker  Â·  3Comments

darahsten picture darahsten  Â·  7Comments

durdenk picture durdenk  Â·  8Comments

ulziiburend picture ulziiburend  Â·  7Comments