iconolab search
authorHarris Baptiste <harris.baptiste@iri.centrepompidou.fr>
Fri, 12 Aug 2016 10:28:11 +0200
changeset 106 233bda6f2865
parent 105 eeb3541b343b
child 107 d82cb24d6443
iconolab search
src/iconolab/models.py
src/iconolab/search_indexes.py
src/iconolab/search_indexes/__init__.py
src/iconolab/search_indexes/forms.py
src/iconolab/search_indexes/indexes.py
src/iconolab/search_indexes/query.py
src/iconolab/search_indexes/views.py
src/iconolab/templates/iconolab/collection_home.html
src/iconolab/templates/partials/header.html
src/iconolab/templates/partials/header_search_form.html
src/iconolab/templates/search/annotation_search.html
src/iconolab/templates/search/default_search.html
src/iconolab/templates/search/image_search.html
src/iconolab/templates/search/indexes/iconolab/annotation_text.txt
src/iconolab/templates/search/indexes/iconolab/image_text.txt
src/iconolab/urls.py
src/iconolab/views/search_indexes.py
--- a/src/iconolab/models.py	Fri Aug 05 15:32:49 2016 +0200
+++ b/src/iconolab/models.py	Fri Aug 12 10:28:11 2016 +0200
@@ -94,6 +94,18 @@
     
     def __str__(self):
         return self.name
+    
+    @property
+    def collection(self):
+        return self.item.collection.name
+
+    @property
+    def title(self):
+        return self.item.metadatas.title
+    
+    @property
+    def description(self):
+        return self.item.metadatas.description
 
 
 class AnnotationManager(models.Manager):
@@ -191,6 +203,10 @@
     def awaiting_revisions_count(self):
         return self.revisions.filter(state=AnnotationRevision.AWAITING).distinct().count()
     
+    @property
+    def tags(self):
+        return [tag.label for tag in self.current_revision.tags.all()]
+    
     
     # Call to create a new revision, possibly from a merge
     @transaction.atomic
--- a/src/iconolab/search_indexes.py	Fri Aug 05 15:32:49 2016 +0200
+++ b/src/iconolab/search_indexes.py	Fri Aug 12 10:28:11 2016 +0200
@@ -10,15 +10,11 @@
 
 	title = indexes.CharField(model_attr='current_revision__title')
 	description = indexes.CharField(model_attr='current_revision__description')
-	tags = indexes.MultiValueField()
+	tags = indexes.MultiValueField(model_attr='tags')
 
 	## tags
 	def get_model(self):
 		return Annotation
 
-	def prepare_tags(self, annotation):
-		return ["toto", "titi", "sesl"]
-
-
 	def index_queryset(self, using=None):
-		return self.get_model().objects.filter(created__lte=datetime.datetime.now()).distinct('current_revision_id');
\ No newline at end of file
+		return self.get_model().objects.filter(created__lte=datetime.datetime.now())
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/search_indexes/__init__.py	Fri Aug 12 10:28:11 2016 +0200
@@ -0,0 +1,2 @@
+from .indexes import AnnotationIndex, ImageIndex 
+__all__ = ['AnnotationIndex', 'ImageIndex']
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/search_indexes/forms.py	Fri Aug 12 10:28:11 2016 +0200
@@ -0,0 +1,47 @@
+from django import forms
+from haystack.forms import SearchForm
+from iconolab.models import Image, Annotation
+
+
+
+
+#def get_available_choices():
+
+def get_selected_model(type):
+	
+	available_models = {
+		'image': Image,
+		'annotation': Annotation
+	}
+
+	return available_models[type]
+
+
+class IconolabSearchForm(SearchForm):
+
+	realm = forms.ChoiceField(required=False, choices=(("image","Image"), ("annotation","Annotation")) )
+	
+	def __init__(self, *args, **kwargs):
+		
+		super(IconolabSearchForm, self).__init__(*args, **kwargs)
+
+	def get_realm_queryset(self, qs, realm):
+		
+		if realm == 'image':
+			qs = qs.models(Image).load_all_queryset(Image, Image.objects.select_related('item', 'item__metadatas'))
+			qs = qs.filter(collection='stdie')
+		if realm == 'annotation':
+			qs = qs.models(Annotation).load_all_queryset(Annotation, Annotation.objects.select_related('image', 'stats', 'current_revision', 'author'))
+		return qs
+
+	def search(self):
+		
+		selected_realm = self.cleaned_data.get("realm")
+		selected_model = get_selected_model(selected_realm)
+		#load all if q empty
+		qs = super(IconolabSearchForm, self).search()
+		if qs.count() == 0:
+			return qs
+		else:
+			qs = self.get_realm_queryset(qs, selected_realm).load_all()
+		return qs
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/search_indexes/indexes.py	Fri Aug 12 10:28:11 2016 +0200
@@ -0,0 +1,37 @@
+import datetime
+from haystack import indexes
+from iconolab.models import Annotation, Image
+
+class ImageIndex(indexes.SearchIndex, indexes.Indexable):
+	text = indexes.CharField(document=True, use_template=True)
+
+	title = indexes.CharField(model_attr='item__metadatas__title')
+	description = indexes.CharField(model_attr='item__metadatas__description')
+	collection = indexes.CharField(model_attr='item__collection__name')
+	tags = indexes.MultiValueField()
+
+	def get_model(self):
+		return Image
+
+	def prepare_tags(self, object):
+		return ["radical", "you better", "yes"]
+
+	def index_queryset(self, using=None):
+		return self.get_model().objects.filter(created__lte=datetime.datetime.now())
+
+
+class AnnotationIndex(indexes.SearchIndex, indexes.Indexable):
+
+	##indexed field
+	text = indexes.CharField(document=True, use_template=True)
+
+	title = indexes.CharField(model_attr='current_revision__title')
+	description = indexes.CharField(model_attr='current_revision__description')
+	tags = indexes.MultiValueField(model_attr='tags')
+
+	## tags
+	def get_model(self):
+		return Annotation
+
+	def index_queryset(self, using=None):
+		return self.get_model().objects.filter(created__lte=datetime.datetime.now())
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/search_indexes/query.py	Fri Aug 12 10:28:11 2016 +0200
@@ -0,0 +1,18 @@
+from haystack.query import RelatedSearchQuerySet
+from iconolab.models import Annotation, Image
+from pprint import pprint
+
+class IconolabRelatedQuerySet(RelatedSearchQuerySet):
+	def __init__(self, using=None, query=None):
+		super(IconolabRelatedQuerySet, self).__init__(using=using, query=query)
+
+	#def in_bulk(self, ids):
+	#	results = {}
+	#	int_ids = [ int(id) for id in ids]
+	#	# Ne garder que les images
+	#	annotations = Image.objects.filter(pk__in = int_ids)
+	#	
+	#	for annotation in annotations:
+	#		results[annotation.pk] = annotation
+	#		
+	#	return results
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/search_indexes/views.py	Fri Aug 12 10:28:11 2016 +0200
@@ -0,0 +1,41 @@
+from haystack.generic_views import SearchView
+from iconolab.search_indexes.forms import IconolabSearchForm
+from iconolab.search_indexes.query import IconolabRelatedQuerySet
+from django.shortcuts import HttpResponse
+
+from pprint import pprint
+
+#override Search and Related QuerySet here
+class IconolabSearchView(SearchView):
+	form_class = IconolabSearchForm
+	queryset = IconolabRelatedQuerySet()
+	template_name = "search/default_search.html"
+	paginate_by = 10
+	load_all = True
+
+	templates_map = {
+		"image": "search/image_search.html",
+		"annotation": "search/annotation_search.html"
+	}
+
+	def get(self, request, *args, **kwargs):
+		self.current_realm = request.GET['realm']
+		return super(IconolabSearchView, self).get(request,*args, **kwargs)
+
+	def get_queryset(self):
+		qs = super(IconolabSearchView, self).get_queryset()
+		return qs
+
+	def get_template_names(self):
+		template = IconolabSearchView.templates_map[self.current_realm]
+		if template is None:
+			template = IconolabSearchView.template_name
+				
+		return [template]
+
+	def get_context_data(self, *args, **kwargs):
+		print("inside get_context_data", kwargs.get("q"))
+		print(kwargs.items())
+		context = super(IconolabSearchView, self).get_context_data(*args, **kwargs)
+		context['collection_name'] = self.kwargs.get('collection_name', '')
+		return context
\ No newline at end of file
--- a/src/iconolab/templates/iconolab/collection_home.html	Fri Aug 05 15:32:49 2016 +0200
+++ b/src/iconolab/templates/iconolab/collection_home.html	Fri Aug 12 10:28:11 2016 +0200
@@ -11,7 +11,7 @@
   
   
 <ul class="image-list-wrapper list-inline">
-  <p><strong>Images du fond</strong></p>
+  <p><strong>Images du fonds</strong></p>
 
   {% for item in collection.items.all %}
   <li class="small-image-wrapper">
--- a/src/iconolab/templates/partials/header.html	Fri Aug 05 15:32:49 2016 +0200
+++ b/src/iconolab/templates/partials/header.html	Fri Aug 12 10:28:11 2016 +0200
@@ -17,13 +17,8 @@
         {% if collection_name %}<li><a href="{% url 'collection_home' collection_name %}">Contribuer</a></li>{% endif %}
       </ul>
       
-      <form class="navbar-form navbar-left" role="search">
-        <div class="form-group">
-          <input type="text" class="form-control" placeholder="Trouver une image...">
-        </div>
-        <button type="submit" class="btn btn-default">Rechercher</button>
-      </form>
-
+      {% include "partials/header_search_form.html"%}
+      
       <ul class="nav navbar-nav navbar-right">
         {% if request.user.is_authenticated %}
           {% notifications_unread as unread_count %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/templates/partials/header_search_form.html	Fri Aug 12 10:28:11 2016 +0200
@@ -0,0 +1,15 @@
+<form method="GET" action="{% url 'haystack_search' %}" class="navbar-form navbar-left" role="search">
+	
+	<div class="form-group">
+	  <input name="q" type="text" class="form-control" placeholder="Trouver une image...">
+	</div>
+	
+	<div class="form-group">
+		<select name="realm" class="form-control">
+			<option value="image">Images</option>
+			<option value="innotation">Annotations</option>
+		</select>
+	</div>
+
+	<button type="submit" class="btn btn-default">Rechercher</button>
+</form>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/templates/search/annotation_search.html	Fri Aug 12 10:28:11 2016 +0200
@@ -0,0 +1,61 @@
+{% extends 'iconolab_base.html' %}
+
+{% load thumbnail %}
+{% load iconolab_tags %} 
+
+{% block content %}
+
+    <h2>Recherche</h2>
+
+    <form method="get" action=".">
+        <table>
+            
+            <tr>
+                <td> {{ form.as_p }} </td> 
+
+                <td>
+                    <input style="margin:0px" type="submit" value="Rechercher">
+                </td>
+            </tr>
+
+        </table>
+
+        {% if query %}
+            
+            <h3><strong>{{ page_obj.paginator.count }}</strong> annotation(s)</h3>
+            
+            {% for result in page_obj.object_list %}
+
+            {% thumbnail result.object.image.media "400x400" crop=False as im %}
+            <div class="annotation-item result" style="position:relative;">
+
+                <img v-el:small-image src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
+                <svg width="{{ im.width }}" height="{{ im.height }}" version="1.1" style="position:absolute; top:0px; left: 0px">
+                  <g transform="matrix({% transform_matrix im_width=im.width im_height=im.height max_x=100 max_y=100 %})">
+                    <path d="{{ result.object.current_revision.fragment|clean_path }}" opacity="0.7" fill="orange"></path>
+                  </g>
+                </svg>
+
+            </div>
+            {% endthumbnail %}
+
+
+                <p>
+                    <a href="{{ result.object.get_absolute_url }}">{{ result.object.current_revision.title }}</a>
+                </p>
+            {% empty %}
+                <p>Aucune annotation n'a été trouvée.</p>
+            {% endfor %}
+
+            {% if page_obj.has_previous or page_obj.has_next %}
+                <div>
+                    {% if page_obj.has_previous %}<a href="?q={{ query }}&amp;page={{ page_obj.previous_page_number }}">{% endif %}&laquo; Previous{% if page_obj.has_previous %}</a>{% endif %}
+                    |
+                    {% if page_obj.has_next %}<a href="?q={{ query }}&amp;page={{ page_obj.next_page_number }}">{% endif %}Next &raquo;{% if page_obj.has_next %}</a>{% endif %}
+                </div>
+            {% endif %}
+        {% else %}
+            {# Show some example queries to run, maybe query syntax, something else? #}
+        {% endif %}
+    </form>
+{% endblock %}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/templates/search/default_search.html	Fri Aug 12 10:28:11 2016 +0200
@@ -0,0 +1,23 @@
+{% extends 'iconolab_base.html' %}
+
+{% load thumbnail %}
+{% load iconolab_tags %} 
+
+{% block content %}
+
+    <h2>Recherche</h2>
+
+    <form method="get" action=".">
+        <table>
+        
+            <tr>
+                <td> {{ form.as_p }} </td> 
+                <td>
+                    <input style="margin:0px" type="submit" value="Rechercher">
+                </td>
+            </tr>
+
+        </table>
+
+    </form>
+{% endblock %}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/templates/search/image_search.html	Fri Aug 12 10:28:11 2016 +0200
@@ -0,0 +1,54 @@
+{% extends 'iconolab_base.html' %}
+
+{% load thumbnail %}
+{% load iconolab_tags %} 
+
+{% block content %}
+
+    <h2>Recherche</h2>
+
+    <form method="get" action=".">
+        <table>
+            
+            <tr>
+                <td> {{ form.as_p }} </td> 
+
+                <td>
+                    <input style="margin:0px" type="submit" value="Rechercher">
+                </td>
+            </tr>
+
+        </table>
+
+        {% if query %}
+            
+            <h3><strong>{{ page_obj.paginator.count }}</strong> image(s)</h3>
+            
+            {% for result in page_obj.object_list %}
+
+            {% thumbnail result.object.media "400x400" crop=False as im %}
+            <div class="annotation-item result" style="position:relative;">
+                <img src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
+            </div>
+            {% endthumbnail %}
+
+                <p>
+                    <a href="{{ result.object.get_absolute_url }}">{{ result.object.title }}</a>
+                    <span>collection {{result.object.collection}}</span>
+                </p>
+            {% empty %}
+                <p>No results found.</p>
+            {% endfor %}
+
+            {% if page_obj.has_previous or page_obj.has_next %}
+                <div>
+                    {% if page_obj.has_previous %}<a href="?q={{ query }}&amp;page={{ page_obj.previous_page_number }}">{% endif %}&laquo; Previous{% if page_obj.has_previous %}</a>{% endif %}
+                    |
+                    {% if page_obj.has_next %}<a href="?q={{ query }}&amp;page={{ page_obj.next_page_number }}">{% endif %}Next &raquo;{% if page_obj.has_next %}</a>{% endif %}
+                </div>
+            {% endif %}
+        {% else %}
+            {# Show some example queries to run, maybe query syntax, something else? #}
+        {% endif %}
+    </form>
+{% endblock %}
\ No newline at end of file
--- a/src/iconolab/templates/search/indexes/iconolab/annotation_text.txt	Fri Aug 05 15:32:49 2016 +0200
+++ b/src/iconolab/templates/search/indexes/iconolab/annotation_text.txt	Fri Aug 12 10:28:11 2016 +0200
@@ -2,3 +2,4 @@
 
 {{ object.current_revision.description }}
 
+{{ object.tags }}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/templates/search/indexes/iconolab/image_text.txt	Fri Aug 12 10:28:11 2016 +0200
@@ -0,0 +1,7 @@
+{{ object.item.metadatas.title }}
+
+{{ object.item.metadatas.description }}
+
+{{ object.tags }}
+
+samedi
\ No newline at end of file
--- a/src/iconolab/urls.py	Fri Aug 05 15:32:49 2016 +0200
+++ b/src/iconolab/urls.py	Fri Aug 12 10:28:11 2016 +0200
@@ -16,32 +16,38 @@
 from django.core.urlresolvers import reverse_lazy
 from django.conf.urls import url, include
 from django.contrib import admin
-from . import views
+from iconolab import views
+from iconolab.search_indexes.views import IconolabSearchView
 from . import settings
 
 from django.conf.urls.static import static
 from django.contrib.auth.decorators import login_required
 from django.contrib.staticfiles.urls import staticfiles_urlpatterns
+import notifications.urls
 
 urlpatterns = [
-    url(r'^$', views.RedirectView.as_view(url=reverse_lazy("home"))),
+    url(r'^$', views.iconolab.RedirectView.as_view(url=reverse_lazy("home"))),
     url(r'^admin/', admin.site.urls),
-    url(r'^home$', views.GlobalHomepageView.as_view(), name="home"),
-    url(r'^collections/(?P<collection_name>[a-z]+)$', views.CollectionHomepageView.as_view(), name='collection_home'), # Home fond
-    url(r'^collections/(?P<collection_name>[a-z]+)/items/(?P<item_guid>[^/]+)$', views.ShowItemView.as_view(), name='item_detail'),
-    url(r'^collections/(?P<collection_name>[a-z]+)/images/(?P<image_guid>[^/]+)$', views.ShowImageView.as_view(), name='image_detail'),
-    url(r'^collections/(?P<collection_name>[a-z]+)/images/(?P<image_guid>[^/]+)/annotations/create$', login_required(views.CreateAnnotationView.as_view()), name='annotation_create'),
-    url(r'^collections/(?P<collection_name>[a-z]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/detail$', views.ShowAnnotationView.as_view(), name='annotation_detail'),
-    url(r'^collections/(?P<collection_name>[a-z]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/edit$', login_required(views.EditAnnotationView.as_view()), name='annotation_edit'),
-    url(r'^collections/(?P<collection_name>[a-z]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/revisions/(?P<revision_guid>[^/]+)/detail', views.ShowRevisionView.as_view(), name='revision_detail'),
-    url(r'^collections/(?P<collection_name>[a-z]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/revisions/(?P<revision_guid>[^/]+)/merge$', login_required(views.MergeProposalView.as_view()), name='annotation_merge'),
-    url(r'errors/404', views.NotFoundErrorView.as_view(), name="404error"),
+    url(r'^home$', views.iconolab.GlobalHomepageView.as_view(), name="home"),
+    url(r'^collections/(?P<collection_name>[a-z]+)$', views.iconolab.CollectionHomepageView.as_view(), name='collection_home'), # Home fond
+    url(r'^collections/(?P<collection_name>[a-z]+)/items/(?P<item_guid>[^/]+)$', views.iconolab.ShowItemView.as_view(), name='item_detail'),
+    url(r'^collections/(?P<collection_name>[a-z]+)/images/(?P<image_guid>[^/]+)$', views.iconolab.ShowImageView.as_view(), name='image_detail'),
+    url(r'^collections/(?P<collection_name>[a-z]+)/images/(?P<image_guid>[^/]+)/annotations/create$', login_required(views.iconolab.CreateAnnotationView.as_view()), name='annotation_create'),
+    url(r'^collections/(?P<collection_name>[a-z]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/detail$', views.iconolab.ShowAnnotationView.as_view(), name='annotation_detail'),
+    url(r'^collections/(?P<collection_name>[a-z]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/edit$', login_required(views.iconolab.EditAnnotationView.as_view()), name='annotation_edit'),
+    url(r'^collections/(?P<collection_name>[a-z]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/revisions/(?P<revision_guid>[^/]+)/detail', views.iconolab.ShowRevisionView.as_view(), name='revision_detail'),
+    url(r'^collections/(?P<collection_name>[a-z]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/revisions/(?P<revision_guid>[^/]+)/merge$', login_required(views.iconolab.MergeProposalView.as_view()), name='annotation_merge'),
+    url(r'^user/(?P<slug>[a-z0-9\-]+)/home/?$', views.iconolab.UserHomeView.as_view(), name="user_home"),
+    url(r'^user/notifications/all/?$', login_required(views.iconolab.UserNotificationsView.as_view()), name="user_notifications"),
+    url(r'^errors/404', views.iconolab.NotFoundErrorView.as_view(), name="404error"),
     url(r'^rest', include('restapi.urls')),
     url(r'^account/', include('iconolab.auth.urls', namespace='account')),
     url(r'^comments/', include('django_comments_xtd.urls')),
-    url(r'^comments/annotation/post', views.post_comment_iconolab, name="post_comment"),
-    url(r'^search/', include('haystack.urls')),
+    url(r'^comments/annotation/post', views.comments.post_comment_iconolab, name="post_comment"),
+    url('^user/notifications/', include(notifications.urls, namespace='notifications')),
+    url(r'^search/$', IconolabSearchView.as_view(), name="haystack_search"),
+    #url(r'^search/', include('haystack.urls'), name="search_iconolab"),
 ]
 
 urlpatterns += staticfiles_urlpatterns()
-urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
\ No newline at end of file
+urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)