Дата: 2025-11-10
Версия: 1.0.0
Вопрос: Как из простых элементов (поля, entity) собрать классы и модули?
Теория:
- MDA (Model-Driven Architecture) - разработка на основе моделей
- DSL (Domain-Specific Languages) - языки для конкретных предметных областей
- Метапрограммирование - код, который генерирует код
Практика (готовые решения для Python):
1. Pydantic - модели данных из описания
2. dataclasses - классы из декораторов
3. SQLAlchemy - ORM модели
4. Jinja2 - генерация кода из шаблонов
5. AST - работа с синтаксическим деревом
6. Cookiecutter - генерация проектов
7. Yeoman/Plop (аналоги для Python)
Для платформы ЦИФРА:
# Описание entity
User:
fields:
- name: id, type: int, primary_key: true
- name: email, type: str, unique: true
- name: password, type: str
# Конструктор генерирует:
# ↓
# 1. SQLAlchemy модель
# 2. Pydantic схему
# 3. FastAPI endpoints
# 4. Alembic миграцию
# 5. Тесты
Концепция: Описываешь ЧТО нужно (модель), система генерирует КАК (код).
┌─────────────────────────────────────────────────────────┐
│ META-УРОВНИ │
├─────────────────────────────────────────────────────────┤
│ M3: Meta-Meta Model (MOF) │
│ "Язык для описания языков моделирования" │
│ ↓ │
│ M2: Meta Model (UML, Ecore) │
│ "Язык для описания моделей" │
│ ↓ │
│ M1: Model (ваша схема) │
│ "Описание сущностей: User, Product, Order" │
│ ↓ │
│ M0: Instance (код) │
│ "Сгенерированный код: models.py, api.py" │
└─────────────────────────────────────────────────────────┘
Пример:
M2 (Meta Model):
Entity:
- name: string
- fields: Field[]
Field:
- name: string
- type: DataType
- constraints: Constraint[]
M1 (Model):
Entity "User":
- Field "id": int, primary_key
- Field "email": string, unique
- Field "password": string
M0 (Generated Code):
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
email = Column(String, unique=True)
password = Column(String)
Концепция: Специализированный язык для конкретной предметной области.
Примеры DSL:
# SQL - DSL для баз данных
SELECT name, email FROM users WHERE id = 1
# HTML - DSL для разметки
<div class="user">
<h1>{{ user.name }}</h1>
</div>
# Ваш DSL для описания entity:
entity User:
id: int @primary_key
email: string @unique @email
password: string @min_length(8)
created_at: datetime @auto_now_add
index:
- email
- created_at
api:
- GET /users
- POST /users
- GET /users/{id}
Парсер DSL → Python код:
# Из DSL выше генерируется:
# 1. SQLAlchemy модель
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
email = Column(String, unique=True, index=True)
password = Column(String)
created_at = Column(DateTime, server_default=func.now(), index=True)
# 2. Pydantic схема
class UserCreate(BaseModel):
email: EmailStr
password: str = Field(min_length=8)
# 3. FastAPI endpoints
@app.get("/users")
async def list_users(): ...
@app.post("/users")
async def create_user(user: UserCreate): ...
@app.get("/users/{id}")
async def get_user(id: int): ...
Что это: Библиотека для создания моделей данных с автовалидацией.
pip install pydantic
Простой пример:
from pydantic import BaseModel, Field, EmailStr
from typing import Optional
# Описание модели
class User(BaseModel):
id: int
email: EmailStr
name: str = Field(min_length=1, max_length=100)
age: Optional[int] = Field(None, ge=0, le=150)
# Использование
user = User(
id=1,
email="john@example.com",
name="John",
age=30
)
print(user.dict()) # {'id': 1, 'email': 'john@example.com', ...}
print(user.json()) # '{"id":1,"email":"john@example.com",...}'
# Автовалидация
try:
User(id=1, email="invalid", name="X")
except ValidationError as e:
print(e)
# email: value is not a valid email address
# age: field required
Для конструктора:
from typing import Type
from pydantic import create_model
def create_entity_model(entity_name: str, fields: dict) -> Type[BaseModel]:
"""
Создаёт Pydantic модель динамически.
entity_name: "User"
fields: {
"id": (int, ...),
"email": (str, ...),
"age": (int, Field(ge=0, le=150))
}
"""
return create_model(entity_name, **fields)
# Использование
UserModel = create_entity_model("User", {
"id": (int, ...),
"email": (str, ...),
"age": (int, Field(default=None, ge=0, le=150))
})
user = UserModel(id=1, email="test@example.com", age=25)
print(user) # id=1 email='test@example.com' age=25
Что это: Встроенный декоратор для создания классов данных.
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class User:
id: int
email: str
name: str
age: Optional[int] = None
is_active: bool = True
# Автоматически создаются:
# - __init__()
# - __repr__()
# - __eq__()
user = User(id=1, email="john@example.com", name="John")
print(user) # User(id=1, email='john@example.com', name='John', age=None, is_active=True)
Динамическое создание:
from dataclasses import make_dataclass
def create_dataclass_from_schema(name: str, fields: list):
"""
fields = [
("id", int),
("email", str),
("age", int, field(default=0))
]
"""
return make_dataclass(name, fields)
UserClass = create_dataclass_from_schema("User", [
("id", int),
("email", str),
("age", int, field(default=0))
])
user = UserClass(id=1, email="test@example.com")
print(user) # User(id=1, email='test@example.com', age=0)
Что это: ORM с декларативным описанием моделей.
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
# Декларативное описание
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
email = Column(String, unique=True)
name = Column(String(100))
# Автоматически создаётся таблица
engine = create_engine("sqlite:///db.sqlite")
Base.metadata.create_all(engine)
Динамическое создание таблиц:
from sqlalchemy import Table, Column, Integer, String, MetaData
def create_table_from_schema(table_name: str, fields: dict):
"""
fields = {
"id": {"type": Integer, "primary_key": True},
"email": {"type": String, "unique": True},
"name": {"type": String(100)}
}
"""
metadata = MetaData()
columns = []
for field_name, field_config in fields.items():
col = Column(
field_name,
field_config["type"],
primary_key=field_config.get("primary_key", False),
unique=field_config.get("unique", False)
)
columns.append(col)
table = Table(table_name, metadata, *columns)
return table
# Использование
users_table = create_table_from_schema("users", {
"id": {"type": Integer, "primary_key": True},
"email": {"type": String, "unique": True},
"name": {"type": String(100)}
})
engine = create_engine("sqlite:///db.sqlite")
users_table.create(engine)
Что это: Шаблонизатор для генерации текста (в том числе кода).
pip install jinja2
Шаблон модели:
# templates/model.py.j2
from sqlalchemy import Column, Integer, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class {{ entity.name }}(Base):
__tablename__ = "{{ entity.table_name }}"
{% for field in entity.fields %}
{{ field.name }} = Column(
{{ field.type }},
{% if field.primary_key %}primary_key=True,{% endif %}
{% if field.unique %}unique=True,{% endif %}
{% if field.nullable %}nullable=True{% else %}nullable=False{% endif %}
)
{% endfor %}
def __repr__(self):
return f"<{{ entity.name }}(id={self.id})>"
Генератор:
from jinja2 import Environment, FileSystemLoader
# Конфигурация entity
entity_config = {
"name": "User",
"table_name": "users",
"fields": [
{"name": "id", "type": "Integer", "primary_key": True, "nullable": False},
{"name": "email", "type": "String", "unique": True, "nullable": False},
{"name": "name", "type": "String(100)", "nullable": False},
{"name": "age", "type": "Integer", "nullable": True}
]
}
# Загрузка шаблона
env = Environment(loader=FileSystemLoader("templates"))
template = env.get_template("model.py.j2")
# Генерация кода
generated_code = template.render(entity=entity_config)
# Сохранение
with open("generated/models.py", "w") as f:
f.write(generated_code)
print(generated_code)
Результат (generated/models.py):
from sqlalchemy import Column, Integer, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id = Column(
Integer,
primary_key=True,
nullable=False
)
email = Column(
String,
unique=True,
nullable=False
)
name = Column(
String(100),
nullable=False
)
age = Column(
Integer,
nullable=True
)
def __repr__(self):
return f"<User(id={self.id})>"
Что это: Работа с синтаксическим деревом Python кода.
import ast
# Генерация класса программно
def generate_class(class_name: str, fields: list):
"""
Создаёт Python класс через AST.
fields = [
{"name": "id", "type": "int"},
{"name": "email", "type": "str"}
]
"""
# Создаём __init__ метод
init_args = [ast.arg(arg="self", annotation=None)]
init_args += [
ast.arg(arg=field["name"], annotation=ast.Name(id=field["type"], ctx=ast.Load()))
for field in fields
]
init_body = [
ast.Assign(
targets=[ast.Attribute(value=ast.Name(id="self", ctx=ast.Load()), attr=field["name"], ctx=ast.Store())],
value=ast.Name(id=field["name"], ctx=ast.Load())
)
for field in fields
]
init_func = ast.FunctionDef(
name="__init__",
args=ast.arguments(
posonlyargs=[],
args=init_args,
kwonlyargs=[],
kw_defaults=[],
defaults=[]
),
body=init_body,
decorator_list=[],
returns=None
)
# Создаём класс
class_def = ast.ClassDef(
name=class_name,
bases=[],
keywords=[],
body=[init_func],
decorator_list=[]
)
# Создаём модуль
module = ast.Module(body=[class_def], type_ignores=[])
# Компилируем в код
code = compile(module, filename="<ast>", mode="exec")
# Выполняем
namespace = {}
exec(code, namespace)
return namespace[class_name]
# Использование
User = generate_class("User", [
{"name": "id", "type": "int"},
{"name": "email", "type": "str"}
])
user = User(id=1, email="test@example.com")
print(user.id, user.email) # 1 test@example.com
Преобразование AST → код:
import ast
import astor # pip install astor
# AST объект
class_def = ast.ClassDef(
name="User",
bases=[],
keywords=[],
body=[...],
decorator_list=[]
)
# AST → Python код (строка)
code = astor.to_source(class_def)
print(code)
Что это: Генератор проектов из шаблонов.
pip install cookiecutter
Создание шаблона:
my-template/
├── cookiecutter.json # Параметры
└── {{cookiecutter.project_name}}/
├── models.py
├── api.py
└── README.md
cookiecutter.json:
{
"project_name": "my_project",
"entity_name": "User",
"fields": [
{"name": "id", "type": "int"},
{"name": "email", "type": "str"}
]
}
models.py (шаблон):
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class {{ cookiecutter.entity_name }}(Base):
__tablename__ = "{{ cookiecutter.entity_name.lower() }}s"
{% for field in cookiecutter.fields %}
{{ field.name }} = Column({{ field.type | capitalize }})
{% endfor %}
Использование:
cookiecutter my-template/
# Вводите параметры:
project_name: analytics
entity_name: Report
fields: [{"name": "id", "type": "int"}, {"name": "title", "type": "str"}]
# Создаётся проект:
analytics/
├── models.py
├── api.py
└── README.md
Концепция: Описываешь serializer → получаешь валидацию + API.
from rest_framework import serializers
class UserSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
email = serializers.EmailField()
name = serializers.CharField(max_length=100)
age = serializers.IntegerField(min_value=0, max_value=150, required=False)
# Автоматически:
# - Валидация
# - Сериализация (Python → JSON)
# - Десериализация (JSON → Python)
data = {"id": 1, "email": "test@example.com", "name": "John"}
serializer = UserSerializer(data=data)
if serializer.is_valid():
print(serializer.validated_data)
pip install marshmallow
from marshmallow import Schema, fields, validate
class UserSchema(Schema):
id = fields.Int(required=True)
email = fields.Email(required=True)
name = fields.Str(required=True, validate=validate.Length(min=1, max=100))
age = fields.Int(validate=validate.Range(min=0, max=150))
schema = UserSchema()
result = schema.load({"id": 1, "email": "test@example.com", "name": "John", "age": 30})
print(result) # {'id': 1, 'email': 'test@example.com', 'name': 'John', 'age': 30}
pip install attrs
import attr
@attr.s(auto_attribs=True)
class User:
id: int
email: str
name: str
age: int = 0
# Автоматически создаются:
# - __init__
# - __repr__
# - __eq__
# - Валидаторы
user = User(id=1, email="test@example.com", name="John")
print(user) # User(id=1, email='test@example.com', name='John', age=0)
┌─────────────────────────────────────────────────────────┐
│ YAML ОПИСАНИЕ │
│ entities: │
│ User: │
│ fields: │
│ - name: id, type: int, primary_key: true │
│ - name: email, type: str, unique: true │
│ api: │
│ - GET /users │
│ - POST /users │
└────────────────────┬────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────┐
│ PARSER (YAML → Python) │
│ entity_config = yaml.safe_load(...) │
└────────────────────┬────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────┐
│ CODE GENERATOR │
│ ┌────────────────────────────────────────────────┐ │
│ │ 1. SQLAlchemy Model (Jinja2) │ │
│ │ templates/sqlalchemy_model.py.j2 │ │
│ ├────────────────────────────────────────────────┤ │
│ │ 2. Pydantic Schema (create_model) │ │
│ │ UserCreate, UserResponse │ │
│ ├────────────────────────────────────────────────┤ │
│ │ 3. FastAPI Endpoints (Jinja2) │ │
│ │ templates/fastapi_crud.py.j2 │ │
│ ├────────────────────────────────────────────────┤ │
│ │ 4. Alembic Migration (Jinja2) │ │
│ │ templates/alembic_migration.py.j2 │ │
│ ├────────────────────────────────────────────────┤ │
│ │ 5. Tests (Jinja2) │ │
│ │ templates/test_entity.py.j2 │ │
│ └────────────────────────────────────────────────┘ │
└────────────────────┬────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────┐
│ GENERATED CODE │
│ ├── models/user.py (SQLAlchemy) │
│ ├── schemas/user.py (Pydantic) │
│ ├── api/users.py (FastAPI CRUD) │
│ ├── migrations/001_user.py (Alembic) │
│ └── tests/test_user.py (pytest) │
└─────────────────────────────────────────────────────────┘
Файл: schemas/User.yaml
entity:
name: User
table_name: users
description: "Пользователь системы"
fields:
- name: id
type: integer
primary_key: true
auto_increment: true
- name: email
type: string
max_length: 255
unique: true
nullable: false
validators:
- email
- name: username
type: string
max_length: 100
unique: true
nullable: false
validators:
- min_length: 3
- alphanumeric
- name: password_hash
type: string
max_length: 255
nullable: false
- name: is_active
type: boolean
default: true
- name: created_at
type: datetime
auto_now_add: true
- name: updated_at
type: datetime
auto_now: true
indexes:
- fields: [email]
unique: true
- fields: [username]
unique: true
- fields: [created_at]
relationships:
- name: posts
entity: Post
type: one_to_many
foreign_key: user_id
api:
endpoints:
- method: GET
path: /users
description: "Список пользователей"
auth: true
- method: POST
path: /users
description: "Создать пользователя"
auth: false
- method: GET
path: /users/{id}
description: "Получить пользователя"
auth: true
- method: PUT
path: /users/{id}
description: "Обновить пользователя"
auth: true
- method: DELETE
path: /users/{id}
description: "Удалить пользователя"
auth: true
admin_only: true
permissions:
create: ["anonymous"]
read: ["authenticated"]
update: ["owner", "admin"]
delete: ["admin"]
generator.py:
import yaml
from jinja2 import Environment, FileSystemLoader
from pathlib import Path
from pydantic import create_model
class CodeGenerator:
def __init__(self, templates_dir: str, output_dir: str):
self.env = Environment(loader=FileSystemLoader(templates_dir))
self.output_dir = Path(output_dir)
def generate_from_yaml(self, yaml_file: str):
"""Генерирует код из YAML описания"""
# 1. Загрузка YAML
with open(yaml_file) as f:
config = yaml.safe_load(f)
entity_name = config["entity"]["name"]
# 2. Генерация SQLAlchemy модели
self._generate_sqlalchemy_model(config)
# 3. Генерация Pydantic схем
self._generate_pydantic_schemas(config)
# 4. Генерация FastAPI endpoints
self._generate_fastapi_endpoints(config)
# 5. Генерация Alembic миграции
self._generate_alembic_migration(config)
# 6. Генерация тестов
self._generate_tests(config)
print(f"✅ Generated code for {entity_name}")
def _generate_sqlalchemy_model(self, config):
"""Генерирует SQLAlchemy модель"""
template = self.env.get_template("sqlalchemy_model.py.j2")
code = template.render(entity=config)
output_file = self.output_dir / "models" / f"{config['entity']['name'].lower()}.py"
output_file.parent.mkdir(parents=True, exist_ok=True)
output_file.write_text(code)
def _generate_pydantic_schemas(self, config):
"""Генерирует Pydantic схемы"""
template = self.env.get_template("pydantic_schemas.py.j2")
code = template.render(entity=config)
output_file = self.output_dir / "schemas" / f"{config['entity']['name'].lower()}.py"
output_file.parent.mkdir(parents=True, exist_ok=True)
output_file.write_text(code)
def _generate_fastapi_endpoints(self, config):
"""Генерирует FastAPI CRUD endpoints"""
template = self.env.get_template("fastapi_crud.py.j2")
code = template.render(entity=config)
output_file = self.output_dir / "api" / f"{config['entity']['name'].lower()}s.py"
output_file.parent.mkdir(parents=True, exist_ok=True)
output_file.write_text(code)
def _generate_alembic_migration(self, config):
"""Генерирует Alembic миграцию"""
template = self.env.get_template("alembic_migration.py.j2")
code = template.render(entity=config)
import datetime
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"{timestamp}_create_{config['entity']['table_name']}.py"
output_file = self.output_dir / "migrations" / "versions" / filename
output_file.parent.mkdir(parents=True, exist_ok=True)
output_file.write_text(code)
def _generate_tests(self, config):
"""Генерирует pytest тесты"""
template = self.env.get_template("test_entity.py.j2")
code = template.render(entity=config)
output_file = self.output_dir / "tests" / f"test_{config['entity']['name'].lower()}.py"
output_file.parent.mkdir(parents=True, exist_ok=True)
output_file.write_text(code)
# Использование
if __name__ == "__main__":
generator = CodeGenerator(
templates_dir="templates",
output_dir="generated"
)
generator.generate_from_yaml("schemas/User.yaml")
templates/sqlalchemy_model.py.j2:
from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime
Base = declarative_base()
class {{ entity.name }}(Base):
"""{{ entity.description }}"""
__tablename__ = "{{ entity.table_name }}"
{% for field in fields %}
{{ field.name }} = Column(
{% if field.type == "integer" %}Integer{% endif %}
{% if field.type == "string" %}String({{ field.max_length | default(255) }}){% endif %}
{% if field.type == "boolean" %}Boolean{% endif %}
{% if field.type == "datetime" %}DateTime{% endif %},
{% if field.primary_key %}primary_key=True,{% endif %}
{% if field.auto_increment %}autoincrement=True,{% endif %}
{% if field.unique %}unique=True,{% endif %}
{% if field.nullable == false %}nullable=False,{% endif %}
{% if field.default is defined %}default={{ field.default }},{% endif %}
{% if field.auto_now_add %}default=datetime.utcnow,{% endif %}
{% if field.auto_now %}onupdate=datetime.utcnow,{% endif %}
)
{% endfor %}
{% for rel in relationships %}
{{ rel.name }} = relationship("{{ rel.entity }}", back_populates="{{ entity.name.lower() }}")
{% endfor %}
def __repr__(self):
return f"<{{ entity.name }}(id={self.id})>"
templates/fastapi_crud.py.j2:
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from typing import List
from ..database import get_db
from ..models.{{ entity.name.lower() }} import {{ entity.name }}
from ..schemas.{{ entity.name.lower() }} import {{ entity.name }}Create, {{ entity.name }}Response
router = APIRouter(prefix="/{{ entity.table_name }}", tags=["{{ entity.table_name }}"])
{% for endpoint in api.endpoints %}
{% if endpoint.method == "GET" and "{id}" not in endpoint.path %}
@router.get("", response_model=List[{{ entity.name }}Response])
async def list_{{ entity.table_name }}(
skip: int = 0,
limit: int = 100,
db: Session = Depends(get_db)
):
"""{{ endpoint.description }}"""
items = db.query({{ entity.name }}).offset(skip).limit(limit).all()
return items
{% endif %}
{% if endpoint.method == "POST" %}
@router.post("", response_model={{ entity.name }}Response, status_code=201)
async def create_{{ entity.name.lower() }}(
data: {{ entity.name }}Create,
db: Session = Depends(get_db)
):
"""{{ endpoint.description }}"""
item = {{ entity.name }}(**data.dict())
db.add(item)
db.commit()
db.refresh(item)
return item
{% endif %}
{% if endpoint.method == "GET" and "{id}" in endpoint.path %}
@router.get("/{id}", response_model={{ entity.name }}Response)
async def get_{{ entity.name.lower() }}(
id: int,
db: Session = Depends(get_db)
):
"""{{ endpoint.description }}"""
item = db.query({{ entity.name }}).filter({{ entity.name }}.id == id).first()
if not item:
raise HTTPException(status_code=404, detail="{{ entity.name }} not found")
return item
{% endif %}
{% if endpoint.method == "PUT" %}
@router.put("/{id}", response_model={{ entity.name }}Response)
async def update_{{ entity.name.lower() }}(
id: int,
data: {{ entity.name }}Create,
db: Session = Depends(get_db)
):
"""{{ endpoint.description }}"""
item = db.query({{ entity.name }}).filter({{ entity.name }}.id == id).first()
if not item:
raise HTTPException(status_code=404, detail="{{ entity.name }} not found")
for key, value in data.dict().items():
setattr(item, key, value)
db.commit()
db.refresh(item)
return item
{% endif %}
{% if endpoint.method == "DELETE" %}
@router.delete("/{id}", status_code=204)
async def delete_{{ entity.name.lower() }}(
id: int,
db: Session = Depends(get_db)
):
"""{{ endpoint.description }}"""
item = db.query({{ entity.name }}).filter({{ entity.name }}.id == id).first()
if not item:
raise HTTPException(status_code=404, detail="{{ entity.name }} not found")
db.delete(item)
db.commit()
return None
{% endif %}
{% endfor %}
Шаг 1: Описываете entity (YAML)
# schemas/Product.yaml
entity:
name: Product
table_name: products
fields:
- name: id
type: integer
primary_key: true
- name: name
type: string
max_length: 200
- name: price
type: integer
api:
endpoints:
- method: GET
path: /products
- method: POST
path: /products
Шаг 2: Запускаете генератор
python generator.py schemas/Product.yaml
Шаг 3: Получаете готовый код
generated/
├── models/product.py # SQLAlchemy модель
├── schemas/product.py # Pydantic схемы
├── api/products.py # FastAPI CRUD
├── migrations/..._create_products.py
└── tests/test_product.py
Шаг 4: Подключаете к приложению
# main.py
from fastapi import FastAPI
from generated.api.products import router as products_router
app = FastAPI()
app.include_router(products_router)
Готово! API работает:
GET /products - Список
POST /products - Создать
GET /products/1 - Получить
PUT /products/1 - Обновить
DELETE /products/1 - Удалить
Идея: Claude анализирует текстовый запрос → генерирует YAML → конструктор генерирует код.
Пользователь: "Создай сущность Product с полями name, price, stock"
↓
Claude API: Анализ → YAML
↓
{
entity: {name: "Product", table_name: "products"},
fields: [
{name: "id", type: "integer", primary_key: true},
{name: "name", type: "string", max_length: 200},
{name: "price", type: "integer"},
{name: "stock", type: "integer", default: 0}
],
api: {endpoints: [...]}
}
↓
Code Generator: YAML → Python код
↓
Готовые файлы: models.py, api.py, schemas.py
Реализация:
import anthropic
from generator import CodeGenerator
async def ai_powered_generator(user_request: str):
"""
AI-powered конструктор:
Текстовый запрос → Claude генерирует YAML → Генератор создаёт код
"""
# 1. Claude генерирует YAML
claude = anthropic.Anthropic(api_key="...")
prompt = f"""
Создай YAML описание entity для следующего запроса:
"{user_request}"
Формат YAML:
entity:
name: "EntityName"
table_name: "table_name"
fields:
- name: id, type: integer, primary_key: true
- name: ..., type: ..., ...
api:
endpoints:
- method: GET, path: /items
- method: POST, path: /items
Верни ТОЛЬКО YAML, без комментариев.
"""
response = await claude.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=2000,
messages=[{"role": "user", "content": prompt}]
)
yaml_content = response.content[0].text
# 2. Сохраняем YAML
yaml_file = "schemas/generated.yaml"
with open(yaml_file, "w") as f:
f.write(yaml_content)
# 3. Генерируем код
generator = CodeGenerator(
templates_dir="templates",
output_dir="generated"
)
generator.generate_from_yaml(yaml_file)
return {
"yaml": yaml_content,
"files_generated": [
"models/entity.py",
"schemas/entity.py",
"api/entities.py"
]
}
# Использование
result = await ai_powered_generator(
"Создай сущность User с email, password, is_active"
)
YAML (описание entity)
↓
Claude API (генерация YAML из текста)
↓
Python Parser (PyYAML)
↓
Code Generator:
├── Jinja2 (шаблоны)
├── Pydantic (динамические модели)
└── AST (если нужна гибкость)
↓
Generated Code:
├── SQLAlchemy models
├── Pydantic schemas
├── FastAPI endpoints
├── Alembic migrations
└── Tests
Вопрос: Существует ли что-то для описания entity → генерация кода?
Ответ: ДА! Множество решений:
Теория:
- MDA (Model-Driven Architecture)
- DSL (Domain-Specific Languages)
- Метапрограммирование
Практика (Python):
- Pydantic - модели с валидацией
- dataclasses - классы данных
- SQLAlchemy - ORM модели
- Jinja2 - генерация кода из шаблонов
- AST - работа с синтаксическим деревом
- Cookiecutter - генерация проектов
Для платформы ЦИФРА:
Описание (YAML) + Claude API + Jinja2 = Готовый код
Время разработки конструктора: 3-5 дней
Экономия времени после: Каждая новая entity = 5 секунд вместо 1 часа!
Версия: 1.0.0
Статус: Готово к обсуждению
Следующий шаг: Начать разработку конструктора?