在 django-tables2 中排序不区分大小写

Ordering case insensitive in django-tables2

第一个 post 在我很久以前阅读的这个很棒的社区中:)

我在使用这个很棒的库时遇到了问题 "django-tables2"。当我按 CharField 对列进行排序时,它会进行区分大小写的排序,从而导致如下意外行为:

Iago
Pablo
iago

我想以更自然的方式被点菜:

Iago
iago
Pablo

这是我对 table:

的简化代码
class Inquiry(models.Model):
    ...
    contact_last_name = models.CharField(max_length=50)
    ...

class Hometable(tables.Table):
    contact_last_name = tables.Column(verbose_name="Contact", order_by=('contact_last_name'))
    class Meta:
        model = Inquiry
        fields= ('contact_last_name',)

我知道在 Django 1.8 中有一个内置函数 Lower 可以使不敏感 order_by,但它不适用于 django tables:

contact_last_name = tables.Column(verbose_name="Contact", order_by=(Lower('contact_last_name')))

导致异常:

TypeError at /
    'Lower' object is not iterable

有人用 django-tables2 做过类似的事情吗?

谢谢!

更新:解决方案是在视图中使用小写字段进行注释,然后可以在 table 中进行排序。

class Inquiry(models.Model):
    ...
    contact_last_name = models.CharField(max_length=50)
    ...

class Hometable(tables.Table):
    contact_last_name = tables.Column(verbose_name="Contact", order_by=('contact_last_name_lower'))
    class Meta:
        model = Inquiry
        fields= ('contact_last_name',)

并在按照 Alasdair 的目的配置 table 时在查询集中进行适当的注释:

inquiries = inquiries.annotate(contact_last_name_lower=Lower('last_name'))
my_table = Hometable(inquiries)

我没试过这个,我对 django-tables2 也不是很熟悉,所以我不知道它是否行得通。

您可以尝试使用新的字段名称,例如contact_last_name_lower 为列设置 order_by 时。

class Hometable(tables.Table):
    contact_last_name = tables.Column(verbose_name="Contact", order_by=('contact_last_name_lower',))
    class Meta:
        model = Inquiry
        fields= ('contact_last_name',)

然后,当您实例化 table 时,用小写字段注释查询集。

queryset = Inquiry.objects.annotate(contact_last_name_lower=Lower('contact_last_name'))
table = Hometable(queryset)

https://django-tables2.readthedocs.io/en/latest/pages/ordering.html#table-order-foo-methods 的基础上,您需要添加一个 table.order_FOO() method 并以如下形式结束:

class Hometable(tables.Table):
    contact_last_name = tables.Column(verbose_name="Contact", order_by=('contact_last_name'))

    def order_contact_last_name (self, QuerySet, is_descending):
        QuerySet = QuerySet.annotate(
            field_lower=Func(F('contact_last_name '), function='LOWER')
        ).order_by(('-' if is_descending else '') + 'field_lower')
        return (QuerySet, True)

    class Meta:
        model = Inquiry
        fields= ('contact_last_name',)

当您单击 headers 列进行订购以及初始订购时,这应该有效。