如何为models.ManyToManyField输出django.forms.SelectMultiple,以使现有关系呈现有序?

时间:2018-08-01 22:25:38

标签: python django django-models django-forms django-widget

我正在使用django-1.9和select2使我的用户能够选择,创建和排序他们书籍中的章节和图像数据之间的关系。

models.py

class Section(django.Model):
    title = models.CharField(max_length=500)
    parent = models.ForeignKey('self', related_name='subsections', null=True, blank=True)
    phrases = models.ManyToManyField(Image, through=ImageOrdering, blank=True, related_name='sections')

class Image(models.Model):
    name = models.CharField()

class ImageOrdering(models.Model):
    section = models.ForeignKey('Section', on_delete=models.CASCADE)
    image = models.ForeignKey('Image', on_delete=models.CASCADE)
    order = models.IntegerField()

    class Meta:
        ordering = ['order', ]

forms.py

class SortedSelectMultiple(forms.SelectMultiple):
    def render(self, name, value, attrs=None, choices=()):
        """ The selected values need to be rendered sorted and last. """
        choices = list((image.pk, str(image)) for image in Image.objects.filter(id__in=value))
        choices.sort(key=lambda image: value.index(int(image[0])))
        self.choices.queryset = Images.objects.exclude(id__in=value)
        return super(SortedSelectMultiple, self).render(name, value, attrs, choices)

class SectionForm(forms.ModelForm):
    class Meta:
        model = Section
        fields = ('title', 'images')
        widgets = {
            'title': forms.TextInput(attrs={'class': 'form-control'}),
            # 'images': forms.SelectMultiple(attrs={'class': 'form-control select2-multiple-sortable'}),
            'images': SortedSelectMultiple(attrs={'class': 'form-control select2-multiple-sortable'}),
        }

    def save(self, commit=True):
        """ All this hackery to preserve the order. """
        this = super(SectionForm, self).save(False)
        if commit:
            this.save()
            self.instance.images.clear()
            sort_order = dict(self.data).get('images')
            images = list(self.cleaned_data['images'])
            images.sort(key=lambda image: sort_order.index(str(image.pk)))
            for index, image in enumerate(images):
                ordering, created = ImageOrdering.objects.get_or_create(image=image, section=self.instance, order=index)
                ordering.save()
            return self.instance

我发现这是保留用户拖放元素后Select2给其元素的顺序的唯一方法。元素的DOM顺序用于确定顺序。为此,我必须在呈现表单时保留它。

我觉得我在这里做的事非常丑陋,而且至少不是Pythonic,但是整整一整天的头发我找不到理智的解决方案。也许我想要达到的目的(选项的顺序)是错误的方法?

0 个答案:

没有答案