8

我正在显示一个模型表单集,我希望表单按其中一个字段的内容进行排序。所以我想SomeModel.objects.filter(whatever).order_by('somefield')在模板中使用(模型)表单集的等价物。

我怎样才能做到这一点?

请注意,can_order它不会做我想要的(它必须是自动的,而不是用户指定的)。我也尝试过其他的东西,比如 dictsort 过滤器,但这会产生不可预测的输出(即不按指定字段排序)。

我什至尝试过{% regroup formset by somefield as sorted_formset %},但结果sorted_formset不能用作(迭代)普通表单集。

4

5 回答 5

7

完成答案。有两种方法可以控制表单集中表单的顺序:表单集尊重给定查询集的顺序(这在其他回复中显示)。另一种方法(如果您想完全控制表单的顺序)是定义自定义表单集类和覆盖__iter____getitem__方法:

from django.forms import BaseModelFormSet

class MyModelBaseFormset(BaseModelFormSet):
    def __iter__(self):
        """Yields the forms in the order they should be rendered"""
        return ...

    def __getitem__(self, index):
        """Returns the form at the given index, based on the rendering order"""
        return ...


MyModelFormset = modelformset_factory(model=MyModel, formset=MyModelBaseFormset, queryset=...)

这种方法在 Django 文档中有描述:

遍历表单集将按照表单创建的顺序呈现表单。您可以通过为该方法提供替代实现来更改此顺序__iter__()

表单集也可以被索引,返回相应的表单。如果您 override __iter__,您还需要 override __getitem__以具有匹配的行为。

https://docs.djangoproject.com/en/dev/topics/forms/formsets/#django.forms.formsets.BaseFormSet

实现这些方法的示例例如在这个 SO 线程中:modelformset __iter__ 重载问题

于 2017-05-03T20:33:27.560 回答
7

如果您没有定义 Formset,这是“内联代码”版本:

FS=inlineformset_factory(ParentClass,ChildClass)
formset=FS(instance=parentobject,
           queryset=parentobject.childobject_set.order_by("-time_begin")
          )
于 2015-08-05T14:54:02.563 回答
5

感谢上面的@john-peters 回答,为我指明了正确的方向。但这里有一个更好的方法:

MyFormset(inlineformset_factory(...)):

  def get_queryset(self):
    return super(MyFormset, self).get_queryset().order_by('myfieldname')

这样你就不必复制或弄乱 django 的代码,也不必在路上造成损坏。只需使用 django 给你的查询集并覆盖排序。我在自己的代码中使用了它,它可以工作。

编辑。经过一番研究,我意识到虽然它看起来工作正常,但它以某种方式弄乱了 BaseInlineFormset.get_queryset() 中的逻辑,导致重复的数据库查询。但是,希望有人对此发表评论并纠正它,我将把它留在这里。同时,我有另一个解决方案,它可以工作并且不会导致冗余查询..如下:

MyFormset(inlineformset_factory(...)):
    def __init__(self, *args, **kwargs):
        super(MyFormset, self).__init__(*args, **kwargs)
        self.queryset = self.queryset.order_by('myfieldname')

这会在安全时间修改查询集,然后再对其进行任何操作。在我的代码中,我也在此处执行 .select_related(),这大大加快了我的大型模型表单集的速度!

于 2015-06-17T18:49:11.570 回答
3

感谢rantanplan的评论,我找到了解决方案。我无法使用上面链接中描述的方法,因为我不知道查询集将是什么(这是一个带有嵌套表单集的复杂表单)。

无论如何,我通过覆盖 Django 的 BaseInlineFormSet 类的 get_queryset 方法找到了解决方案。我在下面复制了它,包括我的 mod,以防 googlers 发现它有帮助。

def get_queryset(self):
    '''
    Copied this method from Django code and modified the ordering statement
    '''
    if not hasattr(self, '_queryset'):
        if self.queryset is not None:
            qs = self.queryset
        else:
            qs = self.model._default_manager.get_query_set()

        # If the queryset isn't already ordered we need to add an
        # artificial ordering here to make sure that all formsets
        # constructed from this queryset have the same form order.
        if not qs.ordered:
# MY MOD IS HERE:
#            qs = qs.order_by(self.model._meta.pk.name)
            qs = qs.order_by('order_index')
#/MOD

        # Removed queryset limiting here. As per discussion re: #13023
        # on django-dev, max_num should not prevent existing
        # related objects/inlines from being displayed.
        self._queryset = qs
    return self._queryset
于 2012-11-16T03:04:28.880 回答
1

一种更简单的方法,但它可能不适用于所有情况,但如果你能负担得起,只需在模型 Meta 类中定义排序:

class ExampleModel(models.Model):
     ...
     class Meta:
          ordering = ("name", )

Formset 将尊重查询集的排序,这将尊重 Meta 类变量的值。

于 2020-01-03T06:08:42.793 回答