From 63ee1c39267d4cc3ae40958d083b80c0984052d8 Mon Sep 17 00:00:00 2001 From: Emilie Date: Fri, 7 Oct 2016 12:05:43 +0200 Subject: [PATCH] Search : count + filter by ContentType --- app/local_settings.py | 4 +- .../core/templatetags/organization_tags.py | 1 + app/organization/core/urls.py | 1 + app/organization/core/views.py | 71 ++++++++++++++++++- app/organization/magazine/models.py | 3 + app/organization/media/models.py | 5 +- app/templates/base.html | 3 +- app/templates/search_results.html | 13 +++- 8 files changed, 95 insertions(+), 6 deletions(-) diff --git a/app/local_settings.py b/app/local_settings.py index 70325834..b1fb9bf7 100644 --- a/app/local_settings.py +++ b/app/local_settings.py @@ -128,7 +128,9 @@ DASHBOARD_TAGS = ( ("mezzanine_tags.app_list",), (), ("mezzanine_tags.recent_act GRAPPELLI_ADMIN_TITLE = 'IRCAM Admin' -SEARCH_MODEL_CHOICES = () +SEARCH_MODEL_CHOICES = None # all objects +SEARCH_PER_PAGE = 10 +MAX_PAGING_LINKS = 10 RATINGS_ACCOUNT_REQUIRED = True diff --git a/app/organization/core/templatetags/organization_tags.py b/app/organization/core/templatetags/organization_tags.py index c0a5bd4f..a1ce4cd6 100644 --- a/app/organization/core/templatetags/organization_tags.py +++ b/app/organization/core/templatetags/organization_tags.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from django.http import QueryDict from mezzanine.pages.models import Page from mezzanine.blog.models import BlogPost from mezzanine.template import Library diff --git a/app/organization/core/urls.py b/app/organization/core/urls.py index 804c46cc..643d9edb 100644 --- a/app/organization/core/urls.py +++ b/app/organization/core/urls.py @@ -10,4 +10,5 @@ from mezzanine.conf import settings from organization.core.views import * urlpatterns = [ + url("^search/$", CustomSearchView.as_view(), name="search"), ] diff --git a/app/organization/core/views.py b/app/organization/core/views.py index 504bf762..0095baca 100644 --- a/app/organization/core/views.py +++ b/app/organization/core/views.py @@ -2,7 +2,11 @@ from django.shortcuts import render, get_object_or_404 from django.http import Http404 from django.views.generic.base import View from django.views.generic import DetailView, ListView, TemplateView - +from django.apps import apps +from django.utils.translation import ugettext_lazy as _ +from django.http import QueryDict +from mezzanine.conf import settings +from mezzanine.utils.views import paginate from organization.core.models import * @@ -16,3 +20,68 @@ class SlugMixin(object): # class CustomDisplayableView(SlugMixin, DetailView): # # model = CustomDisplayable + + +class CustomSearchView(TemplateView): + + template_name='search_results.html' + + + def get(self, request, *args, **kwargs): + + """ + Display search results. Takes an optional "contenttype" GET parameter + in the form "app-name.ModelName" to limit search results to a single model. + """ + context = super(CustomSearchView, self).get_context_data(**kwargs) + query = request.GET.get("q", "") + page = request.GET.get("page", 1) + per_page = settings.SEARCH_PER_PAGE + max_paging_links = settings.MAX_PAGING_LINKS + try: + parts = request.GET.get("type", "").split(".", 1) + search_model = apps.get_model(*parts) + search_model.objects.search # Attribute check + except (ValueError, TypeError, LookupError, AttributeError): + search_model = Displayable + search_type = _("Everything") + else: + search_type = search_model._meta.verbose_name_plural.capitalize() + + results = search_model.objects.search(query, for_user=request.user) + + # count objects + filter_dict = dict() + for result in results: + if result.__class__.__name__ in filter_dict: + filter_dict[result.__class__.__name__]['count'] += 1 + else: + filter_dict[result.__class__.__name__] = {'count' : 1} + filter_dict[result.__class__.__name__].update({'app_label' : result._meta.app_label}) + + # get url param + current_query = QueryDict(mutable=True) + current_query = request.GET.copy() + + # generate filter url + for key, value in filter_dict.items(): + current_query['type'] = value['app_label']+'.'+key + filter_dict[key].update({'url' : request.path+"?"+current_query.urlencode(safe='/')}) + + # pagination + paginated = paginate(results, page, per_page, max_paging_links) + + # context + context = {"query": query, "results": paginated, + "search_type": search_type} + + # cancel filter url + if request.GET.__contains__('type'): + previous_query = QueryDict(mutable=True) + previous_query = request.GET.copy() + previous_query.pop('type') + context['cancel_filter_url'] = '?'+previous_query.urlencode(safe='/') + + context['filter_dict'] = filter_dict + # context.update(extra_context or {}) + return self.render_to_response(context) diff --git a/app/organization/magazine/models.py b/app/organization/magazine/models.py index e7e355bb..90dba922 100644 --- a/app/organization/magazine/models.py +++ b/app/organization/magazine/models.py @@ -4,6 +4,7 @@ from django.db import models from django import forms from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType +from mezzanine.core.managers import SearchableManager from django.utils.translation import ugettext_lazy as _ from django.core.urlresolvers import reverse, reverse_lazy @@ -13,12 +14,14 @@ from mezzanine.blog.models import BlogPost from organization.network.models import Department, PersonListBlock from organization.media.models import Audio, Video from organization.core.models import * +from organization.magazine.apps import * class Article(BlogPost, SubTitled): department = models.ForeignKey(Department, verbose_name=_('department'), related_name='articles', limit_choices_to=dict(id__in=Department.objects.all()), blank=True, null=True, on_delete=models.SET_NULL) topics = models.ManyToManyField("Topic", verbose_name=_('topics'), related_name="articles", blank=True) + search_fields = ("title", "content") def get_absolute_url(self): return reverse("magazine-article-detail", kwargs={"slug": self.slug}) diff --git a/app/organization/media/models.py b/app/organization/media/models.py index f0161341..f5d196ac 100644 --- a/app/organization/media/models.py +++ b/app/organization/media/models.py @@ -4,7 +4,7 @@ from pyquery import PyQuery as pq from django.db import models from django.utils.translation import ugettext_lazy as _ - +from mezzanine.core.managers import SearchableManager from mezzanine.core.models import RichText, Displayable, Slugged from mezzanine.core.fields import RichTextField, OrderField, FileField from mezzanine.utils.models import AdminThumbMixin, upload_to @@ -24,6 +24,9 @@ class Media(Titled): closed_source_url = models.URLField(_('closed source URL'), max_length=1024, blank=True) poster_url = models.URLField(_('poster'), max_length=1024, blank=True) + objects = SearchableManager() + search_fields = ("title",) + class Meta: abstract = True diff --git a/app/templates/base.html b/app/templates/base.html index bef11655..e7b55441 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -297,8 +297,7 @@ - - {% include "includes/search_form.html" %} + {% search_form %} {% include "includes/footer_scripts.html" %} {% endspaceless %} diff --git a/app/templates/search_results.html b/app/templates/search_results.html index 1c5b62b4..cf6843a5 100644 --- a/app/templates/search_results.html +++ b/app/templates/search_results.html @@ -1,6 +1,6 @@ {% extends "base.html" %} -{% load i18n mezzanine_tags %} +{% load i18n mezzanine_tags organization_tags %} {% block meta_title %}{% trans "Search Results" %}{% endblock %} {% block title %}{% trans "Search Results" %}{% endblock %} @@ -37,10 +37,21 @@ {% endif %}

+

+

Filter:

+ {% for key,value in filter_dict.items %} + {{ key }} {{ value.count }}
+ {% endfor %} + {% if cancel_filter_url %} + Cancel filter + {% endif %} +

{% for result in results.object_list %} {% with result.get_absolute_url as result_url %} +
{{ forloop.counter0|add:results.start_index }}) + - {{ result|classname }} - {% if result_url %} {{ result }} {% else %} -- 2.39.5