mirror of
https://github.com/Infinidat/infi.clickhouse_orm.git
synced 2024-11-21 16:46:33 +03:00
Added usage examples
This commit is contained in:
parent
bc900c2ef1
commit
c0bdbb7664
1
examples/db_explorer/.gitignore
vendored
Normal file
1
examples/db_explorer/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/env/
|
38
examples/db_explorer/charts.py
Normal file
38
examples/db_explorer/charts.py
Normal file
|
@ -0,0 +1,38 @@
|
|||
import pygal
|
||||
from pygal.style import RotateStyle
|
||||
from jinja2.filters import do_filesizeformat
|
||||
|
||||
|
||||
number_formatter = lambda v: '{:,}'.format(v)
|
||||
bytes_formatter = lambda v: do_filesizeformat(v, True)
|
||||
|
||||
|
||||
def tables_piechart(db, by_field, value_formatter):
|
||||
Tables = db.get_model_for_table('tables', system_table=True)
|
||||
qs = Tables.objects_in(db).filter(database=db.db_name, is_temporary=False).exclude(engine='Buffer')
|
||||
tuples = [(getattr(table, by_field), table.name) for table in qs]
|
||||
return _generate_piechart(tuples, value_formatter)
|
||||
|
||||
|
||||
def columns_piechart(db, tbl_name, by_field, value_formatter):
|
||||
ColumnsTable = db.get_model_for_table('columns', system_table=True)
|
||||
qs = ColumnsTable.objects_in(db).filter(database=db.db_name, table=tbl_name)
|
||||
tuples = [(getattr(col, by_field), col.name) for col in qs]
|
||||
return _generate_piechart(tuples, value_formatter)
|
||||
|
||||
|
||||
def _get_top_tuples(tuples, n=15):
|
||||
non_zero_tuples = [t for t in tuples if t[0]]
|
||||
sorted_tuples = sorted(non_zero_tuples, reverse=True)
|
||||
if len(sorted_tuples) > n:
|
||||
others = (sum(t[0] for t in sorted_tuples[n:]), 'others')
|
||||
sorted_tuples = sorted_tuples[:n] + [others]
|
||||
return sorted_tuples
|
||||
|
||||
|
||||
def _generate_piechart(tuples, value_formatter):
|
||||
style = RotateStyle('#9e6ffe', background='white', legend_font_family='Roboto', legend_font_size=18, tooltip_font_family='Roboto', tooltip_font_size=24)
|
||||
chart = pygal.Pie(style=style, margin=0, title=' ', value_formatter=value_formatter, truncate_legend=-1)
|
||||
for t in _get_top_tuples(tuples):
|
||||
chart.add(t[1], t[0])
|
||||
return chart.render(is_unicode=True, disable_xml_declaration=True)
|
15
examples/db_explorer/requirements.txt
Normal file
15
examples/db_explorer/requirements.txt
Normal file
|
@ -0,0 +1,15 @@
|
|||
certifi==2020.4.5.2
|
||||
chardet==3.0.4
|
||||
click==7.1.2
|
||||
Flask==1.1.2
|
||||
idna==2.9
|
||||
infi.clickhouse-orm==2.0.1
|
||||
iso8601==0.1.12
|
||||
itsdangerous==1.1.0
|
||||
Jinja2==2.11.2
|
||||
MarkupSafe==1.1.1
|
||||
pygal==2.4.0
|
||||
pytz==2020.1
|
||||
requests==2.23.0
|
||||
urllib3==1.25.9
|
||||
Werkzeug==1.0.1
|
63
examples/db_explorer/server.py
Normal file
63
examples/db_explorer/server.py
Normal file
|
@ -0,0 +1,63 @@
|
|||
from infi.clickhouse_orm import Database, F
|
||||
from charts import tables_piechart, columns_piechart, number_formatter, bytes_formatter
|
||||
from flask import Flask
|
||||
from flask import render_template
|
||||
import sys
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def homepage_view():
|
||||
db = _get_db('system')
|
||||
DatabasesTable = db.get_model_for_table('databases', system_table=True)
|
||||
databases = DatabasesTable.objects_in(db).exclude(name='system').order_by(F.lower(DatabasesTable.name))
|
||||
return render_template('homepage.html', db=db, databases=databases)
|
||||
|
||||
|
||||
@app.route('/<db_name>/')
|
||||
def database_view(db_name):
|
||||
db = _get_db(db_name)
|
||||
ColumnsTable = db.get_model_for_table('columns', system_table=True)
|
||||
tables = ColumnsTable.objects_in(db).filter(database=db_name).aggregate(ColumnsTable.table,
|
||||
compressed_size=F.sum(ColumnsTable.data_compressed_bytes),
|
||||
uncompressed_size=F.sum(ColumnsTable.data_uncompressed_bytes),
|
||||
ratio=F.sum(ColumnsTable.data_uncompressed_bytes) / F.sum(ColumnsTable.data_compressed_bytes)
|
||||
).order_by(F.lower(ColumnsTable.table))
|
||||
return render_template('database.html',
|
||||
db=db,
|
||||
tables=tables,
|
||||
tables_piechart_by_rows=tables_piechart(db, 'total_rows', value_formatter=number_formatter),
|
||||
tables_piechart_by_size=tables_piechart(db, 'total_bytes', value_formatter=bytes_formatter),
|
||||
)
|
||||
|
||||
|
||||
@app.route('/<db_name>/<tbl_name>/')
|
||||
def table_view(db_name, tbl_name):
|
||||
db = _get_db(db_name)
|
||||
TablesTable = db.get_model_for_table('tables', system_table=True)
|
||||
tbl_info = TablesTable.objects_in(db).filter(database=db_name, name=tbl_name)[0]
|
||||
create_table_sql = db.raw('SHOW CREATE TABLE %s FORMAT TabSeparatedRaw' % tbl_name)
|
||||
ColumnsTable = db.get_model_for_table('columns', system_table=True)
|
||||
columns = ColumnsTable.objects_in(db).filter(database=db_name, table=tbl_name)
|
||||
return render_template('table.html',
|
||||
db=db,
|
||||
tbl_name=tbl_name,
|
||||
tbl_info=tbl_info,
|
||||
create_table_sql=create_table_sql,
|
||||
columns=columns,
|
||||
piechart=columns_piechart(db, tbl_name, 'data_compressed_bytes', value_formatter=bytes_formatter),
|
||||
)
|
||||
|
||||
|
||||
def _get_db(db_name):
|
||||
db_url = sys.argv[1] if len(sys.argv) > 1 else 'http://localhost:8123/'
|
||||
username = sys.argv[2] if len(sys.argv) > 2 else None
|
||||
password = sys.argv[3] if len(sys.argv) > 3 else None
|
||||
return Database(db_name, db_url, username, password, readonly=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
_get_db('system') # fail early on db connection problems
|
||||
app.run(debug=True)
|
22
examples/db_explorer/templates/base.html
Normal file
22
examples/db_explorer/templates/base.html
Normal file
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>ClickHouse Explorer</title>
|
||||
<link rel="icon" href="data:,">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.0/milligram.css">
|
||||
<script type="text/javascript" src="http://kozea.github.com/pygal.js/latest/pygal-tooltips.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
|
||||
{% block contents %}
|
||||
{% endblock %}
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
54
examples/db_explorer/templates/database.html
Normal file
54
examples/db_explorer/templates/database.html
Normal file
|
@ -0,0 +1,54 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block contents %}
|
||||
|
||||
<h1>{{ db.db_name }}</h1>
|
||||
|
||||
<p>
|
||||
<a href="..">Home</a>
|
||||
»
|
||||
{{ db.db_name }}
|
||||
</p>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="column">
|
||||
<h2>Top Tables by Size</h2>
|
||||
{% autoescape false %}
|
||||
{{ tables_piechart_by_size }}
|
||||
{% endautoescape %}
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<h2>Top Tables by Rows</h2>
|
||||
{% autoescape false %}
|
||||
{{ tables_piechart_by_rows }}
|
||||
{% endautoescape %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<h2>Tables ({{ tables.count() }})</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Uncompressed Size</th>
|
||||
<th>Compressed Size</th>
|
||||
<th>Compression Ratio</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for table in tables %}
|
||||
<tr>
|
||||
<td><a href="{{ table.table|urlencode }}/">{{ table.table }}</a></th>
|
||||
<td>{{ table.uncompressed_size|filesizeformat(true) }}</td>
|
||||
<td>{{ table.compressed_size|filesizeformat(true) }}</td>
|
||||
<td>{% if table.uncompressed_size %} {{ "%.2f" % table.ratio }} {% else %} 1 {% endif %} : 1</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
41
examples/db_explorer/templates/homepage.html
Normal file
41
examples/db_explorer/templates/homepage.html
Normal file
|
@ -0,0 +1,41 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block contents %}
|
||||
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="column-50">
|
||||
|
||||
<h1>ClickHouse Explorer</h1>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>URL</th>
|
||||
<td>{{ db.db_url }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Version</th>
|
||||
<td>{{ db.server_version|join('.') }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Timezone</th>
|
||||
<td>{{ db.server_timezone }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2>Databases ({{ databases.count() }})</h2>
|
||||
<ul>
|
||||
{% for d in databases %}
|
||||
<li>
|
||||
<a href="{{ d.name|urlencode }}/">{{ d.name }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
79
examples/db_explorer/templates/table.html
Normal file
79
examples/db_explorer/templates/table.html
Normal file
|
@ -0,0 +1,79 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block contents %}
|
||||
|
||||
|
||||
<p>
|
||||
<a href="../..">Home</a>
|
||||
»
|
||||
<a href="..">{{ db.db_name }}</a>
|
||||
»
|
||||
{{ tbl_name }}
|
||||
</p>
|
||||
|
||||
<h1>{{ tbl_name }}</h1>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="column">
|
||||
<h2>Details</h2>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Total rows</th>
|
||||
<td>{{ "{:,}".format(tbl_info.total_rows) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Total size</th>
|
||||
<td>{{ tbl_info.total_bytes|filesizeformat(true) }}</td>
|
||||
</tr>
|
||||
{% if tbl_info.total_rows %}
|
||||
<tr>
|
||||
<th>Average row size</th>
|
||||
<td>{{ (tbl_info.total_bytes / tbl_info.total_rows)|filesizeformat(true) }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<th>Engine</th>
|
||||
<td>{{ tbl_info.engine }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<h2>Top Columns by Size</h2>
|
||||
{% autoescape false %}
|
||||
{{ piechart }}
|
||||
{% endautoescape %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<h2>Columns ({{ columns.count() }})</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Uncompressed Size</th>
|
||||
<th>Compressed Size</th>
|
||||
<th>Compression Ratio</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for col in columns %}
|
||||
<tr>
|
||||
<td>{{ col.name }}</td>
|
||||
<td>{{ col.type }}</td>
|
||||
<td>{{ col.data_uncompressed_bytes|filesizeformat(true) }}</td>
|
||||
<td>{{ col.data_compressed_bytes|filesizeformat(true) }}</td>
|
||||
<td>{% if col.data_compressed_bytes %} {{ "%.2f" % (col.data_uncompressed_bytes / col.data_compressed_bytes) }} {% else %} 1 {% endif %} : 1</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>Table Definition</h2>
|
||||
<pre><code>{{ create_table_sql }}</code></pre>
|
||||
|
||||
{% endblock %}
|
Loading…
Reference in New Issue
Block a user