Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversHalloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PC×
FREEDOM251

Freedom251 › Blog › ClickHouse

Generar DDL de ClickHouse desde un modelo Pydantic v2: qué se puede automatizar y qué no

By Freedom251 Team · · 4 min read

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Puedes dejar de escribir a mano la lista de columnas de ClickHouse y derivarla de un modelo Pydantic v2, pero no con una sola llamada. model_json_schema() devuelve JSON Schema, no SQL, y un CREATE TABLE de ClickHouse exige además decisiones de almacenamiento (motor, claves) que ningún modelo de validación contiene. Lo que sí funciona es un generador pequeño que recorra los campos del modelo, traduzca tipos con una tabla explícita y reciba el resto de cláusulas como configuración.

Por qué «un modelo es suficiente» no es del todo cierto

La documentación de Pydantic indica que BaseModel.model_json_schema() (y TypeAdapter.json_schema()) devuelve un diccionario serializable a JSON, conforme a JSON Schema Draft 2020-12 y OpenAPI 3.1.0. Es una descripción interoperable de la forma de los datos. Personalizarla sigue siendo personalizar JSON Schema; no define semántica de ClickHouse.

As an Amazon Associate I earn from qualifying purchases.

Por su parte, la referencia de CREATE TABLE describe una lista de columnas más cláusulas: motor de tabla, expresiones de clave y, según el caso, valores predeterminados, comentarios, codecs, TTL, índices secundarios, proyecciones y restricciones. Nada de eso se deduce de anotaciones como int o str.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Conclusión práctica: el modelo puede ser la fuente de verdad de nombres, tipos y nulabilidad; el motor, el ORDER BY y la partición son política de almacenamiento y deben declararse aparte.

Opciones para conectar Pydantic con ClickHouse

Enfoque Ventaja Límite
Generador propio que lee los campos del modelo La definición de campos queda junto al modelo de aplicación. Debes definir y mantener el mapeo de tipos y cláusulas.
model_json_schema() y luego conversión Usa la salida estándar de Pydantic. JSON Schema no incluye la semántica de tabla de ClickHouse; añade una capa intermedia.
Generador de ClickHouse Connect desde esquemas PyArrow Función oficial documentada que construye CREATE TABLE para tipos escalares comunes. No es un adaptador Pydantic; crea columnas no anulables, lanza TypeError con tipos no admitidos y su documentación pide revisar el SQL.
DDL escrito y mantenido a mano Acceso a todas las cláusulas y cada decisión es visible. Duplica información si el modelo cambia por separado.

El generador de PyArrow está descrito en Advanced inserting. Si ya usas Arrow, puedes construir el esquema Arrow a partir del modelo y reutilizarlo; si no, añadir esa dependencia solo por el DDL probablemente no compense frente a un mapeo propio.

Decisiones que debes fijar antes de escribir código

Mapeo de tipos

Python int no dice si necesitas Int32, Int64 o un tipo sin signo. Elige una anchura por defecto y, para casos distintos, anota el campo con metadatos propios. Un punto de partida razonable, que es una propuesta de diseño y no un comportamiento de Pydantic:

Tipo Python ClickHouse propuesto Decisión pendiente
str String ¿LowCardinality(String) en campos categóricos?
int Int64 Anchura y signo según el dominio.
float Float64 —
bool Bool —
date Date —
datetime DateTime64(3) Precisión y zona horaria.
X | None Nullable(X) Si prefieres valores por defecto en lugar de nulos.

Documenta aparte las reglas para Decimal, enums, listas, modelos anidados, alias y campos excluidos. Mientras no estén definidas, lo más seguro es que el generador falle explícitamente.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Cláusulas de almacenamiento

Motor, base de datos, tabla, ORDER BY y PARTITION BY entran como parámetros. Así el generador no inventa una clave de ordenación que afecta al diseño físico de la tabla.

Un generador mínimo (boceto ilustrativo)

El siguiente código es un boceto de diseño. No se ha ejecutado ni validado contra un servidor ClickHouse; pruébalo con los modelos que realmente admitas.

import types
from datetime import date, datetime
from typing import Union, get_args, get_origin

from pydantic import BaseModel

TYPE_MAP = {
    str: "String",
    int: "Int64",
    float: "Float64",
    bool: "Bool",
    date: "Date",
    datetime: "DateTime64(3)",
}

def _ch_type(name, annotation):
    origin = get_origin(annotation)
    if origin in (Union, types.UnionType):
        args = [a for a in get_args(annotation) if a is not type(None)]
        if len(args) == 1 and len(args) != len(get_args(annotation)):
            return f"Nullable({_ch_type(name, args[0])})"
    if annotation in TYPE_MAP:
        return TYPE_MAP[annotation]
    raise TypeError(f"Campo {name!r}: tipo no soportado {annotation!r}")

def create_table_sql(model, table, engine, order_by):
    cols = [
        f"    `{name}` {_ch_type(name, f.annotation)}"
        for name, f in model.model_fields.items()
    ]
    return (
        f"CREATE TABLE IF NOT EXISTS {table}n(n"
        + ",n".join(cols)
        + f"n)nENGINE = {engine}nORDER BY {order_by}"
    )

class Event(BaseModel):
    id: int
    user: str
    ts: datetime
    score: float | None = None

print(create_table_sql(Event, "events", "MergeTree", "(ts, id)"))

La salida es SQL determinista con cuatro columnas, y score como Nullable(Float64). Un tipo no contemplado (por ejemplo dict) provoca TypeError en lugar de adivinar.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Aplicarlo con seguridad

  1. Imprime o guarda el SQL generado y revísalo antes de ejecutarlo; es la misma recomendación que hace la documentación del generador de ClickHouse Connect.
  2. Ejecútalo con el cliente Python, por ejemplo con client.command(sql), como muestra la página de integración de Python.
  3. Añade pruebas por cada tipo que el generador admite, incluido el caso en que debe fallar.
  4. Trata los cambios de modelo posteriores como migraciones: CREATE TABLE IF NOT EXISTS no altera una tabla existente, así que un campo nuevo requiere un ALTER TABLE deliberado.

Cuándo no compensa generar

Si la tabla usa TTL, codecs, proyecciones, índices secundarios o un motor distinto de MergeTree, probablemente es más claro mantener ese DDL explícito, o ampliar la configuración del generador solo con lo que necesites. Un generador que pretende cubrir cualquier modelo acaba siendo una segunda implementación de CREATE TABLE.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

ClickHouseDDLJSON SchemaPydanticPython

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.