在 Django 中创建通用搜索视图
Creating a generic search view in Django
我正在努力在 Django 中创建我的自定义通用视图,以便轻松地为某些模型创建搜索页面。我想像这样使用它:
class MyModelSearchView(SearchView):
template_name = 'path/to/template.html'
model = MyModel
fields = ['name', 'email', 'whatever']
这将导致 returns GET 上的搜索表单以及 POST 上的表单和结果。
fields
指定 MyModel
的哪些字段可供用户搜索。
class SearchView(FormView):
def get_form(self, form_class=None):
# what I'v already tried:
class SearchForm(ModelForm):
class Meta:
model = self.model
fields = self.fields
return SearchForm()
def post(self, request, *args, **kwargs):
# perform searching and return results
上述代码的问题在于,如果某些字段未正确填写,则不会提交表单。应该允许用户只提供部分字段进行搜索,但使用我提供的代码,使用 ModelForm
生成的表单可以防止这种情况发生(例如,因为模型中的字段不能为空)。
我的问题是:
- 是否可以根据模型生成表单以忽略此行为?
- 或者有没有更简单的方法来创建
SearchView
class?
如果可能的话,我不想手动写表格。
完成此操作的一种方法是在 MyModel
中的字段上设置 blank=True
,如 the docs:
中所示
If the model field has blank=True
, then required
is set to False
on the form field. Otherwise, required=True
.
但要将其作为通用解决方案,您不能指望能够修改模型字段。您可以在创建实例后立即将字段的 required
属性设置为 False
:
class SearchForm(ModelForm):
class Meta:
model = self.model
fields = self.fields
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for (field_name, field) in self.fields.items():
field.required = False
由于您正在使用 ModelForm 进行搜索,因此您应该通过覆盖 __init__
方法将所有字段设置为 required=False
:
def get_form(self, form_class=None):
# what I'v already tried:
class SearchForm(ModelForm):
class Meta:
model = self.model
fields = self.fields
def __init__(self, *args, **kwargs):
super(SearchForm, self).__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].required = False
return SearchForm()
虽然我建议您应该使用 django-filter
,这样可以更轻松、更清晰地过滤您的搜索。首先你需要安装它:
pip install django-filter
然后将其添加到您的 INSTALLED_APPS
。之后,您可以在您的应用程序中创建一个 filters.py
文件:
# myapp/filters.py
import django_filters as filters
from .models import MyModel
MyModelFilterSet(filters.FilterSet):
class Meta:
model = MyModel
fields = ['name', 'email', 'whatever']
默认情况下,它将使用 __exact
查找进行过滤。您可以通过多种方式更改它,只需看一下 here and here. To know which lookups you can use, take a look here.
创建 filters.py
文件后,您可以将其添加到视图,如 ListView:
# myapp/views.py
from django.views.generic import ListView
from .filters import MyModelFilterSet
from .models import MyModel
class MyModelSearchView(ListView):
template_name = 'path/to/template.html'
model = MyModel
def get_queryset(self):
qs = self.model.objects.all()
filtered_model_list = MyModelFilterSet(self.request.GET, queryset=qs)
return filtered_model_list.qs
您可以使用 django-filter
做更多事情。这是完整的 documentation.
我正在努力在 Django 中创建我的自定义通用视图,以便轻松地为某些模型创建搜索页面。我想像这样使用它:
class MyModelSearchView(SearchView):
template_name = 'path/to/template.html'
model = MyModel
fields = ['name', 'email', 'whatever']
这将导致 returns GET 上的搜索表单以及 POST 上的表单和结果。
fields
指定 MyModel
的哪些字段可供用户搜索。
class SearchView(FormView):
def get_form(self, form_class=None):
# what I'v already tried:
class SearchForm(ModelForm):
class Meta:
model = self.model
fields = self.fields
return SearchForm()
def post(self, request, *args, **kwargs):
# perform searching and return results
上述代码的问题在于,如果某些字段未正确填写,则不会提交表单。应该允许用户只提供部分字段进行搜索,但使用我提供的代码,使用 ModelForm
生成的表单可以防止这种情况发生(例如,因为模型中的字段不能为空)。
我的问题是:
- 是否可以根据模型生成表单以忽略此行为?
- 或者有没有更简单的方法来创建
SearchView
class?
如果可能的话,我不想手动写表格。
完成此操作的一种方法是在 MyModel
中的字段上设置 blank=True
,如 the docs:
If the model field has
blank=True
, thenrequired
is set toFalse
on the form field. Otherwise,required=True
.
但要将其作为通用解决方案,您不能指望能够修改模型字段。您可以在创建实例后立即将字段的 required
属性设置为 False
:
class SearchForm(ModelForm):
class Meta:
model = self.model
fields = self.fields
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for (field_name, field) in self.fields.items():
field.required = False
由于您正在使用 ModelForm 进行搜索,因此您应该通过覆盖 __init__
方法将所有字段设置为 required=False
:
def get_form(self, form_class=None):
# what I'v already tried:
class SearchForm(ModelForm):
class Meta:
model = self.model
fields = self.fields
def __init__(self, *args, **kwargs):
super(SearchForm, self).__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].required = False
return SearchForm()
虽然我建议您应该使用 django-filter
,这样可以更轻松、更清晰地过滤您的搜索。首先你需要安装它:
pip install django-filter
然后将其添加到您的 INSTALLED_APPS
。之后,您可以在您的应用程序中创建一个 filters.py
文件:
# myapp/filters.py
import django_filters as filters
from .models import MyModel
MyModelFilterSet(filters.FilterSet):
class Meta:
model = MyModel
fields = ['name', 'email', 'whatever']
默认情况下,它将使用 __exact
查找进行过滤。您可以通过多种方式更改它,只需看一下 here and here. To know which lookups you can use, take a look here.
创建 filters.py
文件后,您可以将其添加到视图,如 ListView:
# myapp/views.py
from django.views.generic import ListView
from .filters import MyModelFilterSet
from .models import MyModel
class MyModelSearchView(ListView):
template_name = 'path/to/template.html'
model = MyModel
def get_queryset(self):
qs = self.model.objects.all()
filtered_model_list = MyModelFilterSet(self.request.GET, queryset=qs)
return filtered_model_list.qs
您可以使用 django-filter
做更多事情。这是完整的 documentation.