web-dev-qa-db-ja.com

Django管理者にselect_relatedを使用させる方法は?

私のモデルの1つは特に複雑です。 Django Adminで編集しようとすると、1042クエリが実行され、処理に9秒以上かかります。

ドロップダウンのいくつかを_raw_id_fields_に置き換えることができることは知っていますが、より大きなボトルネックは、select_related()が正常に実行されていないことだと思います。

管理サイトにこれを実行させることはできますか?

26
mpen

Dr jimbobの答えは理にかなっていますが、私のニーズでは、外部キーの外部キーを選択する場合でも、get_queryset()メソッドをワンライナーでオーバーライドすることができました。多分これは誰かに役立つかもしれません。

class MyModelAdmin(admin.ModelAdmin):
    model = MyModel
    ...
    def get_queryset(self, request):
        return super(MyModelAdmin, self).get_queryset(request).select_related(
            'foreign_key1', 'foreign_key2__fk2_foreign_key')
31
Cloud Artisans

あなたはこれを試すことができます

class Foo(admin.ModelAdmin):
    list_select_related = (
        'foreign_key1',
        'foreign_key2',
    )

https://docs.djangoproject.com/en/dev/ref/contrib/admin/#Django.contrib.admin.ModelAdmin.list_select_related

19
runforever

私の特定のモデルでは、フォームに表示されているときにForeignKeysを通過するのが特に遅いので、select_relatedを使用して呼び出されないので、これを高速化します。

関連するDjangoソースを見ると、Django/contrib/admin/options.pyでメソッドformfield_for_foreignkeysが各FKdb_fieldを受け取り、ForeignKeyクラスを呼び出すことがわかります。 formfieldメソッド。Django/ db/models/fields/related /で定義されています。

def formfield(self, **kwargs):
    db = kwargs.pop('using', None)
    defaults = {
        'form_class': forms.ModelChoiceField,
        'queryset': self.rel.to._default_manager.using(db).complex_filter(self.rel.limit_choices_to),
        'to_field_name': self.rel.field_name,
    }
    defaults.update(kwargs)
    return super(ForeignKey, self).formfield(**defaults)

これから、db_fieldkwargs['queryset']を提供するかどうかを確認し、select_relatedを使用するカスタムクエリセットを定義できます(これはformfield_for_foreignkeyで提供できます)。

したがって、基本的には、admin.ModelAdminSelectRelatedModelAdminでオーバーライドしてから、ModelAdminサブクラスをadmin.ModelAdminではなくSelectRelatedModelAdminにします。

class SelectRelatedModelAdmin(admin.ModelAdmin):
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if 'queryset' in kwargs:
            kwargs['queryset'] = kwargs['queryset'].select_related()
        else:
            db = kwargs.pop('using', None)
            kwargs['queryset'] = db_field.rel.to._default_manager.using(db).complex_filter(db_field.rel.limit_choices_to).select_related()
        return super(SelectRelatedModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

このコードサンプルは、admin InlinesまたはManyToManyFields、またはreadonly_fieldsまたはカスタムselect_relatedクエリによって呼び出される関数のforeign_keyトラバーサルをカバーしていませんが、同様のアプローチがこれらの場合に機能するはずです。

11
dr jimbob

Django 2.0+では、ForeignKeyとManyToManyの関係のパフォーマンスを向上させる良い方法は、 オートコンプリートフィールド を使用することです。

これらのフィールドには、関連するすべてのオブジェクトが表示されるわけではないため、より少ないクエリで読み込まれます。

5
YPCrumble