![](/img/trans.png)
[英]How to filter ModelAdmin autocomplete_fields results with the context of limit_choices_to
[英]How to filter choices in Django2's autocomplete_fields?
Django 2.0,增加了autocomplete_fields ,很棒。
沒有 autocomplete_fields,我可以使用formfield_for_foreignkey更改 ForeignKeyField 的查詢集。
但是將兩者組合在一起是行不通的——自動完成選項列表似乎是動態的,並且來自不同的 url,而不是來自當前表單。
所以問題是——
如何更改自動完成小部件中的查詢集?
如果您對“self”上的ManyToManyField
使用autocomplete_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
覆蓋 ModelAdmin 的get_search_results
方法以使用您想要的查詢。 您可以在視圖的get_queryset
方法中看到它為用於獲取查詢集的自動完成字段提供數據 - 此答案的來源是https://github.com/django/django/blob/03dbdfd9bbbbd0b0172aad648c6bbe3f39541137/django/cont /admin/views/autocomplete.py#L42 。
我在某種程度上遇到了同樣的問題,當使用 autocomplete_fields 時 limit_choices_to 沒有生效,然后我為我的案例找到了一個解決方案,它也可以幫助其他人。 這是我的想法和解決方案,任何人都應該更改代碼以供他/她使用。
假設我們有兩個模型 model_A 和 modle_B:我們將覆蓋“get_search_results”
在我的例子中,model_A 的模型管理員(因為 model_B 有一個外鍵(或 m2m))我只想將選擇限制為所有 model_A 對象
當前沒有model_B 連接的對象,或者在將model_B 的對象更新為之前的model_A 對象的情況下。 所以我們去
# moodels.py
class model_A(models.Model):
name = models.CharField()
class model_B(models.Model):
name = models.CharField()
fk_field = models.OneToOneField( #ManyToManyField or ForeignKey
model_A,
related_name='fk_reverse',
on_delete=models.CASCADE)
# admin.py
class model_A_Admin(admin.ModelAdmin):
search_fields = ('name', )
def get_search_results(self, request, queryset, search_term):
import re
queryset, use_distinct = super().get_search_results(request, queryset, search_term)
# note: str(request.META.get('HTTP_REFERER')) is the url from which the request had come/previous url.
if "model_b/add/" in str(request.META.get('HTTP_REFERER')):
# if we were in creating new model_B instanse page
# note: the url is somehow containing model_Bs calss name then / then "add"
# so there is no related object(of model_A) for non exsisting object(of model_B)
queryset = self.model.objects.filter(fk_reverse=None)
elif re.search(r"model_b/\d/change/", str(request.META.get('HTTP_REFERER'))):
# if we were in updatineg page of an exsisting model_B instanse
# the calling page url contains the id of the model_B instanse
# we are extracting the id and use it for limitaion proccess
pk = int(re.findall(r'\d+', str(str(request.META.get('HTTP_REFERER')).split('/')[-3: ]))[-1])
queryset = self.model.objects.filter(fk_reverse=pk)
return queryset, use_distinct
https://gist.github.com/mh-firouzjaah/48dceae592d4b4275fa31d37ac77ff69
簡短:您可以在django-admin-autocomlete-all 中嘗試我的解決方案或制作類似的東西。
長答案:
一個痛苦是:源外鍵的 limit_choices_to-.. 也沒有實現:(
我能夠在目標 ModelAdmin 的 get_search_results() 中實現過濾器。 但在這里我們還有另一個嚴重的痛苦。 我們可以request.is_ajax and '/autocomplete/' in request.path
檢查request.is_ajax and '/autocomplete/' in request.path
。
此外,我們只有 request.headers['Referer']。 在此幫助下,我們可以將受影響的外鍵限制為 1 個模型。 但是如果我們有 2 個以上的外鍵進入同一個目標(假設:同一個模型實例中的兩個用戶角色),我們不知道其中哪一個調用了 ajax。
我的想法是修改網址。 使用請求 url 我沒有成功(經過長時間嘗試在 DOM 和 js 中查找 select2 元素並擴展 url)。
但是我在使用 window.history.replaceState() 修改 Referer url(即源管理頁面 url)方面取得了一些成功。 我可以臨時修改像/?key=author
這樣的 url - 如果您將使用django-admin-autocomplete-all ,它將始終運行,並且我可以使用額外的自定義 javascript 將幾乎所有內容添加到 Referer url 中。 特別是添加其他表單字段的當前值對於實現動態過濾(字段的依賴關系)非常有用。
所以,這是一個黑客,當然。 但是您可以嘗試 django-admin-autocomplete-all。 - 更多關於它的文檔。
您可以通過重寫 get_search_results 來修改自動完成查詢集,如下所示:
def get_search_results(self, request, queryset, search_term):
queryset, use_distinct = super().get_search_results(request, queryset, search_term)
if 'autocomplete' in request.path:
queryset = queryset.exclude(field_name='foo')
return queryset, use_distinct
這個function在admin.py里面,和你參考的model一起使用,如果autocomplete中使用的model是Bar,那么get_search_results應該在class BarAdmin(admin.ModelAdmin)
此外,如果您在多個 autocomplete_fields 中使用相同的 Model,您可以根據調用位置更改查詢集。 例子:
@admin.register(Foo)
class FooAdmin(admin.ModelAdmin):
fields = (
'the_field',
)
autocomplete_fields = ('the_field',)
@admin.register(Bar)
class BarAdmin(admin.ModelAdmin):
fields = (
'the_same_field',
)
autocomplete_fields = ('the_same_field',)
@admin.register(Key)
class KeyAdmin(admin.ModelAdmin):
fields = (
'name',
)
ordering = [
'-id',
]
search_fields = [
'name',
]
def get_search_results(self, request, queryset, search_term):
queryset, use_distinct = super().get_search_results(request, queryset, search_term)
if 'autocomplete' in request.path:
if 'foo' in request.headers['referer']:
queryset = queryset.exclude(name='foo')
elif 'bar' in request.headers['referer']:
queryset = queryset.exclude(name='bar')
return queryset, use_distinct
我們得到了 Foo 和 Bar 模型,其 ForeingKeys 為 Key Model 並與自動完成一起使用。 現在當我們打開自動完成更改 Foo 時,我們只會看到名稱等於'foo'的查詢集,同樣當我們在 Bar 中打開自動完成時,我們只會看到名稱等於'bar'的查詢集,這樣您就可以根據需要修改查詢集在哪里調用自動完成。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.