Django 按顺序连接两个查询集

Posted

技术标签:

【中文标题】Django 按顺序连接两个查询集【英文标题】:Django Concatenate Two Querysets IN ORDER 【发布时间】:2018-03-06 15:03:35 【问题描述】:

所以我有一个带有选择字段的 ModelForm。在此选择字段中,大约有 100 个条目。在这些条目中,我有许多条目,例如“科罗拉多组织 - 丹佛”,我希望将它们放在列表顶部,这样所有带有“科罗拉多组织”的条目都位于列表顶部,并且所有内容else 按字典顺序排序。

我尝试过创建两个单独的查询集(这似乎是个坏主意,但只需 100 个左右的条目即可管理)。似乎有很多方法可以组合这两个查询集,但不保持顺序(这是重点)。我试过这个:

class CreateContactForm(ModelForm):
    ...

    def __init__(self, *args, **kwargs):
        super(CreateContactForm, self).__init__(*args, **kwargs)
        p = models.ConstantContactList.objects.filter(
            name__startswith=settings.PREF_ORGANIZATION_PREFIX
        )
        np = models.ConstantContactList.objects.filter(
            name__regex=r'^(?!)'.format(settings.PREF_ORGANIZATION_PREFIX)
        ).order_by('-name')

        self.fields['cc_lists'].queryset = list(p) + list(np)

这不起作用,尽管它可能,如果有某种方法可以将该列表转换回查询集,或者是否有一种方法可以绕过查询集?我不知道。任何人都可以提供关于我应该做什么的线索吗?

【问题讨论】:

你试过没有这两个list coersions吗?我现在无法访问 Django 进行测试,但它可能只是在 SQL 中创建一个 UNION() 来组合两个查询集 pnp @C14L unsupported operand type(s) for +: 'QuerySet' and 'QuerySet' 【参考方案1】:

我建议不要尝试对查询集进行排序,而只在渲染层(模板或表单)中处理排序。这样,如果您想本地化您的代码,您就不必更改查询。

假设您使用 forms.Select 小部件。您可能希望从此小部件继承并覆盖 render_menu 逻辑,以便自己构建它并自己处理排序。您将可以访问已渲染或未渲染的选项,因此从那时起它不应该成为问题。

【讨论】:

我会调查一下,这似乎更合理。【参考方案2】:

好的。我想出了一个适用于这里的解决方案,并且我正在将它提供给有相同需求的任何其他人。

from django.forms.widgets import Select
import re

class CustomOrderingWidget(Select):
    def __init__(self, priority_regex, sort='+', attrs=None):
        super(CustomOrderingWidget, self).__init__(attrs)
        self.regex = re.compile(priority_regex)
        self.sort = sort
        self.template_name = 'django/forms/widgets/select.html'

    def render(self, name, value, attrs=None, renderer=None):
        context = self.get_context(name, value, attrs)
        optgroups = context.get('widget').get('optgroups')
        firsts, others = [], []
        for grp in optgroups:
            if self.regex.search(grp[1][0].get('label')):
                firsts.append(grp)
            else:
                others.append(grp)
        if self.sort == '+':
            kfn = lambda x: x[1][0].get('label')
            context['widget']['optgroups'] = sorted(firsts, key=kfn) +\
                                               sorted(others, key=kfn)
        elif self.sort == '-':
            kfn = lambda x: x[1][0].get('label')
            context['widget']['optgroups'] =\
                sorted(firsts, key=kfn, reverse=True) +\
                sorted(others, key=kfn, reverse=True)
        else:
            context['widget']['optgroups'] = firsts + others
        return self._render(self.template_name, context, renderer)

然后你可以将它插入到这样的 ModelForm 中......

import settings # YOUR personal stuffz!

class CreateContactForm(ModelForm):
    ...
    class Meta:
       ...
        widgets = 
            # Just an example, make your own regex string!  
            'cc_lists': CustomOrderingWidget("^0".format(
                settings.PREF_ORGANIZATION_PREFIX
            ))
        

【讨论】:

以上是关于Django 按顺序连接两个查询集的主要内容,如果未能解决你的问题,请参考以下文章

Django:更新查询集中对象的顺序属性

按特定顺序更新查询集

在 Django 模型查询中按顺序排列的原始 SQL

在django模板中按id的顺序显示查询集及其外键

如何以正确的顺序链接查询集,而不是按日期排序,按foreignKey排序?

Django - 如何在页面上更改搜索结果的排序顺序?