8

3 つの ForeignKey フィールドを持つ単純なモデルがあります。

class Car(models.Model):
    wheel = models.ForeignKey('Wheel', related_name='wheels')
    created = models.DateTimeField(auto_now_add=True)
    max_speed = models.PositiveSmallIntegerField(null=True)
    dealer = models.ForeignKey('Dealer')
    category = models.ForeignKey('Category')

django admin のリスト ビューでは、4 つのクエリを取得します。それらの 1 つは、3 つの INNER JOINS を使用する SELECT です。その1つのクエリは遅くなります。INNER JOIN を STRAIGHT_JOIN に置き換えると、問題が解決します。管理者が生成したクエリが評価される直前にパッチを適用する方法はありますか?

4

7 に答える 7

1

わかりました。管理者が生成したクエリにパッチを適用する方法を見つけました。それは醜いですが、うまくいくようです

class CarChangeList(ChangeList):

    def get_results(self, request):
        """Override to patch ORM generated SQL"""
        super(CarChangeList, self).get_results(request)
        original_qs = self.result_list
        sql = str(original_qs.query)
        new_qs = Car.objects.raw(sql.replace('INNER JOIN', 'STRAIGHT_JOIN'))

        def patch_len(self):
           return original_qs.count()
        new_qs.__class__.__len__ = patch_len

        self.result_list = new_qs


class CarAdmin(admin.ModelAdmin):

    list_display = ('wheel', 'max_speed', 'dealer', 'category', 'created')

    def get_changelist(self, request, **kwargs):
        """Return custom Changelist"""
        return CarChangeList

admin.site.register(Rank, RankAdmin)
于 2013-04-12T18:50:08.853 に答える
1

Django admin (バージョン 1.4.9) で同じ問題に遭遇しました。MySQL を使用すると、かなり単純な管理リスト ページが非常に遅くなります。

私の場合は、フィールドが多対 1 の関係である場合に、クエリ セットにChangeList.get_query_set()過度に広範なグローバルを追加するメソッドが原因でした。適切なデータベース (咳 PostgreSQL 咳) の場合、これは問題になりませんが、MySQL の場合は、この方法でいくつかの結合がトリガーされたことがありました。select_related()list_display

私が見つけた最もクリーンな解決策は、グローバルselect_related()ディレクティブを、本当に必要なテーブルのみを結合する、よりターゲットを絞ったディレクティブに置き換えることでした。select_related()これは、明示的な関係名で呼び出すことで簡単に実行できました。

このアプローチは、複数のフォローアップ クエリのデータベース内結合を交換することになる可能性がありますが、MySQL が大きなクエリを処理している場合、多くの小さなクエリの方が高速である可能性があります。

多かれ少なかれ、私がしたことは次のとおりです。

from django.contrib.admin.views.main import ChangeList


class CarChangeList(ChangeList):

    def get_query_set(self, request):
        """
        Replace a global select_related() directive added by Django in 
        ChangeList.get_query_set() with a more limited one.
        """
        qs = super(CarChangeList, self).get_query_set(request)
        qs = qs.select_related('wheel')  # Don't join on dealer or category
        return qs


class CarAdmin(admin.ModelAdmin):

        def get_changelist(self, request, **kwargs):
            return CarChangeList
于 2014-02-20T17:17:45.343 に答える