当前,在我的Django管理员模型视图之一中,我能够按照数据库中的可用状态分别选择多个可用国家(申请国):
但是,当我实际上只与少数几个国家/地区小组一起工作时,这非常烦人。但是我确实需要添加或减去奇数国家,而无需管理和考虑每个国家组的类别名称。
我当时的想法是使用关键字(在应用程序中还可以用于其他目的)
我想做的是通过admin.ModelAdmin
添加一个自定义字段,该字段也是autocomplete_field
,在下拉列表中显示与国家/地区相关的关键字。如果选择了该下拉菜单中的一个项目,它将向模型字段(适用国家/地区)返回带有所选关键字的国家/地区的查询集。无需保存其他任何内容,无需跟踪过去使用了哪个与国家/地区相关的关键字。这只是一次批量选择多个国家/地区的快捷方式(因此,添加/修改后,自定义字段始终显示为空)。
我想尽可能地以Django admin的方式进行操作,而不用碰触自定义HTML之类的事情。如果无法做到这一点,我将探索涉及Django-Q任务的解决方案。
下面是一些解释这些关系的代码:
models.py->关键字:
class Keyword(models.Model):
name = models.TextField()
models.py->国家/地区:
class Country(models.Model):
"""
More info: https://en.wikipedia.org/wiki/ISO_3166-1
"""
name = models.TextField()
alpha_2_code = models.CharField(max_length=2)
alpha_3_code = models.CharField(max_length=3)
independent = models.BooleanField()
keywords = models.ManyToManyField(Keyword)
models.py-> FundingProgram
class FundingProgram(models.Model):
# Unimportant fields redacted
applicant_countries = models.ManyToManyField(Country, blank=True)
admin.py-> FundingProgramAdmin
@admin.register(models.FundingProgram)
class FundingProgramAdmin(admin.ModelAdmin, DynamicArrayMixin):
autocomplete_fields = (
"applicant_countries",
)
search_fields = (
"applicant_countries__keywords__name",
)
# Here is where I think I should make a custom field,
# that acts as a multiple choice (autocomplete) dropdown where
# a function takes input and returns a quryset to applicant_countries field
答案 0 :(得分:0)
我设法使用Django Autocomplete Light库解决了这个问题。
这就是我所做的(仅在此处包括相关的补充内容,请阅读有关如何安装该库的文档,等等)。
from dal import autocomplete
from my_app import models
class KeywordsSelect(autocomplete.Select2QuerySetView):
def get_queryset(self):
if not self.request.user.is_authenticated:
return models.Keyword.objects.none()
qs = models.Keyword.objects.all()
if self.q:
# Todo: Probably worth sorting the queryset for consistency
qs = qs.filter(name__istartswith=self.q)
return qs
def get_result_value(self, result):
return result.pk
class CountriesSelect(autocomplete.Select2QuerySetView):
def get_queryset(self):
if not self.request.user.is_authenticated:
return models.Country.objects.none()
qs = models.Country.objects.all()
if self.q:
# Todo: Probably worth sorting the queryset for consistency
qs = qs.filter(name__istartswith=self.q)
return qs
def get_result_value(self, result):
return result.pk
from django.conf.urls import url
from my_app import views
urlpatterns = [
url(r"^keywords-select/$", views.KeywordsSelect.as_view(), name="keywords-select",),
url(r"^countries-select/$", views.CountriesSelect.as_view(), name="countries-select",),
]
上面创建了一个端点,可以像这样查询端点:http://localhost:8000/countries-select/?q=Austri
,并返回如下输出:
{
"results": [
{
"id": 9,
"text": "Austria",
"selected_text": "Austria"
}
],
"pagination": {
"more": false
}
}
现在,我们可以修改admin以包括修改后的表单,该表单将在自动选择框中调用此端点。下面请注意,我需要明确列出所有字段,并使两个字段并排存在,它们必须包含在自己的元组("applicant_countries", "bulk_add_countries_by_keyword",)
中。
from dal import autocomplete
from django import forms
class FundingProgramForm(forms.ModelForm):
# Newly created field not retrieved from models.py
bulk_add_countries_by_keyword = forms.ModelMultipleChoiceField(
queryset=models.Keyword.objects.all(),
widget=autocomplete.ModelSelect2Multiple(url="keywords-select"),
required=False,
)
class Meta:
# applicant_countries is a field from models.py which gets overridden here
widgets = {
"applicant_countries": autocomplete.ModelSelect2Multiple(
url="countries-select"
)
}
def save(self, commit=True):
qs = self.cleaned_data["applicant_countries"].union(
models.Country.objects.filter(
keywords__in=self.cleaned_data["bulk_add_countries_by_keyword"]
)
)
self.cleaned_data["applicant_countries"] = qs
return super(FundingProgramForm, self).save(commit=commit)
@admin.register(models.FundingProgram)
class FundingProgramAdmin(admin.ModelAdmin):
form = FundingProgramForm
# Other fields hardcoded below, otherwise they won't appear in model form
fields = (
("applicant_countries", "bulk_add_countries_by_keyword",),
)
# Warning: Remove the following from autocomplete_fields, as it is already overidden with a django autocomplete light widget
# autocomplete_fields = (
# "applicant_countries",
# )