SS 2025
This commit is contained in:
@@ -0,0 +1,231 @@
|
||||
from flask import Flask, render_template, request
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from tabulate import tabulate
|
||||
from sqlalchemy import text
|
||||
import folium
|
||||
import os
|
||||
from decimal import Decimal
|
||||
|
||||
## INIT
|
||||
app = Flask(__name__, template_folder=os.path.abspath('.'))
|
||||
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL', 'postgresql://huaqo:0000@localhost:5432/geowebapp')
|
||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||
db = SQLAlchemy(app)
|
||||
|
||||
|
||||
## QUERIES
|
||||
DATASET = """
|
||||
SELECT {attributes}
|
||||
FROM Hochschulen h
|
||||
JOIN Mieten m ON m.land = h.land
|
||||
LEFT JOIN Bevoelkerung b ON b.region_name = h.ort
|
||||
AND b.bundesland = h.land
|
||||
AND (
|
||||
b.region_type = 'kreis'
|
||||
OR b.region_name = 'Berlin'
|
||||
OR b.region_name = 'Hamburg'
|
||||
OR b.region_name = 'Bremen'
|
||||
OR b.region_name = 'Hannover' AND b.region_type = 'landeshauptstadt'
|
||||
OR b.region_name = 'Saarbrücken' AND b.region_type = 'landeshauptstadt')
|
||||
WHERE {search_attr} ILIKE :search
|
||||
ORDER BY {sort_by} {order}
|
||||
LIMIT {limit};
|
||||
"""
|
||||
DATASET_GROUPED = """
|
||||
SELECT {group_by}, COUNT(*) AS Anzahl
|
||||
FROM Hochschulen
|
||||
GROUP BY {group_by}
|
||||
ORDER BY Anzahl DESC;
|
||||
"""
|
||||
|
||||
## PARAMETERS
|
||||
order_by_options = [
|
||||
{'value': 'land', 'label': 'Bundesland'},
|
||||
{'value': 'typ', 'label': 'Hochschultyp'},
|
||||
{'value': 'traeger', 'label': 'Träger'},
|
||||
{'value': 'precht', 'label': 'Promotionsrecht'},
|
||||
{'value': 'hrecht', 'label': 'Habilitationsrecht'}
|
||||
]
|
||||
|
||||
shortcut_options = [
|
||||
{'url': '//127.0.0.1:5000/?search_attr=typ&search=&order=ASC&sort_by=gjahr&limit=10&attributes=&attributes=h.name_h&attributes=h.gjahr&attributes=h.ort&generate_map=true', 'label': 'Älteste Hochschulen in Deutschland'},
|
||||
{'url': '//127.0.0.1:5000/?search_attr=typ&search=&order=DESC&sort_by=gjahr&limit=10&attributes=&attributes=h.name_h&attributes=h.gjahr&attributes=h.ort&generate_map=true', 'label': 'Jüngste Hochschulen in Deutschland'},
|
||||
{'url': '//127.0.0.1:5000/?search_attr=typ&search=&order=DESC&sort_by=studenten&limit=10&attributes=&attributes=h.name_h&attributes=h.studenten&attributes=h.ort&generate_map=true', 'label': 'Hochschulen mit den meisten Studenten'},
|
||||
{'url': '//127.0.0.1:5000/?search_attr=h.land&search=Berlin&order=DESC&sort_by=studenten&limit=10&attributes=&attributes=h.name_h&attributes=h.studenten&generate_map=true', 'label': 'Berliner Hochschulen mit den meisten Studenten'},
|
||||
{'url': '//127.0.0.1:5000/?search_attr=typ&search=&order=ASC&sort_by=studenten&limit=10&attributes=&attributes=h.name_h&attributes=h.studenten&attributes=h.ort&generate_map=true', 'label': 'Hochschulen mit den wenigsten Studenten'},
|
||||
{'url': '//127.0.0.1:5000/?search_attr=typ&search=&order=DESC&sort_by=b.total_population&limit=10&attributes=&attributes=h.name_h&attributes=h.ort&attributes=b.total_population&generate_map=true', 'label': 'Hochschulen mit den meisten Einwohnern'},
|
||||
{'url': '//127.0.0.1:5000/?search_attr=typ&search=&order=ASC&sort_by=b.total_population&limit=10&attributes=&attributes=h.name_h&attributes=h.ort&attributes=b.total_population&generate_map=true', 'label': 'Hochschulen mit den wenigsten Einwohnern'},
|
||||
{'url': '//127.0.0.1:5000/?search_attr=typ&search=&order=ASC&sort_by=m.mieten_ab_2019&limit=100&attributes=&attributes=h.name_h&attributes=h.ort&attributes=m.mieten_ab_2019&generate_map=true', 'label': 'Hochschulen mit den niedrigsten Mieten'},
|
||||
{'url': '//127.0.0.1:5000/?search_attr=typ&search=&order=DESC&sort_by=m.mieten_ab_2019&limit=200&attributes=&attributes=h.name_h&attributes=h.ort&attributes=m.mieten_ab_2019&generate_map=true', 'label': 'Hochschulen mit den höchsten Mieten'}
|
||||
]
|
||||
|
||||
search_options = [
|
||||
{'value': 'h.name_h', 'label': 'Hochschulname'},
|
||||
{'value': 'h.typ', 'label': 'Typ'},
|
||||
{'value': 'h.traeger', 'label': 'Träger'},
|
||||
{'value': 'h.land', 'label': 'Land'},
|
||||
{'value': 'h.precht', 'label': 'Precht'},
|
||||
{'value': 'h.hrecht', 'label': 'Hrecht'},
|
||||
{'value': 'h.str', 'label': 'Straße'},
|
||||
{'value': 'h.ort', 'label': 'Ort'},
|
||||
{'value': 'h.web', 'label': 'Web'}
|
||||
]
|
||||
|
||||
order_options = [
|
||||
{'value': 'ASC', 'label': 'Aufsteigend'},
|
||||
{'value': 'DESC', 'label': 'Absteigend'}
|
||||
]
|
||||
|
||||
sort_by_options = [
|
||||
{'value': 'name_h', 'label': 'Hochschulname'},
|
||||
{'value': 'gjahr', 'label': 'Gründungsjahr'},
|
||||
{'value': 'typ', 'label': 'Typ'},
|
||||
{'value': 'traeger', 'label': 'Träger'},
|
||||
{'value': 'land', 'label': 'Land'},
|
||||
{'value': 'studenten', 'label': 'Studenten'},
|
||||
{'value': 'precht', 'label': 'Precht'},
|
||||
{'value': 'hrecht', 'label': 'Hrecht'},
|
||||
{'value': 'plz', 'label': 'PLZ'},
|
||||
{'value': 'str', 'label': 'Straße'},
|
||||
{'value': 'ort', 'label': 'Ort'},
|
||||
{'value': 'b.total_population', 'label': 'Einwohner'},
|
||||
{'value': 'm.mieten_ab_2019', 'label': 'Mieten'}
|
||||
]
|
||||
|
||||
checkbox_options = [
|
||||
{'value': 'h.name_h', 'label': 'Hochschulname'},
|
||||
{'value': 'h.gjahr', 'label': 'Gründungsjahr'},
|
||||
{'value': 'h.typ', 'label': 'Typ'},
|
||||
{'value': 'h.traeger', 'label': 'Träger'},
|
||||
{'value': 'h.land', 'label': 'Land'},
|
||||
{'value': 'h.studenten', 'label': 'Studenten'},
|
||||
{'value': 'h.precht', 'label': 'Precht'},
|
||||
{'value': 'h.hrecht', 'label': 'Hrecht'},
|
||||
{'value': 'h.plz', 'label': 'PLZ'},
|
||||
{'value': 'h.str', 'label': 'Straße'},
|
||||
{'value': 'h.ort', 'label': 'Ort'},
|
||||
{'value': 'h.web', 'label': 'Web'},
|
||||
{'value': 'b.total_population', 'label': 'Einwohner'},
|
||||
{'value': 'm.mieten_ab_2019', 'label': 'Mieten'}
|
||||
]
|
||||
|
||||
## DATA QUERY
|
||||
class Dataset_Parameters:
|
||||
def __init__(self, order='ASC', limit='10', sort_by='gjahr', attributes=['name_h'], search='', search_attr='name_h', group_by='typ'):
|
||||
if attributes is None:
|
||||
attributes = ['name_h']
|
||||
self.order = order
|
||||
self.limit = limit
|
||||
self.sort_by = sort_by
|
||||
self.attributes = attributes
|
||||
self.search = search
|
||||
self.search_attr = search_attr
|
||||
self.group_by = group_by
|
||||
|
||||
def update(self, **kwargs):
|
||||
for key, value in kwargs.items():
|
||||
if hasattr(self, key):
|
||||
setattr(self, key, value)
|
||||
|
||||
@classmethod
|
||||
def get_parameters(cls, request):
|
||||
parameters = cls()
|
||||
parameters.update(
|
||||
order=request.args.get('order', parameters.order),
|
||||
limit=request.args.get('limit', parameters.limit),
|
||||
sort_by=request.args.get('sort_by', parameters.sort_by),
|
||||
attributes=request.args.getlist('attributes') or parameters.attributes,
|
||||
search=request.args.get('search', parameters.search),
|
||||
search_attr=request.args.get('search_attr', parameters.search_attr),
|
||||
group_by=request.args.get('group_by', parameters.group_by)
|
||||
)
|
||||
parameters.attributes = [attr for attr in parameters.attributes if attr]
|
||||
if 'lat' not in parameters.attributes:
|
||||
parameters.attributes.append('lat')
|
||||
if 'lon' not in parameters.attributes:
|
||||
parameters.attributes.append('lon')
|
||||
return parameters
|
||||
|
||||
def get_data(query_template, parameters):
|
||||
params_dict = {k: v for k, v in parameters.__dict__.items()}
|
||||
for key, value in params_dict.items():
|
||||
if isinstance(value, list):
|
||||
params_dict[key] = ', '.join(value)
|
||||
query = query_template.format(**params_dict)
|
||||
result = db.session.execute(text(query), {'search': f"%{params_dict.get('search', '')}%"})
|
||||
|
||||
return result.fetchall()
|
||||
|
||||
## TABLES
|
||||
def create_table(data, parameters):
|
||||
lat_index = parameters.attributes.index('lat') if 'lat' in parameters.attributes else -1
|
||||
lon_index = parameters.attributes.index('lon') if 'lon' in parameters.attributes else -1
|
||||
|
||||
filtered_data = []
|
||||
for row in data:
|
||||
filtered_row = [value for i, value in enumerate(row) if i not in [lat_index, lon_index]]
|
||||
filtered_data.append(filtered_row)
|
||||
|
||||
filtered_attributes = [attr for attr in parameters.attributes if attr not in ['lat', 'lon']]
|
||||
table = tabulate(filtered_data, headers=filtered_attributes, tablefmt='html')
|
||||
return table
|
||||
def create_grouped_table(data, parameters):
|
||||
headers = [parameters.group_by, 'Anzahl']
|
||||
table = tabulate(data, headers=headers, tablefmt='html')
|
||||
return table
|
||||
|
||||
## MAP
|
||||
def generate_map(data, column_names):
|
||||
map_center = [51.1657, 10.4515]
|
||||
map = folium.Map(location=map_center, tiles="cartodb positron", zoom_start=6)
|
||||
|
||||
try:
|
||||
lat_index = column_names.index('lat')
|
||||
lon_index = column_names.index('lon')
|
||||
except ValueError:
|
||||
print("Lat or Lon column not found in the result set")
|
||||
return None
|
||||
|
||||
bounds = []
|
||||
for row in data:
|
||||
lat = row[lat_index]
|
||||
lon = row[lon_index]
|
||||
if isinstance(lat, Decimal):
|
||||
lat = float(lat)
|
||||
if isinstance(lon, Decimal):
|
||||
lon = float(lon)
|
||||
if lat is not None and lon is not None:
|
||||
folium.Marker([lat, lon], popup=f"Data: {row}").add_to(map)
|
||||
bounds.append([lat, lon])
|
||||
|
||||
if bounds:
|
||||
map.fit_bounds(bounds)
|
||||
|
||||
map_html = map._repr_html_()
|
||||
return map_html
|
||||
|
||||
## VIEWS
|
||||
@app.route('/', methods=['GET'])
|
||||
def home():
|
||||
dataset_parameters = Dataset_Parameters.get_parameters(request)
|
||||
dataset = get_data(DATASET, dataset_parameters)
|
||||
dataset_grouped = get_data(DATASET_GROUPED, dataset_parameters)
|
||||
table = create_table(dataset, dataset_parameters)
|
||||
table_grouped = create_grouped_table(dataset_grouped, dataset_parameters)
|
||||
map = generate_map(dataset, dataset_parameters.attributes)
|
||||
return render_template(
|
||||
'index.html',
|
||||
table=table,
|
||||
table_grouped=table_grouped,
|
||||
parameters=dataset_parameters,
|
||||
map=map,
|
||||
order_by_options=order_by_options,
|
||||
search_options=search_options,
|
||||
order_options=order_options,
|
||||
sort_by_options=sort_by_options,
|
||||
shortcut_options=shortcut_options,
|
||||
checkbox_options=checkbox_options)
|
||||
|
||||
## RUN
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
||||
Reference in New Issue
Block a user