applegrew/django-select2

django-select2 whit django-cities loops.

mikaelosterberg opened this issue · 4 comments

Hi

Can't get django-select2 play nice whit django-cities any one have a suggestion?

The problem is that on validation of a submitted from django-select2 loops the entier db off django-cities (22K+ rows) it takes a long time.

form.py

class CityClass(AutoModelSelect2Field):
    queryset=City.objects
    search_fields  = ['name__icontains', 'slug__icontains', 'name_std__icontains', ]

class UserForm(forms.Form):
    BIRTH_YEAR_CHOICES = range((date.today().year - 90), (date.today().year - 15))
    error_messages = {
        'duplicate_pagename': _("A page with that name already exists."),
        'duplicate_email':    _("A user with that email already exists."),
        'sixteen_or_older':    _("You have to be sixteen or older to join"),
    }
    email               = forms.EmailField(label=_('E-mail'),
                                        help_text = _("Required"))
    dob                 = forms.DateField(label=_('Date of birth'),                                       widget=extras.SelectDateWidget(years=BIRTH_YEAR_CHOICES),
                                        help_text = _("Required. Your date of birth"))
    city                = CityClass()

views.py

def newUser(request):
    if request.method == 'POST':
            form = UserForm(request.POST)
            if form.is_valid():
                messages.info(request,  form.cleaned_data)

I don't use Auto*Field, but django-cities works nice in my app (you can try in on search form on http://www.4job.co).
Here is my approach:

forms.py

class SearchFormSimple(forms.Form):
    loc = HeavySelect2MultipleChoiceField(
                    widget=HeavySelect2MultipleWidget(
                            data_view='cities_json',
                            select2_options={
                                    'placeholder': _('Type city name')
                                    }
                            ),
                    required=False)

urls.py

...
    url(r'^select2/cities/',        CitiesSelect2View.as_view(),
                                        name='cities_json'),
...

views.py

class CitiesSelect2View(Select2View):
    """ Data view for Cities """
    max_results = 15  # page size is max_results

    def get_results(self, request, term, page, context):

        from cities.models import City
        curr_lang = get_language()[0:2]
        if curr_lang == 'ru':
            city_set = (City.objects
                            .filter(alt_names_ru__name__istartswith=term)
                            .distinct()
                            .order_by('name'))
        else:
            city_set = (City.objects
                            .filter(name__istartswith=term)
                            .distinct()
                            .order_by('name'))
        min_ = (page - 1) * self.max_results
        max_ = min_ + self.max_results + 1
        city_set = list(city_set[min_:max_])
        has_more = len(city_set) == (max_ - min_)
        if has_more:
            city_set = city_set[:-1]
        res = []
        from .utils import full_city_rec
        for city in city_set:
            names = full_city_rec(city, curr_lang)
            res.append((city.id, ", ".join(names)))
        return (NO_ERR_RESP, has_more, res)

hope this helps you.
It's code for component visible to unregistered user. Similar code used for saving city for enterprise location (accessible for registered users) and there is no problem with validation.

Thanks that helps.. Currently I am swamped by other tasks and my job of course, so you can except delay in my response.

@mikaelosterberg

The problem is that on validation of a submitted from django-select2 loops the entier db off django-cities (22K+ rows) it takes a long time.

Well the code uses normal Django code for the validation. So if the submitted value is stored in value then it runs - self.queryset.get(id=value). Since Pks have unique index over them so this should not cause a full table scan. If you see a performance difference when using Django only and Django + Django_Select2 then please report back.

Ok now I understand the real issue. When django-select2 widgets render they loop through all the rows and discard them. This has been fixed in v4.2.1.