Pull to refresh

Продвинутые формы — мультиселект с автокомплитом

Reading time 5 min
Views 7K
Наши пользователи следят за спецпредложениями авиакомпаний и дешевыми перелетами, каждому интересно своё направление, пунктов вылета и прилета — тысячи, пользователи хотят одновременно следить за несколькоми городами, странами или регионами. Появилась задача — как предоставить удобный механизм подписки? Без долгого тыканья в мульти селект, без кнопок «Добавить пункт вылета». Ответ выглядит так —

Решением стал контрол из Фейсбука и Контакта — пользователи знакомы с ним, а значит не нужно объяснять как он работает. Осталось скрестить его с django.

Этот контрол подойдет для многих случаев когда нужна выборка из большого списка — сотнями или тысячами элементов.
Живой пример — на форме выбора городов для отcлеживания акций авиакомпаний.

Со стророны юзера используем готовый jquery plug-in, доступный на www.emposha.com/javascript/fcbkcomplete.html, скачиваем его и кладем css и js в папку media ( в моём случае — media/css и media/js )
Добавим код формы в foms.py-
class MultiOriginSelect(forms.SelectMultiple):
    class Media:
        css = {
            'all': ('/media/css/fcbkinput.css',)
        }
        js = ('/media/js/jquery.fcbkcomplete.js')
 
class SubscriptionFilterForm(forms.Form):

    CHOICES =[]
    ........
    orgs = forms.MultipleChoiceField(widget=MultiOriginSelect, choices=CHOICES, required=False, initial=[])
    dsts = forms.MultipleChoiceField(widget=MultiOriginSelect, choices=CHOICES,  required=False, initial=[])
    ........

    def __init__(self*args, **kwargs):
        super(SubscriptionFilterForm, self).__init__(*args, **kwargs)

        fcbkcomplete_fields = [u'orgs'u'dsts']
        for field in fcbkcomplete_fields:
            # check whether we have init parameters
            if args:
                loc_list = args[0].getlist(field)
                .....
                # generate dynamic choices for fcbk fields from args, like [id, name]
                self.fields[field].choices = ([(int(o), name(o)) for o in loc_list] )

Последняя строчка — основная, если у формы есть инициализационные значения — заполним choices.

В html файл с формой добавим инициалиазацию контролов:
<head>
<script>
   $(document).ready(function(){
     $("#id_orgs, #id_dsts").fcbkcomplete({
        json_url:'/subscribe_autocomplete',
        first_selected:false,
        filter_hide : true,
        filter_case:false,
        complete_text:"Enter country, city or airport.",
        maxitems: 100
        });
   });
</script>
</head>

<body>
....
    <form>
    ......
    {{form.orgs}}
    {{form.dsts}} 
    <input type = "submit">
    </form>
   ......
</body>


Для того чтобы работал автопокомплит — добавим вьюху, которая будет генерировать необходимый json В нашем случае он расположен по адресу — /subscribe_autocomplete. Итак добавляем — в urls.py:
.....
url(r'^subscribe_autocomplete', subscribe_autocomplete, name='subscribe_autocomplete'),
.....


во views.py:

def subscribe_autocomplete(request):
    q = request.GET.get('tag','')
    # skip too short requests 
    if len(q)<3return HttpResponse('')

    # filter any instances according to tag
    qr = Objects.objects.filter(Q(....))
    
    #generate json
    #message format - [{"caption":"London", "value":4}]
    s =[...];

    return HttpResponse(s)


теперь у нас работает форма на странице и успешно генериться заполненная форма из пост заспроса (form = SubscriptionFilterForm(request.POST) )

Для генерации формы из модели — использую отдельную функцию ( в моем случае ModelsForm не подошел )

def subs_form_from_model(s):
    src_d = {}
    src_d['subscriptionemail'= s.email
    ,,,,

    qd = django.http.QueryDict('')
    qd = qd.copy() # to make muttable
    qd.update(src_d)

    # fill form fields
    qd.setlist('orgs', [unicode(o.id) for o in s.orgs.all()])
    qd.setlist('dsts', [unicode(d.id) for d in s.dsts.all()])

   # create form
    form = SubscriptionFilterForm(qd)
    .......... 

    return form</code>


Большинство пользователей видит поле уже заполненным ( по гео айпи ) и понимает что к чему.
Такую же форму можно ( и нужно ) использовать в админке, для больших мени-ту-мени полей.

PS И чтобы два раза не вставать — если вам понравились буруки (или вы уже пользуетесь нашем поиском и рассылкой) — с радостью пообщаемся с умелым верстальщиком и акробатом JSа.
Tags:
Hubs:
+55
Comments 41
Comments Comments 41

Articles