3 回答
![?](http://img1.sycdn.imooc.com/54584d1300016b9b02200220-100-100.jpg)
TA贡献1900条经验 获得超5个赞
免责声明:这个答案可能不适合OP的观点或模型,但是,它将按原样与示例一起工作。
为了清楚起见,我假设我们有两个模型,Musician 它们Album位于sample应用程序中。
# sample/models.py
from django.db import models
class Musician(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return f'{self.name}'
class Album(models.Model):
artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
description = models.TextField()
def __str__(self):
return f'{self.name} : {self.artist}'
然后,我们必须创建一个mixin类,以获得更好的OOP 体验以及跨多个视图的可扩展性。
#sample/mixins.py
from django.apps import apps
from django.db.models import Q
from functools import reduce
from operator import or_
class SearchMixin:
search_keyword_arg = 'q'
search_settings = {}
lookup_expr = 'icontains'
def get_search_term(self):
return self.request.GET.get(self.search_keyword_arg)
def build_search_query(self, model_ref, term):
return reduce(or_, [Q(**{f'{field}__{self.lookup_expr}': term}) for field in self.search_settings[model_ref]])
def get_search_results(self):
has_search_result = False
search_term = self.get_search_term()
if not search_term:
return {'has_search_result': has_search_result}
results = {}
for model_ref, fields in self.search_settings.items():
app_name, model_str = model_ref.split('.')
ModelKlass = apps.get_model(app_label=app_name, model_name=model_str)
qs = ModelKlass.objects.filter(self.build_search_query(model_ref, search_term))
results[model_ref.replace('.', '_').lower()] = qs
if has_search_result is False and qs.exists():
has_search_result = True
results['has_search_result'] = has_search_result
return results
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['search_result'] = self.get_search_results()
return context
这个SearchMixin类有我们想要的搜索功能。我们可以将此类添加到任何 Django 视图中来获取结果。
为此,我们将SearchMixinclass 继承为ListViewas,
# sample/views.py
from django.views.generic import TemplateView
from sample.mixins import SearchMixin
class GlobalSearchView(SearchMixin, TemplateView):
template_name = 'sample/global_search.html'
search_settings = {
'sample.Musician': ['name'],
'sample.Album': ['name', 'description'],
}
笔记:
我使用了
TemplateView
更适合这种特殊情况的方法。有一个名为的新类属性
search_settings
,用于确定搜索字段。
search_settings
属性应该如何?
它必须是一个
dict
(或dict
类似的对象)对象的键
dict
应该采用以下app_name.ModelClassName
格式的值
dict
必须是模型字段的可迭代
它在模板中看起来怎么样?
该类SearchMixin
将搜索结果添加到名为 and 的上下文变量中,search_result
该变量还有另一个变量has_search_result
( search_result.has_search_result
),可用于检查我们是否有“任何匹配”。
此外,每个查询集都可以通过单独的变量访问。变量的格式为, app_name<underscore><model_name_in_lower_case>
.
例如,对于模型,可以在模板中sample.Musician
获取搜索结果(如果有),如下所示:{{ search_result.sample_musician }}
# sample/templates/sample/global_search.html
{% if search_result.has_search_result %}
<strong>Musician result</strong><br>
{% for musician in search_result.sample_musician %}<br>
{{ musician.name }}
{% endfor %}
<br><br>
<strong>Album result</strong><br>
{% for album in search_result.sample_album %}
{{ album.name }} -- {{ album.description }}<br>
{% endfor %}
{% else %}
No match
{% endif %}
现在,连接视图urls.py并使用查询参数进行搜索,如下所示:
/foo-bar/global-search/?q=xx
![?](http://img1.sycdn.imooc.com/5458471300017f3702200220-100-100.jpg)
TA贡献1798条经验 获得超7个赞
我认为最好将所有内容都get_context_data这样放入:
# global search
class GlobalSearchView(ListView):
template_name = 'search_global.html'
count = 0
countnutri = 0
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['count'] = self.count or 0
context['countnutri'] = self.countnutri or 0
query = self.request.GET.get('q', None)
context['query'] = query
if query:
nutriscore = Post.objects.filter(
Q(title__icontains=query) | Q(slug__icontains=query) | Q(typederepas__name__icontains=query) | Q(prixrepas__name__icontains=query) | Q(vitesserepas__name__icontains=query) | Q(force__name__icontains=query) | Q(bienfaitrepas__name__icontains=query)
).distinct()
user = UserProfile.objects.filter(
Q(pays__icontains=query) | Q(town__icontains=query) | Q(user__username__icontains=query) | Q(mealtrend__name__icontains=query) | Q(pricetrend__name__icontains=query) | Q(speedtrend__name__icontains=query)| Q(strengthtrend__name__icontains=query) | Q(wellnesstrend__name__icontains=query)
).distinct()
context['results'] = chain(nutriscore,user)
return context
results然后您可以在模板中使用变量
![?](http://img1.sycdn.imooc.com/545861e40001199702200220-100-100.jpg)
TA贡献1845条经验 获得超8个赞
你有 3 个 return 语句,所以只有第一个会被执行:
return qs # return user return qn # return nutriscore / NOT EXECUTED return results # return results / NOT EXECUTED
你应该只保留return results
.
如果您确实想返回 3 个项目,请以元组形式返回:
return qa, qn, results
添加回答
举报