如图, Django admin后台生成的搜索框, 默认是没有提示文字的, 不够友好; 网上也没搜到什么好的示例, 于是自己动手实现了一个(要求Python3.6+,Django3.0+)
0. 已经存在的app名为carousel, 大致相当于如下操作/代码
$ python manage.py startapp carousel
# settings.py
```
INSTALLED_APPS = [
...
'carousel',
]
```
# carousel/models.py
```
from django.db import models
class Carousel(models.Model):
community = models.IntegerField('小区ID')
class Meta:
verbose_name = verbose_name_plural = '轮播设置'
```
1. 定制模板标签templatetags
mkdir -p carousel/templatetags
touch carousel/templatetags/__init__.py
touch carousel/templatetags/search_with_placeholder.py
# carousel/templatetags/search_with_placeholder.py
from django.contrib.admin.templatetags.admin_list import (
InclusionAdminNode,
register,
search_form,
)
def search_form_plus(cl, search_placeholder: str = ""):
"""
Display a search form for searching the list with placeholder.
"""
return dict(search_form(cl), search_placeholder=search_placeholder)
@register.tag(name="search_form_plus")
def search_form_tag(parser, token):
return InclusionAdminNode(
parser,
token,
func=search_form_plus,
template_name="search_form_plus.html",
takes_context=False,
)
2. 定制模板template
mkdir -p carousel/templates/admin
mkdir -p carousel/templates/custom_admin
touch carousel/templates/admin/search_form_plus.html
touch carousel/templates/custom_admin/change_list.html
<!-- carousel/templates/admin/search_form_plus.html -->
{% load i18n static %}
{% if cl.search_fields %}
<div id="toolbar"><form id="changelist-search" method="get">
<div><!-- DIV needed for valid HTML -->
<label for="searchbar"><img src="{% static "admin/img/search.svg" %}" alt="Search"></label>
<input type="text" size="40" name="{{ search_var }}" placeholder="{{ search_placeholder }}" value="{{ cl.query }}" id="searchbar" autofocus>
<input type="submit" value="{% translate 'Search' %}">
{% if show_result_count %}
<span class="small quiet">{% blocktranslate count counter=cl.result_count %}{{ counter }} result{% plural %}{{ counter }} results{% endblocktranslate %} (<a href="?{% if cl.is_popup %}_popup=1{% endif %}">{% if cl.show_full_result_count %}{% blocktranslate with full_result_count=cl.full_result_count %}{{ full_result_count }} total{% endblocktranslate %}{% else %}{% translate "Show all" %}{% endif %}</a>)</span>
{% endif %}
{% for pair in cl.params.items %}
{% if pair.0 != search_var %}<input type="hidden" name="{{ pair.0 }}" value="{{ pair.1 }}">{% endif %}
{% endfor %}
</div>
</form></div>
{% endif %}
<!-- carousel/templates/custom_admin/change_list.html -->
{% extends "admin/change_list.html" %}
{% load search_with_placeholder %}
{% block search %}{% search_form_plus cl search_placeholder %}{% endblock %}
3. 定制admin.py
cat carousel/admin.py
# Django3.1
from django.contrib import admin
from .models import BoxCarousel, Carousel,
class PlaceholderMixin:
change_list_template = "custom_admin/change_list.html"
def changelist_view(self, request, extra_context=None):
search_placeholder = getattr(self, "search_placeholder", False)
if search_placeholder:
extra_context = extra_context or {}
extra_context["search_placeholder"] = search_placeholder
return super().changelist_view(request, extra_context)
@admin.register(Carousel)
class CarouselAdmin(PlaceholderMixin, admin.ModelAdmin):
search_fields = ["=community"]
search_placeholder = "请输入小区ID"
其他列表页, 如果也想显示提示文字, 只需继承PlaceholderMixin, 然后定义search_placeholder就可以了
############################################################################
2021-10-07 补充
对于Python3.8+
mixin类可以是如下:
class PlaceholderMixin:
"""自动添加搜索框提示文字"""
change_list_template = "custom_admin/change_list.html"
def changelist_view(self, request, extra_context=None):
if fs := getattr(self, "search_fields", None):
if search_placeholder := getattr(self, "search_placeholder", True):
extra_context = extra_context or {}
if search_placeholder is True:
# 根据search_fields字段内容,自动生成提示文字
meta = self.model._meta
names = []
for field in fs:
if "__" not in field:
names.append(meta.get_field(field).verbose_name)
else:
# 如果搜索字段是外键,加上它的表名
fn, nxt, *_ = field.split("__")
f_obj = meta.get_field(fn)
n = f_obj.verbose_name
if remote_field := f_obj.remote_field:
r_meta = remote_field.model._meta
if (r_n := r_meta.get_field(nxt).verbose_name) != n:
n += r_n
names.append(n)
search_placeholder = "请输入 " + "/".join(names)
extra_context["search_placeholder"] = search_placeholder
return super().changelist_view(request, extra_context)
admin自定义一个基类,然后所有要管理的表都去继承它
from django.contrib import admin
from .mixins import PlaceholderMixin
class ModelAdmin(PlaceholderMixin, admin.ModelAdmin):
...
class XXXAdmin(ModelAdmin):
search_fields = ('field1', 'field2') # 会自动根据field1和field2的verbose_name去生成提示文字
=====================================================================
2021-11-21 简化为只需pip安装,然后修改INSTALLED_APPS就可以直接引入和继承使用了
## Install
- By pypi
pip install search_placeholder
- 或 By git
pip install git+https://github.com/waketzheng/django-search-placeholder.git
## Usage
1. Add app name to settings
INSTALLED_APPS = [
...
"django.contrib.admin",
...
"search_placeholder",
...
]
2. Use search_placeholder.ModelAdmin to replace admin.ModelAdmin
from django.contrib import admin
from search_placeholder import ModelAdmin
@admin.register(ModelClass)
class ModelClassAdmin(ModelAdmin):
# Just inherit from search_placeholder.ModelAdmin
# it will auto generate placeholder of search input by
# the verbose_name of 'field1' and 'field2'
# Or you can uncomment the next line to custom placeholder
#search_placeholder = 'Custom content'
search_fields = ('field1', 'field2')
代码见: https://github.com/waketzheng/django-search-placeholder.git