张贴模型属于Nutriscore文件夹
UserProfile模型属于用户文件夹
如果我使用一个涵盖Post和UserProfile搜索的词,例如Main courses。我得到了一些UserProfile的搜索结果(3个结果(,但Post没有出现任何结果(而count
给了我6个结果(。所以我不知道代码出了什么问题?
user/views.py
# 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
context['query'] = self.request.GET.get('q')
return context
def get_queryset(self): # new
query = self.request.GET.get('q', None)
if query is not None:
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()
results = chain(nutriscore,user)
qs = sorted(user,
key=lambda instance: instance.pk,
reverse=True)
self.count = len(qs)
qn = sorted(nutriscore,
key=lambda instance: instance.pk,
reverse=True)
self.countnutri = len(qn)
return qs
return qn
return results
user/uls.py
path('search/', GlobalSearchView.as_view(),name="global_search"),
user/templates/global_search.html我得到了一个用css显示/折叠功能的菜单。
<div class="row" id="collapseNutriscore">
{% for object in object_list %}
{% with object|class_name as klass %}
{% if klass == 'Post' %}
{{ object.title }}
{% endif %}
{% endwith %}
{% endfor %}
</div>
<br>
<br>
<div class="row collapse" id="collapseCooker">
{% for object in object_list %}
{% with object|class_name as klass %}
{% if klass == 'UserProfile' %}
{{ object.user.username }}
{% endif %}
{% endwith %}
{% endfor %}
</div>
免责声明:这个答案可能不适合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视图中以获得结果。
为此,我们将SearchMixin
类继承到ListView
作为
# 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
类将搜索结果添加到名为search_result
的上下文变量中,并且该类具有另一个变量has_search_result
(search_result.has_search_result
(;任何匹配"。
此外,每个QuerySet都可以由单独的变量访问。变量的格式为,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
我认为最好把所有东西都像这样放在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
变量
您有3个返回语句,因此只执行上的第一个:
return qs # return user
return qn # return nutriscore / NOT EXECUTED
return results # return results / NOT EXECUTED
您应该只保留return results
。
如果您真的想返回这3项,请以元组形式返回:
return qa, qn, results