web-dev-qa-db-ja.com

Django autocomplete_fieldsで選択肢をフィルタリングする方法は?

Django 2.0、 autocomplete_fields が追加されました。これはすばらしいことです。

Autocomplete_fieldsがない場合、 formfield_for_foreignkey を使用してForeignKeyFieldのクエリセットを変更できます。

ただし、この2つを組み合わせても機能しません。オートコンプリートのオプションのリストは動的であり、現在のフォームではなく別のURLから取得されているようです。

だから問題は-

オートコンプリートウィジェットでクエリセットを変更するにはどうすればよいですか?

14
Oren Shpigel

ModelAdminの get_search_results メソッドをオーバーライドして、必要なクエリを使用します。オートコンプリートフィールドのデータを提供するビューのget_querysetメソッドで、クエリセットの取得に使用されていることがわかります-この回答のソースは https://github.com/Django/django /blob/03dbdfd9bbbbd0b0172aad648c6bbe3f39541137/Django/contrib/admin/views/autocomplete.py#L42

3
Peter DeGlopper

'self'のManyToManyFieldautocomplete_fieldsを使用している場合、この例では現在のオブジェクトが除外されます。

get_form をオーバーライドして、現在のオブジェクトのIDを取得します。

field_for_autocomplete = None

def get_form(self, request, obj=None, **kwargs):
    if obj:
        self.field_for_autocomplete = obj.pk

    return super(MyAdmin, self).get_form(request, obj, **kwargs)

次に、get_search_resultsをオーバーライドします。モデルのオートコンプリートURIに対してのみクエリセットを変更します。

def get_search_results(self, request, queryset, search_term):
    queryset, use_distinct = super().get_search_results(request, queryset, search_term)

    # Exclude only for autocomplete
    if request.path == '/admin/myapp/mymodel/autocomplete/':
        queryset = queryset.exclude(field=self.field_for_autocomplete)

    return queryset, use_distinct
3
Mike

短い: Django-admin-autocomlete-all で私のソリューションを試すか、同様のものを作成できます。

長い答え:

1つの問題は次のとおりです。ソース外部キーのlimit_choices_to- ..も実装されていません:(

ターゲットModelAdminのget_search_results()にフィルターを実装することができました。しかし、ここには別の深刻な痛みがあります。 request.is_ajax and '/autocomplete/' in request.pathを確認できます。

さらに、request.headers ['Referer']しかありません。これを利用して、影響を受ける外部キーを1つのモデルに制限できます。しかし、同じターゲットに2つ以上の外部キーがある場合(たとえば、同じモデルインスタンス内の2つのユーザーロール)、どちらがajaxを呼び出すかはわかりません。

私のアイデアは、URLを変更することでした。 Request urlでは成功しませんでした(DOMとjsでselect2要素を見つけてURLを拡張しようと長い間試みた後)。

しかし、window.history.replaceState()を使用してリファラーURL(つまり、ソース管理ページのURL)を変更することである程度の成功を収めています。 /?key=authorのようなURLを一時的に変更できます。これは、Django-admin-autocomplete-allを使用する場合は常に実行され、次のことができます。追加のカスタムJavaScriptを使用して、ほとんどすべてをリファラーURLに追加します。特に、他のフォームフィールドの現在の値を追加すると、動的フィルタリング(フィールドの依存関係)を実装するのに役立つ場合があります。

だから、それは確かにハックです。ただし、Django-admin-autocomplete-allを試してみることができます。 -それのドキュメントでもっと。

1
mirek