2012-04-24 2 views
4

У меня есть модель Django ModelForm, которая предоставляет поле множественного выбора, соответствующее соотношению «многие ко многим», с помощью модели, которая содержит order выбора (список документов) в качестве дополнительного атрибута , В интерфейсе поле отображается в виде двух полей с несколькими полями, аналогичных тому, что указано в админах, один для отображения доступных вариантов, а другой содержит выбранные элементы.Django MultipleChoiceField не сохраняет порядок выбранных значений

Форма может быть сохранена с правильным выбором элементов, но они всегда соответствуют порядку выбора, а не выбору. Браузер отправляет выбор в правильном порядке, но заказ в form.cleaned_data['documents'] - это всегда заказ в оригинальном порядке выбора.

Как я могу заставить MultipleChoiceField соблюдать порядок выбранных элементов?

Спасибо.

+0

Если ManyToMany отношение возвращается на сервере с правильной сортировкой (через сквозную модель), то почему бы не прибегнуть его, используя подход, аналогичный [ этот вопрос] (http://stackoverflow.com/questions/3893955/django-manytomanyfield-ordering-using-through) –

+0

Спасибо за комментарий. Я хочу упорядочить элементы в порядке выбора при создании отношения на стороне сервера. Но 'cleaned_data ['documents']' не отражает порядок выбора в поле select multiple. Я могу переупорядочить использование идентификаторов в 'request.GET.getlist ('documents')', но чувствует себя взломанным. – omat

ответ

5

Нет простого способа. Вы либо должны переопределить метод cleanMultipleChoiceField, либо, как вы упомянули в своем комментарии, используйте список получателей для их повторного заказа вручную. Вероятно, это зависит от того, как часто в коде вам нужно это делать.

Метод MultipleChoiceFieldclean создает QuerySet, что вы получаете, путем фильтрации списка объектов через IN оператора, как это, так что порядок задается в базе данных:

qs = self.queryset.filter(**{'%s__in' % key: value}) 

Вы можете унаследовать от ModelMultipleChoiceField :

class OrderedModelMultipleChoiceField(ModelMultipleChoiceField): 
    def clean(self, value): 
     qs = super(OrderedModelMultipleChoiceField, self).clean(value) 
     return sorted(qs, lambda a,b: sorted(qs, key=lambda x:value.index(x.pk))) 

недостатком является то, что возвращаемое значение больше не QuerySet, но обычный список.

+1

+1 плюс 'sorted (qs, key = lambda x: value.index (x.pk))' короче – okm

+0

спасибо;) отредактировал – ticcky

0

Чтобы вернуть заказанный QuerySet при переопределении чистого метода, который вы могли бы также сделать это:

class OrderedModelMultipleChoiceField(ModelMultipleChoiceField): 
    def clean(self, value): 
     qs = super(OrderedModelMultipleChoiceField, self).clean(value) 
     clauses = ' '.join(['WHEN id=%s THEN %s' % (pk, i) for i, pk in enumerate(value)]) 
     return qs.filter(pk__in=value).extra(
      select={'ordering': 'CASE %s END' % clauses}, 
      order_by=('ordering',) 
     ) 
0

Я сделал это через виджет. Преимущество этого в том, что будет сортировать должным образом на разных языках:

class SortedSelectMultiple(SelectMultiple): 

def render_options(self, selected_choices): 
    self.choices = sorted(self.choices) 
    self.choices.sort(key=lambda x: x[1]) 
    return super(SortedSelectMultiple, self).render_options(selected_choices) 

 Смежные вопросы

  • Нет связанных вопросов^_^