gpt4 book ai didi

python - 如何使用 limit_choices_to 的上下文过滤 ModelAdmin autocomplete_fields 结果

转载 作者:太空宇宙 更新时间:2023-11-04 04:16:20 24 4
gpt4 key购买 nike

我有一种情况,我希望利用 Django 的自动完成管理小部件,它遵守引用模型字段限制。

例如我有以下 Collection具有属性 kind 的模型具有指定的选择。

class Collection(models.Model):
...
COLLECTION_KINDS = (
('personal', 'Personal'),
('collaborative', 'Collaborative'),
)

name = models.CharField()
kind = models.CharField(choices=COLLECTION_KINDS)
...

另一个模型ScheduledCollection引用文献 CollectionForeignKey实现 limit_choices_to 的字段选项。此模型的目的是将元数据关联到 Collection针对特定用例。

class ScheduledCollection(models.Model):
...
collection = models.ForeignKey(Collection, limit_choices_to={'kind': 'collaborative'})

start_date = models.DateField()
end_date = models.DateField()
...

两种型号都注册了 ModelAdmin . Collection模型工具search_fields .

@register(models.Collection)
class CollectionAdmin(ModelAdmin):
...
search_fields = ['name']
...

ScheduledCollection模型工具autocomplete_fields

@register(models.ScheduledCollection)
class ScheduledCollectionAdmin(ModelAdmin):
...
autocomplete_fields = ['collection']
...

这有效但并不完全符合预期。自动完成从 Collection 生成的 View 中检索结果模型。 limit_choices_to不过滤结果,仅在保存时强制执行。

建议实现get_search_resultsget_querysetCollectionAdmin 上模型。我能够做到这一点并过滤结果。但是,这会改变 Collection全面的搜索结果。我不知道如何在 get_search_results 中获得更多上下文或 get_queryset根据关系有条件地过滤结果。

就我而言,我希望 Collection 有多种选择和几个不同的元模型 limit_choices_to选项并让自动完成功能遵守这些限制。

我不希望它自动运行,也许这应该是一个功能请求。在这一点上,我不知道如何根据选择限制(或任何条件)过滤自动完成的结果。

不使用 autocomplete_fields Django 管理员的默认 <select>小部件过滤结果。

最佳答案

触发 http referer 很丑陋,所以我做了一个更好的版本:子类化 AutocompleteSelect 并发送额外的查询参数以允许 get_search_results 自动查找正确的 limit_choices_to。只需将此 mixin 包含在您的 ModelAdmin 中(对于源模型和目标模型)。作为奖励,它还增加了 ajax 请求的延迟,因此您在输入过滤器时不会向服务器发送垃圾邮件,使选择更宽并设置 search_fields 属性(对我的系统正确的'translations__name',自定义你的或省略并像以前一样在 ModelAdmins 上单独设置):

from django.contrib.admin import widgets
from django.utils.http import urlencode
from django.contrib.admin.options import ModelAdmin

class AutocompleteSelect(widgets.AutocompleteSelect):
"""
Improved version of django's autocomplete select that sends an extra query parameter with the model and field name
it is editing, allowing the search function to apply the appropriate filter.
Also wider by default, and adds a debounce to the ajax requests
"""

def __init__(self, rel, admin_site, attrs=None, choices=(), using=None, for_field=None):
super().__init__(rel, admin_site, attrs=attrs, choices=choices, using=using)
self.for_field = for_field

def build_attrs(self, base_attrs, extra_attrs=None):
attrs = super().build_attrs(base_attrs, extra_attrs=extra_attrs)
attrs.update({
'data-ajax--delay': 250,
'style': 'width: 50em;'
})
return attrs

def get_url(self):
url = super().get_url()
url += '?' + urlencode({
'app_label': self.for_field.model._meta.app_label,
'model_name': self.for_field.model._meta.model_name,
'field_name': self.for_field.name
})
return url


class UseAutocompleteSelectMixin():
"""
To avoid ForeignKey fields to Event (such as on ReportColumn) in admin from pre-loading all events
and thus being really slow, we turn them into autocomplete fields which load the events based on search text
via an ajax call that goes through this method.
Problem is this ignores the limit_choices_to of the original field as this ajax is a general 'search events'
without knowing the context of what field it is populating. Someone else has exact same problem:
https://stackoverflow.com/questions/55344987/how-to-filter-modeladmin-autocomplete-fields-results-with-the-context-of-limit-c
So fix this by adding extra query parameters on the autocomplete request,
and use these on the target ModelAdmin to lookup the correct limit_choices_to and filter with it.
"""

# Overrides django.contrib.admin.options.ModelAdmin#formfield_for_foreignkey
# Is identical except in case db_field.name is in autocomplete fields it constructs our improved AutocompleteSelect
# instead of django's and passes it extra for_field parameter
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name in self.get_autocomplete_fields(request):
db = kwargs.get('using')
kwargs['widget'] = AutocompleteSelect(db_field.remote_field, self.admin_site, using=db, for_field=db_field)
if 'queryset' not in kwargs:
queryset = self.get_field_queryset(db, db_field, request)
if queryset is not None:
kwargs['queryset'] = queryset

return db_field.formfield(**kwargs)

return super().formfield_for_foreignkey(db_field, request, **kwargs)

# In principle we could add this override in a different mixin as adding the formfield override above is needed on
# the source ModelAdmin, and this is needed on the target ModelAdmin, but there's do damage adding everywhere so combine them.
def get_search_results(self, request, queryset, search_term):
if 'app_label' in request.GET and 'model_name' in request.GET and 'field_name' in request.GET:
from django.apps import apps
model_class = apps.get_model(request.GET['app_label'], request.GET['model_name'])
limit_choices_to = model_class._meta.get_field(request.GET['field_name']).get_limit_choices_to()
if limit_choices_to:
queryset = queryset.filter(**limit_choices_to)
return super().get_search_results(request, queryset, search_term)

search_fields = ['translations__name']

关于python - 如何使用 limit_choices_to 的上下文过滤 ModelAdmin autocomplete_fields 结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55344987/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com