1+ import traceback
2+ import warnings
13from django .template import Template , Context
4+ from django .db import connection
5+ import logging
26
3- import traceback
7+ logger = logging .getLogger (__name__ )
8+
9+ def _validate_sql (sqltext ):
10+ """Validate the SQL query."""
11+ if len (sqltext ) < 8 or ("select" not in sqltext .lower ()):
12+ return False
13+ return True
14+
15+ def _execute_query (cursor , sqltext ):
16+ """Execute the SQL query and fetch data."""
17+ cursor .execute (sqltext )
18+ desc = cursor .description
19+ result_as_list = [
20+ dict (zip ([col [0 ] for col in desc ], row )) for row in cursor .fetchall ()
21+ ]
22+ columns = [col [0 ] for col in desc ]
23+ return columns , result_as_list
24+
25+ def _calculate_sums (data , columns , footerCols , totalText ):
26+ """Calculate sum for specified columns."""
27+ sumOfColumn = {col : 0 if col in footerCols else "-" for col in columns }
28+
29+ for d in data :
30+ for attr , value in d .items ():
31+ if attr in footerCols :
32+ sumOfColumn [attr ] += float (str (value ).replace ("," , "" ))
33+
34+ totalColumnSet = False
35+ for col in sumOfColumn :
36+ if sumOfColumn [col ] != "-" :
37+ sumOfColumn [col ] = format (float (str (sumOfColumn [col ])), "," )
38+ elif not totalColumnSet :
39+ sumOfColumn [col ] = totalText
40+ totalColumnSet = True
41+
42+ return sumOfColumn
43+
44+ def _render_template (context ):
45+ """Render the HTML table template."""
46+ template = (
47+ "<center><table dir=\" {{direction}}\" border=\" 1\" class=\" table table-striped {{htmlClass}}\" "
48+ "style=\" width:93%;font-family:'{{font}}'\" >"
49+ " <thead> <tr> <th colspan='{{columns|length|add:'1'}}' style=\" font-family:'{{font}}';font-weight: bold;\" > {{title}} </th> </tr>"
50+ " <tr style='background-color:{{headerRowColor}}'>{% if rowIndex %} <th align=\" center\" > # </th> {% endif %} {% for c in columns %} <th>{{ c }}</th> {% endfor %} </tr> </thead>"
51+ " <tbody> {% for d in data %} <tr style='background-color:{% if forloop.counter0|divisibleby:'2' %} {{evenRowColor}} {% else %} {{oddRowColor}} {% endif %} ' >"
52+ " {% if rowIndex %} <td align=\" center\" >{{ forloop.counter }}</td> {% endif %} {% for attr, value in d.items %} <td align=\" center\" >{{ value }}</td> {% endfor %} </tr> {% endfor %} "
53+ " {% if sumOfColumn %} <tr style='background-color:#eee;font-weight: bold;'> <td></td> {% for a,v in sumOfColumn.items %} <td align=\" center\" >{{ v }}</td> {% endfor %} </tr> {% endif %}</tbody> </table></center>"
54+ )
55+
56+ return Template (template ).render (Context (context ))
57+
58+ def _generate_report (cursor , title , sqltext , footerCols , htmlClass , direction , font , totalText , rowIndex , headerRowColor , evenRowColor , oddRowColor ):
59+ """Internal method to generate the SQL report."""
60+ columns , data = _execute_query (cursor , sqltext )
61+
62+ sumOfColumn = None
63+ if footerCols :
64+ sumOfColumn = _calculate_sums (data , columns , footerCols , totalText )
65+
66+ context = {
67+ 'title' : title ,
68+ 'data' : data ,
69+ 'columns' : columns ,
70+ 'sumOfColumn' : sumOfColumn ,
71+ 'direction' : direction ,
72+ 'font' : font ,
73+ 'totalText' : totalText ,
74+ 'rowIndex' : rowIndex ,
75+ 'headerRowColor' : headerRowColor ,
76+ 'evenRowColor' : evenRowColor ,
77+ 'oddRowColor' : oddRowColor ,
78+ 'htmlClass' : htmlClass
79+ }
80+
81+ return _render_template (context )
82+
83+ def generate_from_sql (title , sqltext , footerCols = None , htmlClass = "" , direction = "ltr" , font = "Tahoma" , totalText = "Total" , rowIndex = False , headerRowColor = '#eeeeee' , evenRowColor = '#ffffff' , oddRowColor = "#ffffff" ):
84+ """Generate the SQL report with an internally created cursor."""
85+ try :
86+ if not _validate_sql (sqltext ):
87+ return 'Not Valid SQL'
88+
89+ with connection .cursor () as cursor :
90+ return _generate_report (cursor , title , sqltext , footerCols , htmlClass , direction , font , totalText , rowIndex , headerRowColor , evenRowColor , oddRowColor )
91+ except Exception as e :
92+ logger .error (traceback .format_exc ())
93+ return f"Error: { str (e )} "
94+
95+ def generateFromSql (cursor , title , sqltext , footerCols = None , htmlClass = "" , direction = "ltr" , font = "Tahoma" , totalText = "Total" , rowIndex = False , headerRowColor = '#eeeeee' , evenRowColor = '#ffffff' , oddRowColor = "#ffffff" ):
96+ """Generate the SQL report with a provided cursor."""
97+ warnings .warn ("generateFromSql is deprecated and will be removed in a future release. Use generate_from_sql instead." , DeprecationWarning )
98+ try :
99+ if not _validate_sql (sqltext ):
100+ return 'Not Valid SQL'
4101
5- def generateFromSql (cursor , title , sqltext , footerCols = None , htmlClass = "" , direction = "ltr" , font = "Tahoma" , totalText = "Total" , rowIndex = False , headerRowColor = '#eeeeee' ,evenRowColor = '#ffffff' , oddRowColor = "#ffffff" ) :
6- sumCols = []
7- try :
8- if (len (sqltext ) < 8 or ("select" not in sqltext .lower ())) :
9- return ('Not Valid SQL' )
10-
11- sql_query = sqltext
12- sumCols = footerCols
13- # execute sql query and retrieve data from db
14- cursor .execute (sql_query )
15-
16- # retrieve columns of the data
17- desc = cursor .description
18-
19- result_as_list = [
20- dict (zip ([col [0 ] for col in desc ], row )) for row in cursor .fetchall ()
21- ]
22-
23- columns = [col [0 ] for col in desc ] #result.keys()
24- data = result_as_list
25-
26-
27-
28-
29-
30- sumOfColumn = None
31- if (sumCols != None ) :
32- sumOfColumn = {}
33-
34- # initiating footer aggrigation values
35- for c in columns :
36- if (c in sumCols ):
37- sumOfColumn [c ]= 0
38- else :
39- sumOfColumn [c ]= "-"
40-
41- # travers in rows and aggrigate the values of columns those are in footerCols
42- for d in data :
43- for attr , value in dict (d ).items () :
44- if (attr in sumCols ):
45- sumOfColumn [attr ]= sumOfColumn [attr ]+ float (str (value ).replace ("," , "" ))
46-
47- totalColumnSet = False
48- if (sumCols != None ) :
49- for col , val in sumOfColumn .items () :
50- if (val != "-" ) :
51- sumOfColumn [col ] = format (float (str (val )),"," )
52- elif (totalColumnSet == False ) :
53- sumOfColumn [col ] = totalText
54- totalColumnSet = True
55-
56- # template to generate data from data retrieved from database
57- template = "<center><table dir=\" {{direction}}\" border=\" 1\" class=\" table table-striped {{htmlClass}}\" style=\" width:93%;font-family:'{{font}}'\" > <thead> <tr> <th colspan='{{columns|length|add:'1'}}' style=\" font-family:'{{font}}';font-weight: bold;\" > {{title}} </th> </tr> <tr style='background-color:{{headerRowColor}}'>{% if rowIndex == True %} <th align=\" center\" > # </th> {% endif %} {% for c in columns %} <th>{{ c }}</th> {% endfor %} </tr> </thead> <tbody> {% for d in data %} <tr style='background-color:{% if forloop.counter0|divisibleby:'2' %} {{evenRowColor}} {% else %} {{oddRowColor}} {% endif %} ' > {% if rowIndex == True %} <td align=\" center\" >{{ forloop.counter }}</td> {% endif %} {% for attr, value in d.items %} <td align=\" center\" >{{ value }}</td> {% endfor %} </tr> {% endfor %} {% if sumOfColumn != None %} <tr style='background-color:#eee;font-weight: bold;'> <td></td> {% for a,v in sumOfColumn.items %} <td align=\" center\" >{{ v }}</td> {% endfor %} </tr> {% endif %}</tbody> </table></center>"
58-
59-
60-
61- c = Context ({
62- 'title' :title ,
63- 'data' :data ,
64- 'columns' :columns ,
65- 'sumOfColumn' :sumOfColumn ,
66- 'direction' :direction ,
67- 'font' :font ,
68- 'totalText' :totalText ,
69- 'rowIndex' : rowIndex ,
70- 'headerRowColor' :headerRowColor ,
71- 'evenRowColor' : evenRowColor ,
72- 'oddRowColor' : oddRowColor ,
73- 'htmlClass' : htmlClass
74- })
75-
76- return Template (template ).render (c )
77- except BaseException as e :
78- #print exception trace to console
79- print (traceback .format_exc ())
80- return ("Error :" + str (e ))
102+ return _generate_report (cursor , title , sqltext , footerCols , htmlClass , direction , font , totalText , rowIndex , headerRowColor , evenRowColor , oddRowColor )
103+ except Exception as e :
104+ logger .error (traceback .format_exc ())
105+ return f"Error: { str (e )} "
0 commit comments