Merge branch 'feature/66_seo' into dev
This commit is contained in:
@@ -122,6 +122,14 @@ Rien d’exceptionnel, je respecte simplement la loi, qui dit que certains outil
|
||||
|
||||
J’utilise pour cela [Matomo](https://matomo.org/), un outil [libre](https://matomo.org/free-software/), paramétré pour être en conformité avec [la recommandation « Cookies »](https://www.cnil.fr/fr/solutions-pour-les-cookies-de-mesure-daudience) de la CNIL. Cela signifie que votre adresse IP, par exemple, est anonymisée avant d’être enregistrée. Il m’est donc impossible d’associer vos visites sur ce site à votre personne."""
|
||||
),
|
||||
html.H4(
|
||||
"Liste des marchés par département", id="liste_marches"
|
||||
),
|
||||
dcc.Markdown(
|
||||
"""
|
||||
- [Marchés par département](/departements)
|
||||
"""
|
||||
),
|
||||
],
|
||||
),
|
||||
# Table of Contents Column
|
||||
|
||||
@@ -7,6 +7,7 @@ from src.callbacks import get_top_org_table
|
||||
from src.figures import DataTable, point_on_map
|
||||
from src.utils import (
|
||||
df,
|
||||
df_acheteurs,
|
||||
filter_table_data,
|
||||
format_number,
|
||||
get_annuaire_data,
|
||||
@@ -20,7 +21,12 @@ from src.utils import (
|
||||
|
||||
|
||||
def get_title(acheteur_id: str = None) -> str:
|
||||
return f"Acheteur {acheteur_id} | decp.info"
|
||||
acheteur_nom = (
|
||||
df_acheteurs.filter(pl.col("acheteur_id") == acheteur_id)
|
||||
.select("acheteur_nom")
|
||||
.item()
|
||||
)
|
||||
return f"Marchés publics attribués par {acheteur_nom} | decp.info"
|
||||
|
||||
|
||||
register_page(
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import polars as pl
|
||||
from dash import Input, Output, callback, dcc, html, register_page
|
||||
|
||||
from src.utils import departements, df_acheteurs_departement, df_titulaires_departement
|
||||
|
||||
name = "Département"
|
||||
|
||||
|
||||
def get_title(code):
|
||||
return f"Marchés publics de {departements[code]['departement']} | decp.info"
|
||||
|
||||
|
||||
def get_description(code):
|
||||
return f"Marchés publics passés dans le département {departements[code]['departement']} | decp.info"
|
||||
|
||||
|
||||
register_page(
|
||||
__name__,
|
||||
path_template="/departements/<code>",
|
||||
title=get_title,
|
||||
description=get_description,
|
||||
order=50,
|
||||
name=name,
|
||||
)
|
||||
|
||||
layout = html.Div(
|
||||
[
|
||||
dcc.Location(id="departement_url", refresh="callback-nav"),
|
||||
html.Div(id="departement_marches"),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@callback(
|
||||
Output(component_id="departement_marches", component_property="children"),
|
||||
Input(component_id="departement_url", component_property="pathname"),
|
||||
)
|
||||
def departement_marches(url):
|
||||
departement = url.split("/")[-1]
|
||||
|
||||
def make_link_list(org_type) -> list:
|
||||
link_list = []
|
||||
if org_type == "acheteur":
|
||||
df = df_acheteurs_departement
|
||||
elif org_type == "titulaire":
|
||||
df = df_titulaires_departement
|
||||
else:
|
||||
raise ValueError
|
||||
|
||||
df = df.filter(pl.col(f"{org_type}_departement_code") == departement)
|
||||
|
||||
for row in df.iter_rows(named=True):
|
||||
li = html.Li(
|
||||
[
|
||||
dcc.Link(
|
||||
row[f"{org_type}_nom"],
|
||||
href=url + f"/{org_type}/{row[f'{org_type}_id']}",
|
||||
title=f"Marchés publics de {row[f'{org_type}_nom']}",
|
||||
),
|
||||
" ",
|
||||
dcc.Link(
|
||||
"(page dédiée)",
|
||||
href=f"/{org_type}s/{row[f'{org_type}_id']}",
|
||||
title=f"Page dédiée aux marchés publics de {row[f'{org_type}_nom']}",
|
||||
),
|
||||
]
|
||||
)
|
||||
link_list.append(li)
|
||||
return link_list
|
||||
|
||||
content = [
|
||||
html.H3("Acheteurs publics du département"),
|
||||
html.Ul(make_link_list("acheteur")),
|
||||
html.H3("Titulaires du département"),
|
||||
html.Ul(make_link_list("titulaire")),
|
||||
]
|
||||
|
||||
return content
|
||||
@@ -0,0 +1,25 @@
|
||||
from dash import dcc, html, register_page
|
||||
|
||||
from src.utils import departements
|
||||
|
||||
name = "Départements"
|
||||
|
||||
register_page(
|
||||
__name__,
|
||||
path="/departements",
|
||||
title="Marchés par département | decp.info",
|
||||
name="Départements",
|
||||
description="Tous les marchés publics, classés par départements",
|
||||
)
|
||||
|
||||
layout = html.Div(
|
||||
[
|
||||
html.H3("Départements"),
|
||||
html.Ul(
|
||||
[
|
||||
html.Li(dcc.Link(d["departement"], href=f"/departements/{k}"))
|
||||
for k, d in departements.items()
|
||||
]
|
||||
),
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,99 @@
|
||||
import polars as pl
|
||||
from dash import Input, Output, callback, dcc, html, register_page
|
||||
|
||||
from src.utils import (
|
||||
df_acheteurs,
|
||||
df_acheteurs_marches,
|
||||
df_titulaires,
|
||||
df_titulaires_marches,
|
||||
)
|
||||
|
||||
name = "Liste des marchés publics"
|
||||
|
||||
|
||||
def make_org_nom_verbe(org_type, org_id) -> tuple:
|
||||
if org_type == "titulaire":
|
||||
df = df_titulaires
|
||||
verbe = "remportés"
|
||||
elif org_type == "acheteur":
|
||||
df = df_acheteurs
|
||||
verbe = "attribués"
|
||||
else:
|
||||
raise ValueError
|
||||
|
||||
org_nom = (
|
||||
df.filter(pl.col(f"{org_type}_id") == org_id).select(f"{org_type}_nom").item()
|
||||
)
|
||||
|
||||
return org_nom, verbe
|
||||
|
||||
|
||||
def get_title(code, org_type, org_id):
|
||||
org_nom, verbe = make_org_nom_verbe(org_type, org_id)
|
||||
|
||||
return f"Marchés publics {verbe} par {org_nom} | decp.info"
|
||||
|
||||
|
||||
def get_description(code, org_type, org_id):
|
||||
org_nom, verbe = make_org_nom_verbe(org_type, org_id)
|
||||
|
||||
return f"Liste complète des marchés publics {verbe} par {org_nom} et publiés par decp.info. Cliquez sur les liens pour consulter les détails de chaque marché."
|
||||
|
||||
|
||||
register_page(
|
||||
__name__,
|
||||
path_template="/departements/<code>/<org_type>/<org_id>",
|
||||
title=get_title,
|
||||
description=get_description,
|
||||
order=40,
|
||||
name=name,
|
||||
)
|
||||
|
||||
layout = html.Div(
|
||||
[
|
||||
dcc.Location(id="liste_marches_url", refresh="callback-nav"),
|
||||
html.Div(id="liste_marches"),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@callback(
|
||||
Output(component_id="liste_marches", component_property="children"),
|
||||
Input(component_id="liste_marches_url", component_property="pathname"),
|
||||
)
|
||||
def liste_marches(url):
|
||||
org_type = url.split("/")[-2]
|
||||
org_id = url.split("/")[-1]
|
||||
|
||||
def make_link_list() -> list:
|
||||
link_list = []
|
||||
if org_type == "acheteur":
|
||||
df = df_acheteurs_marches
|
||||
elif org_type == "titulaire":
|
||||
df = df_titulaires_marches
|
||||
else:
|
||||
raise ValueError
|
||||
|
||||
df = df.filter(pl.col(f"{org_type}_id") == org_id)
|
||||
|
||||
for row in df.iter_rows(named=True):
|
||||
li = html.Li(
|
||||
[
|
||||
dcc.Link(
|
||||
row["objet"],
|
||||
href=f"/marches/{row['uid']}",
|
||||
title=f"Marchés public attribué : {row['objet']}",
|
||||
)
|
||||
]
|
||||
)
|
||||
link_list.append(li)
|
||||
return link_list
|
||||
|
||||
nom, verbe = make_org_nom_verbe(org_type, org_id)
|
||||
|
||||
content = [
|
||||
html.H3(f"Marchés publics {verbe} par {nom}"),
|
||||
html.Ul(make_link_list()),
|
||||
]
|
||||
|
||||
return content
|
||||
+5
-6
@@ -34,9 +34,7 @@ layout = [
|
||||
dcc.Store(id="marche_data"),
|
||||
dcc.Store(id="titulaires_data"),
|
||||
dcc.Location(id="marche_url", refresh="callback-nav"),
|
||||
html.Script(
|
||||
type="application/ld+json", id="marche_jsonld", children=['{"test": "1"}']
|
||||
),
|
||||
html.Script(type="application/ld+json", id="marche_jsonld"),
|
||||
dbc.Container(
|
||||
className="marche_infos",
|
||||
children=[
|
||||
@@ -114,7 +112,7 @@ def get_marche_data(url) -> tuple[dict, list]:
|
||||
Input("titulaires_data", "data"),
|
||||
)
|
||||
def update_marche_info(marche, titulaires):
|
||||
def make_parameter(col):
|
||||
def make_parameter(col, bold=True):
|
||||
column_object = data_schema.get(col)
|
||||
column_name = column_object.get("title") if column_object else col
|
||||
|
||||
@@ -158,10 +156,11 @@ def update_marche_info(marche, titulaires):
|
||||
else:
|
||||
value = ""
|
||||
|
||||
param_content = html.P([column_name, " : ", html.Strong(value)])
|
||||
value = html.Strong(value) if bold else value
|
||||
param_content = html.P([column_name, " : ", value])
|
||||
return param_content
|
||||
|
||||
marche_objet = make_parameter("objet")
|
||||
marche_objet = make_parameter("objet", bold=False)
|
||||
|
||||
marche_infos = [
|
||||
make_parameter("id"),
|
||||
|
||||
+60
-2
@@ -18,8 +18,9 @@ from src.utils import (
|
||||
)
|
||||
from utils import prepare_table_data
|
||||
|
||||
update_date = os.path.getmtime(os.getenv("DATA_FILE_PARQUET_PATH"))
|
||||
update_date = datetime.fromtimestamp(update_date).strftime("%d/%m/%Y")
|
||||
update_date_timestamp = os.path.getmtime(os.getenv("DATA_FILE_PARQUET_PATH"))
|
||||
update_date = datetime.fromtimestamp(update_date_timestamp).strftime("%d/%m/%Y")
|
||||
update_date_iso = datetime.fromtimestamp(update_date_timestamp).isoformat()
|
||||
|
||||
|
||||
name = "Tableau"
|
||||
@@ -48,6 +49,63 @@ datatable = html.Div(
|
||||
|
||||
layout = [
|
||||
dcc.Location(id="tableau_url", refresh=False),
|
||||
html.Script(
|
||||
type="application/ld+json",
|
||||
id="dataset_jsonld",
|
||||
children=[
|
||||
json.dumps(
|
||||
{
|
||||
"@context": "https://schema.org/",
|
||||
"@type": "Dataset",
|
||||
"name": "Données essentielles des marchés publics français (DECP)",
|
||||
"description": "Données de marchés publics exhaustives décrivant les marchés publics attribués en France depuis 2018.",
|
||||
"url": "https://decp.info",
|
||||
"sameAs": "https://www.data.gouv.fr/datasets/608c055b35eb4e6ee20eb325",
|
||||
"keywords": [
|
||||
"marchés publics",
|
||||
"commande publique",
|
||||
"decp",
|
||||
"public procurement",
|
||||
],
|
||||
"license": "https://www.etalab.gouv.fr/licence-ouverte-open-licence",
|
||||
"isAccessibleForFree": True,
|
||||
"creator": {
|
||||
"@type": "Organization",
|
||||
"url": "https://colmo.tech",
|
||||
"name": "Colmo",
|
||||
"sameAs": "https://annuaire-entreprises.data.gouv.fr/entreprise/colmo-989393350",
|
||||
"contactPoint": {
|
||||
"@type": "ContactPoint",
|
||||
"contactType": "Support et contact commercial",
|
||||
"email": "colin@colmo.tech",
|
||||
},
|
||||
},
|
||||
"includedInDataCatalog": {
|
||||
"@type": "DataCatalog",
|
||||
"name": "data.gouv.fr",
|
||||
},
|
||||
"distribution": [
|
||||
{
|
||||
"@type": "DataDownload",
|
||||
"encodingFormat": "CSV",
|
||||
"contentUrl": "https://www.data.gouv.fr/api/1/datasets/r/22847056-61df-452d-837d-8b8ceadbfc52",
|
||||
},
|
||||
{
|
||||
"@type": "DataDownload",
|
||||
"encodingFormat": "Parquet",
|
||||
"contentUrl": "https://www.data.gouv.fr/api/1/datasets/r/11cea8e8-df3e-4ed1-932b-781e2635e432",
|
||||
},
|
||||
],
|
||||
"temporalCoverage": f"2018-01-01/{update_date_iso[:10]}",
|
||||
"spatialCoverage": {
|
||||
"@type": "Place",
|
||||
"address": {"countryCode": "FR"},
|
||||
},
|
||||
},
|
||||
indent=2,
|
||||
)
|
||||
],
|
||||
),
|
||||
html.Div(
|
||||
html.Details(
|
||||
children=[
|
||||
|
||||
@@ -7,6 +7,7 @@ from src.callbacks import get_top_org_table
|
||||
from src.figures import DataTable, point_on_map
|
||||
from src.utils import (
|
||||
df,
|
||||
df_titulaires,
|
||||
filter_table_data,
|
||||
format_number,
|
||||
get_annuaire_data,
|
||||
@@ -20,7 +21,12 @@ from src.utils import (
|
||||
|
||||
|
||||
def get_title(titulaire_id: str = None) -> str:
|
||||
return f"Titulaire {titulaire_id} | decp.info"
|
||||
titulaire_nom = (
|
||||
df_titulaires.filter(pl.col("titulaire_id") == titulaire_id)
|
||||
.select("titulaire_nom")
|
||||
.item()
|
||||
)
|
||||
return f"Marchés publics remportés par {titulaire_nom} | decp.info"
|
||||
|
||||
|
||||
register_page(
|
||||
|
||||
Reference in New Issue
Block a user