Add progress bar with completion level for collections.
authorAlexandre Segura <mex.zktk@gmail.com>
Mon, 22 May 2017 17:25:40 +0200
changeset 521 63a7f61554fe
parent 520 d1e231a045ac
child 522 2d9660ad4a94
Add progress bar with completion level for collections.
src/iconolab/models.py
src/iconolab/templates/iconolab/collection_home.html
src/iconolab/templates/iconolab/home.html
src/iconolab/views/objects.py
--- a/src/iconolab/models.py	Mon May 22 16:17:36 2017 +0200
+++ b/src/iconolab/models.py	Mon May 22 17:25:40 2017 +0200
@@ -9,7 +9,7 @@
 from django.contrib.auth.models import User
 from django.contrib.contenttypes.fields import GenericRelation
 from django.contrib.contenttypes.models import ContentType
-from django.db import models, transaction
+from django.db import models, transaction, connection
 from django.utils.text import slugify
 from django_comments_xtd.models import XtdComment
 
@@ -17,6 +17,14 @@
 
 logger = logging.getLogger(__name__)
 
+# https://docs.djangoproject.com/fr/1.11/topics/db/sql/#executing-custom-sql-directly
+def dictfetchall(cursor):
+    "Return all rows from a cursor as a dict"
+    columns = [col[0] for col in cursor.description]
+    return [
+        dict(zip(columns, row))
+        for row in cursor.fetchall()
+    ]
 
 class Collection(models.Model):
     """
@@ -42,6 +50,33 @@
     height = models.IntegerField(null=True, blank=True)
     width = models.IntegerField(null=True, blank=True)
     show_image_on_home = models.BooleanField(default=False)
+    completed_percent_calculated = None
+
+    def completed_percent(self):
+
+        if self.completed_percent_calculated is None:
+
+            sql = '''SELECT i.id AS item, COUNT(a.id) AS annotations
+    FROM iconolab_collection c
+    JOIN iconolab_item i ON i.collection_id = c.id
+    JOIN iconolab_image img ON img.item_id = i.id
+    LEFT JOIN iconolab_annotation a ON a.image_id = img.id
+    WHERE c.id = %s
+    GROUP BY c.name, i.id'''
+
+            with connection.cursor() as cursor:
+                cursor.execute(sql, [self.id])
+                results = dictfetchall(cursor)
+                total_items = len(results)
+                items_with_annotation = 0
+
+                for result in results:
+                    if result['annotations'] > 0:
+                        items_with_annotation += 1
+
+                self.completed_percent_calculated = int(round((items_with_annotation * 100) / total_items))
+
+        return self.completed_percent_calculated
 
     def __str__(self):
         return self.name
--- a/src/iconolab/templates/iconolab/collection_home.html	Mon May 22 16:17:36 2017 +0200
+++ b/src/iconolab/templates/iconolab/collection_home.html	Mon May 22 17:25:40 2017 +0200
@@ -13,6 +13,13 @@
         <img src="{{ im.url }}" class="img-responsive">
       {% endthumbnail %}
       <hr>
+      <div class="progress">
+        <div class="progress-bar progress-bar-info progress-bar-striped" role="progressbar"
+          aria-valuenow="{{ collection.completed_percent }}" aria-valuemin="0" aria-valuemax="100"
+          style="width: {{ collection.completed_percent }}%;">
+          {{ collection.completed_percent }}%
+        </div>
+      </div>
       <p>
         {{ collection.description | safe }}
       </p>
--- a/src/iconolab/templates/iconolab/home.html	Mon May 22 16:17:36 2017 +0200
+++ b/src/iconolab/templates/iconolab/home.html	Mon May 22 17:25:40 2017 +0200
@@ -30,6 +30,13 @@
           </a>
         </div>
         <h4 class="text-center">{{collection.verbose_name}}</h4>
+        <div class="progress">
+          <div class="progress-bar progress-bar-info progress-bar-striped" role="progressbar"
+            aria-valuenow="{{ collection.completed_percent }}" aria-valuemin="0" aria-valuemax="100"
+            style="width: {{ collection.completed_percent }}%;">
+            {{ collection.completed_percent }}%
+          </div>
+        </div>
         <a class="btn btn-default btn-primary btn-block" href="{% url 'collection_home' collection.name %}">
           Contribuer
         </a>
@@ -148,10 +155,3 @@
   {% endif %}
 </div>
 {% endblock %}
-
-{% block footer_js %}
-<script>
-  _v = new Vue(iconolab.CollectionSelector);
-  _v.$mount("#homepage-main");
-</script>
-{% endblock %}
--- a/src/iconolab/views/objects.py	Mon May 22 16:17:36 2017 +0200
+++ b/src/iconolab/views/objects.py	Mon May 22 17:25:40 2017 +0200
@@ -68,6 +68,9 @@
             .order_by('-annotation_count')\
             .all()[:10]
 
+        for collection in context['collections_primary']:
+            collection.completed_percent()
+
         most_accurate_tags = []
         for row in rows:
             tag = Tag.objects.get(id=row['tag'])
@@ -212,6 +215,7 @@
             return result(request)
         context = super(CollectionHomepageView, self).get_context_data(**kwargs)
         context['collection_name'] = self.kwargs.get('collection_name', '')
+        collection.completed_percent()
         context['collection'] = collection
 
         # get Pagination and navigation query args