django管理员错误地将订单添加到查询中

Cri*_*lho 8 python mysql django django-admin

I have noticed thanks to django debug toolbar, that every django admin list page, always add an "ORDER BY id DESC" to all my queries, EVEN if I manually override the get_queryset method of the admin.ModelAdmin (which I usually do because I want custom sorting on some of my admin pages)

I guess this is not really something to worry about, but it is an additional sorting operation the database will need to do, even if it doesn't make sense at all.

Is there any way to prevent this? It seems like on some models (even that, not on all) if I add the ordering meta data, then it won't automatically add an order by by id, but it will however add by that field, which is something also I don't want, because doing so would add that order by to all my other queries across the code.

编辑:似乎罪魁祸首是在ChangeList的django.contrib.admin.views.main,在第316行的函数get_ordering(django 1.7.10)

 pk_name = self.lookup_opts.pk.name
    if not (set(ordering) & set(['pk', '-pk', pk_name, '-' + pk_name])):
        # The two sets do not intersect, meaning the pk isn't present. So
        # we add it.
        ordering.append('-pk')
Run Code Online (Sandbox Code Playgroud)

我想知道这背后的原因是什么......

编辑:为了提高性能,并且由于MySQL(和InnoDB)在没有给出order by时以聚簇索引顺序返回数据,我可以安全地删除该id附加.要做到这一点,这很容易,我刚刚扩展了django的ChangeList并修改了get_ordering方法.之后,只需创建一个自定义的管理模型,该模型从ModelAdmin扩展并覆盖get_changelist方法以重新转换上述类.

我希望它可以帮助任何人:)

7wo*_*ers 4

遇到与此问题完全相同的问题,当我已经有唯一的排序时,由于 ID 排序,管理查询集速度慢了 4 倍。感谢@user1777914 和他的工作,我没有每次加载都超时!如果其他人也遇到同样的问题,我只是为了清楚起见而在此处添加这个答案。正如 user1777914 提到的扩展 ChangeList:

class NoPkChangeList(ChangeList):
    def get_ordering(self, request, queryset):
        """
        Returns the list of ordering fields for the change list.
        First we check the get_ordering() method in model admin, then we check
        the object's default ordering. Then, any manually-specified ordering
        from the query string overrides anything. Finally, WE REMOVE the primary
        key ordering field.
        """
        params = self.params
        ordering = list(self.model_admin.get_ordering(request) or self._get_default_ordering())
        if ORDER_VAR in params:
            # Clear ordering and used params
            ordering = []
            order_params = params[ORDER_VAR].split('.')
            for p in order_params:
                try:
                    none, pfx, idx = p.rpartition('-')
                    field_name = self.list_display[int(idx)]
                    order_field = self.get_ordering_field(field_name)
                    if not order_field:
                        continue  # No 'admin_order_field', skip it
                    # reverse order if order_field has already "-" as prefix
                    if order_field.startswith('-') and pfx == "-":
                        ordering.append(order_field[1:])
                    else:
                        ordering.append(pfx + order_field)
                except (IndexError, ValueError):
                    continue  # Invalid ordering specified, skip it.

        # Add the given query's ordering fields, if any.
        ordering.extend(queryset.query.order_by)

        # Ensure that the primary key is systematically present in the list of
        # ordering fields so we can guarantee a deterministic order across all
        # database backends.
        # pk_name = self.lookup_opts.pk.name
        # if not (set(ordering) & {'pk', '-pk', pk_name, '-' + pk_name}):
        #     # The two sets do not intersect, meaning the pk isn't present. So
        #     # we add it.
        #     ordering.append('-pk')

        return ordering
Run Code Online (Sandbox Code Playgroud)

然后在你的 ModelAdmin 中覆盖 get_changelist:

class MyAdmin(ModelAdmin):
    def get_changelist(self, request, **kwargs):
        return NoPkChangeList
Run Code Online (Sandbox Code Playgroud)