Repository: getredash/redash

Issue:
Load query results in dashboard with separate requests
Currently when requesting dashboard data from the server it returns it with all the visualizations, queries and query results. While at first this seemed as a good idea (to have single http request), it has some downsides:
1. In case of large data sets, getting them all in one puts too much stress on the server.
2. In ability to use HTTP caching in case the same query is used for several visualizaitons or if it was loaded already (and the cache isn't stale).
3. It prevents "progressive" load, as data for all the queries needs to be downloaded before single visualization can be seen.

Therefore let's change the API to return everything aside from query results. It might even be just a server change, as in theory, in the past this case was handled properly by the application (although a lot has been changed since). 



Discussion:

Resolving patch:
diff --git a/redash/controllers.py b/redash/controllers.py
--- a/redash/controllers.py
+++ b/redash/controllers.py
@@ -294,11 +294,11 @@ def post(self):
 
         query.create_default_visualizations()
 
-        return query.to_dict(with_result=False)
+        return query.to_dict()
 
     @require_permission('view_query')
     def get(self):
-        return [q.to_dict(with_result=False, with_stats=True) for q in models.Query.all_queries()]
+        return [q.to_dict(with_stats=True) for q in models.Query.all_queries()]
 
 
 class QueryAPI(BaseResource):
@@ -318,7 +318,7 @@ def post(self, query_id):
 
         query = models.Query.get_by_id(query_id)
 
-        return query.to_dict(with_result=False, with_visualizations=True)
+        return query.to_dict(with_visualizations=True)
 
     @require_permission('view_query')
     def get(self, query_id):
@@ -392,7 +392,7 @@ def post(self):
                         'error': 'Access denied for table(s): %s' % (metadata.used_tables)
                     }
                 }
-        
+
         models.ActivityLog(
             user=self.current_user,
             type=models.ActivityLog.QUERY_EXECUTION,
diff --git a/redash/models.py b/redash/models.py
--- a/redash/models.py
+++ b/redash/models.py
@@ -78,7 +78,7 @@ def permissions(self):
 class Group(BaseModel):
     DEFAULT_PERMISSIONS = ['create_dashboard', 'create_query', 'edit_dashboard', 'edit_query',
                            'view_query', 'view_source', 'execute_query']
-    
+
     id = peewee.PrimaryKeyField()
     name = peewee.CharField(max_length=100)
     permissions = ArrayField(peewee.CharField, default=DEFAULT_PERMISSIONS)
@@ -151,7 +151,7 @@ def verify_password(self, password):
 
 class ActivityLog(BaseModel):
     QUERY_EXECUTION = 1
-    
+
     id = peewee.PrimaryKeyField()
     user = peewee.ForeignKeyField(User)
     type = peewee.IntegerField()
@@ -277,7 +277,7 @@ def create_default_visualizations(self):
                                             type="TABLE", options="{}")
         table_visualization.save()
 
-    def to_dict(self, with_result=True, with_stats=False, with_visualizations=False, with_user=True):
+    def to_dict(self, with_stats=False, with_visualizations=False, with_user=True):
         d = {
             'id': self.id,
             'latest_query_data_id': self._data.get('latest_query_data', None),
@@ -307,9 +307,6 @@ def to_dict(self, with_result=True, with_stats=False, with_visualizations=False,
             d['visualizations'] = [vis.to_dict(with_query=False)
                                    for vis in self.visualizations]
 
-        if with_result and self.latest_query_data:
-            d['latest_query_data'] = self.latest_query_data.to_dict()
-
         return d
 
     @classmethod
@@ -383,13 +380,11 @@ def to_dict(self, with_widgets=False):
         layout = json.loads(self.layout)
 
         if with_widgets:
-            widgets = Widget.select(Widget, Visualization, Query, QueryResult, User)\
+            widgets = Widget.select(Widget, Visualization, Query, User)\
                 .where(Widget.dashboard == self.id)\
                 .join(Visualization, join_type=peewee.JOIN_LEFT_OUTER)\
                 .join(Query, join_type=peewee.JOIN_LEFT_OUTER)\
-                .join(User, join_type=peewee.JOIN_LEFT_OUTER)\
-                .switch(Query)\
-                .join(QueryResult, join_type=peewee.JOIN_LEFT_OUTER)
+                .join(User, join_type=peewee.JOIN_LEFT_OUTER)
             widgets = {w.id: w.to_dict() for w in widgets}
 
             # The following is a workaround for cases when the widget object gets deleted without the dashboard layout
@@ -539,4 +534,4 @@ def create_db(create_tables, drop_tables):
         if create_tables and not model.table_exists():
             model.create_table()
 
-    db.close_db(None)
\ No newline at end of file
+    db.close_db(None)


Test patch: