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