How can I create an advanced custom search form in Django admin and use Django admins change list display. My advanced search form has several fields, including:
如何在Django admin中创建高级自定义搜索表单并使用Django管理员更改列表显示。我的高级搜索表单有几个字段,包括:
- region
- city
- province
admin.py:
class PropertyAdmin(ModelAdmin):
change_list_template = "property/admin/property_change_list.html"
list_per_page = 20
list_display_links = ('property_country_province_city',)
search_fields = ('id',)
list_filter = ('is_sale','is_rent','is_presales','estate_type','water')
list_display_links = ('property_type',)
Models.py
class Property(models.Model):
objects = PublicPropertyManager()
title = models.CharField(_("title"), max_length = 80, blank=True)
country = models.ForeignKey(Country, verbose_name=_("Country"))
province = models.ForeignKey(Province, verbose_name=_("Province"))
city = models.ForeignKey(City, verbose_name=_("City"))
region = models.ForeignKey(Region, verbose_name=_("Region"))
address = models.CharField(
verbose_name=_("address"), max_length = 250, blank=True, null=True
)
2 个解决方案
#1
2
class CandidateAdmin(admin.ModelAdmin):
formfield_overrides = {
models.TextField: {'widget': Textarea(attrs={'rows': 4, 'cols': 40})},
}
list_display = ('id', 'first_name', 'last_name', 'current_company',
'title', 'gender', 'country', 'status', 'consultant',
'mobile_number', 'civil_reg_number', 'added_date')
list_display_links = ('id', 'first_name', 'last_name')
list_filter = ('consultant', 'status', 'gender', 'country', 'city')
form = CandidateForm
advanced_search_form = AdvancedSearchForm()
other_search_fields = {}
search_fields = ['first_name', 'last_name', 'civil_reg_number',
'status', 'cvmn', 'cven',
'address', 'mobile_number', 'notes']
actions = [recruited_by_scc]
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'consultant':
kwargs['initial'] = Consultant.objects.get(user=request.user)
return db_field.formfield(**kwargs)
return super(CandidateAdmin, self).\
formfield_for_foreignkey(db_field, request, **kwargs)
def changelist_view(self, request, extra_context=None, **kwargs):
extra_context = {'asf':self.advanced_search_form}
request.POST._mutable=True
post_keys = []
search_keys = []
for key in request.POST.keys():
value=request.POST.get(key)
if value!='' and key!='csrfmiddlewaretoken':
post_keys.append(key)
for key in self.other_search_fields.keys():
value = [x for x in self.other_search_fields.get(key) if x!='']
if value:
search_keys.append(key)
if post_keys!=search_keys and len(post_keys)>0 and len(search_keys)>0:
self.other_search_fields = {}
for key in self.advanced_search_form.fields.keys():
try:
temp = request.POST.pop(key)
except KeyError:
pass
else:
if temp!=['']:
self.other_search_fields[key] = temp
request.session[request.user.username] = self.other_search_fields
self.other_search_fields = {}
request.POST._mutable=False
return super(CandidateAdmin, self).changelist_view(request, extra_context=extra_context)
def queryset(self, request):
qs = super(CandidateAdmin, self).queryset(request)
search_query = []
#self.other_search_fields = request.session[request.user.username]
if request.session[request.user.username]:
other_search_fields = request.session[request.user.username]
for key in other_search_fields.keys():
key_values = other_search_fields.get(key)
key_values =[value for value in key_values if value!='']
if key_values:
questions = [('{0}__icontains'.format(key), value) for value in key_values]
q_list = [Q(x) for x in questions]
query = reduce(operator.or_, q_list)
search_query.append(query)
if search_query:
make_query = reduce(operator.and_, search_query)
return qs.filter(make_query)
return qs
admin/search_form.html
{% load i18n grp_tags %}
{% if cl.search_fields %}
<!-- Search Form -->
{% if asf %}
<form action="" method="POST"> {% csrf_token %}
{{asf}}
<input type="submit" value="search" />
</form>
{% else %}
<!-- Search Form -->
<form id="grp-changelist-search" action="" method="get">
<input type="text" name="{{ search_var }}" id="grp-changelist-search" class="grp-search-field" value="{{ cl.query }}" />
<button type="submit" value="" class="grp-search-button"></button>
{% for pair in cl.params.items %}
{% ifnotequal pair.0 search_var %}<input type="hidden" name="{{ pair.0 }}" value="{{ pair.1 }}"/>{% endifnotequal %}
{% endfor %}
</form>
{% endif %}
{% endif %}
#2
0
I'm not sure if you meant that you've already written a custom search, but in this case, depending on what you want to do, you may not need that. You can search on related model fields through the default search_fields
with the caveat that this'll generate related lookups/joins.
我不确定你是否意味着你已经编写了自定义搜索,但在这种情况下,根据你想要做什么,你可能不需要那样做。您可以通过默认的search_fields搜索相关的模型字段,但需要注意这将生成相关的查找/连接。
I'm, not sure what City
, Province
, and Region
look like, but assuming they have a name
field, this should work (if they have an id
field, this would just be province__id
, etc.):
我不确定City,Province和Region是什么样子,但假设他们有一个名字字段,这应该有用(如果他们有一个id字段,这只是省___,等等):
# admin.py
class PropertyAdmin(ModelAdmin):
...
search_fields = (
'region__name',
'city__name',
'province__name',
)
Note that if you render any of the ForeignKeys
in the list_display
, you'll likely want to override the queryset to use select_related
on any fields that you show to avoid generating a lot of unnecessary SQL queries:
请注意,如果您在list_display中呈现任何ForeignKeys,您可能希望覆盖查询集以在您显示的任何字段上使用select_related,以避免生成大量不必要的SQL查询:
# admin.py
class PropertyAdmin(ModelAdmin):
...
def get_queryset(self, request);
qs = super(PropertyAdmin, self).get_queryset(request)
return qs.select_related('province', 'city', 'region',)
P.S. It also looks like you define list_display_links
twice there, so the second definition is overriding the first one, which may not be the behavior you want.
附:它看起来像你在那里定义了list_display_links两次,所以第二个定义覆盖了第一个定义,这可能不是你想要的行为。
#1
2
class CandidateAdmin(admin.ModelAdmin):
formfield_overrides = {
models.TextField: {'widget': Textarea(attrs={'rows': 4, 'cols': 40})},
}
list_display = ('id', 'first_name', 'last_name', 'current_company',
'title', 'gender', 'country', 'status', 'consultant',
'mobile_number', 'civil_reg_number', 'added_date')
list_display_links = ('id', 'first_name', 'last_name')
list_filter = ('consultant', 'status', 'gender', 'country', 'city')
form = CandidateForm
advanced_search_form = AdvancedSearchForm()
other_search_fields = {}
search_fields = ['first_name', 'last_name', 'civil_reg_number',
'status', 'cvmn', 'cven',
'address', 'mobile_number', 'notes']
actions = [recruited_by_scc]
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'consultant':
kwargs['initial'] = Consultant.objects.get(user=request.user)
return db_field.formfield(**kwargs)
return super(CandidateAdmin, self).\
formfield_for_foreignkey(db_field, request, **kwargs)
def changelist_view(self, request, extra_context=None, **kwargs):
extra_context = {'asf':self.advanced_search_form}
request.POST._mutable=True
post_keys = []
search_keys = []
for key in request.POST.keys():
value=request.POST.get(key)
if value!='' and key!='csrfmiddlewaretoken':
post_keys.append(key)
for key in self.other_search_fields.keys():
value = [x for x in self.other_search_fields.get(key) if x!='']
if value:
search_keys.append(key)
if post_keys!=search_keys and len(post_keys)>0 and len(search_keys)>0:
self.other_search_fields = {}
for key in self.advanced_search_form.fields.keys():
try:
temp = request.POST.pop(key)
except KeyError:
pass
else:
if temp!=['']:
self.other_search_fields[key] = temp
request.session[request.user.username] = self.other_search_fields
self.other_search_fields = {}
request.POST._mutable=False
return super(CandidateAdmin, self).changelist_view(request, extra_context=extra_context)
def queryset(self, request):
qs = super(CandidateAdmin, self).queryset(request)
search_query = []
#self.other_search_fields = request.session[request.user.username]
if request.session[request.user.username]:
other_search_fields = request.session[request.user.username]
for key in other_search_fields.keys():
key_values = other_search_fields.get(key)
key_values =[value for value in key_values if value!='']
if key_values:
questions = [('{0}__icontains'.format(key), value) for value in key_values]
q_list = [Q(x) for x in questions]
query = reduce(operator.or_, q_list)
search_query.append(query)
if search_query:
make_query = reduce(operator.and_, search_query)
return qs.filter(make_query)
return qs
admin/search_form.html
{% load i18n grp_tags %}
{% if cl.search_fields %}
<!-- Search Form -->
{% if asf %}
<form action="" method="POST"> {% csrf_token %}
{{asf}}
<input type="submit" value="search" />
</form>
{% else %}
<!-- Search Form -->
<form id="grp-changelist-search" action="" method="get">
<input type="text" name="{{ search_var }}" id="grp-changelist-search" class="grp-search-field" value="{{ cl.query }}" />
<button type="submit" value="" class="grp-search-button"></button>
{% for pair in cl.params.items %}
{% ifnotequal pair.0 search_var %}<input type="hidden" name="{{ pair.0 }}" value="{{ pair.1 }}"/>{% endifnotequal %}
{% endfor %}
</form>
{% endif %}
{% endif %}
#2
0
I'm not sure if you meant that you've already written a custom search, but in this case, depending on what you want to do, you may not need that. You can search on related model fields through the default search_fields
with the caveat that this'll generate related lookups/joins.
我不确定你是否意味着你已经编写了自定义搜索,但在这种情况下,根据你想要做什么,你可能不需要那样做。您可以通过默认的search_fields搜索相关的模型字段,但需要注意这将生成相关的查找/连接。
I'm, not sure what City
, Province
, and Region
look like, but assuming they have a name
field, this should work (if they have an id
field, this would just be province__id
, etc.):
我不确定City,Province和Region是什么样子,但假设他们有一个名字字段,这应该有用(如果他们有一个id字段,这只是省___,等等):
# admin.py
class PropertyAdmin(ModelAdmin):
...
search_fields = (
'region__name',
'city__name',
'province__name',
)
Note that if you render any of the ForeignKeys
in the list_display
, you'll likely want to override the queryset to use select_related
on any fields that you show to avoid generating a lot of unnecessary SQL queries:
请注意,如果您在list_display中呈现任何ForeignKeys,您可能希望覆盖查询集以在您显示的任何字段上使用select_related,以避免生成大量不必要的SQL查询:
# admin.py
class PropertyAdmin(ModelAdmin):
...
def get_queryset(self, request);
qs = super(PropertyAdmin, self).get_queryset(request)
return qs.select_related('province', 'city', 'region',)
P.S. It also looks like you define list_display_links
twice there, so the second definition is overriding the first one, which may not be the behavior you want.
附:它看起来像你在那里定义了list_display_links两次,所以第二个定义覆盖了第一个定义,这可能不是你想要的行为。