Templatejen laatu: declarative_base, ConfigDict, ForeignKey

- models.py: sqlalchemy.ext.declarative → sqlalchemy.orm (poistaa
  MovedIn20Warning-varoituksen)
- schemas.py: class Config → model_config = ConfigDict() (poistaa
  PydanticDeprecatedSince20-varoituksen)
- models.py: _id-kentät saavat ForeignKey("taulu.id") kun speksissä
  on relationship-merkintä

Testattu: 10 erilaista projektia, 78/78 testiä läpi, 0 varoitusta.
This commit is contained in:
2026-04-13 13:18:11 +03:00
parent b88a741f85
commit 42b71dbf77

View File

@@ -1202,18 +1202,27 @@ Blog → Author: name,email,bio(Text|None) / Post: title, content(Text), author_
} }
function tmplModels(spec) { function tmplModels(spec) {
// Kerää tarvittavat SA-tyypit + ForeignKey jos relaatioita
const saTypes = new Set(['Integer']); const saTypes = new Set(['Integer']);
for (const e of spec.entities) for (const f of e.fields) saTypes.add(f.sa_type.match(/^(\w+)/)[1]); for (const e of spec.entities) for (const f of e.fields) saTypes.add(f.sa_type.match(/^(\w+)/)[1]);
const relMap = {};
for (const r of (spec.relationships || [])) {
const target = spec.entities.find(e => e.name === r.to);
if (target) relMap[`${r.from}.${r.field}`] = target.table_name;
}
const hasFk = Object.keys(relMap).length > 0;
if (hasFk) saTypes.add('ForeignKey');
const imports = [...saTypes].sort().join(', '); const imports = [...saTypes].sort().join(', ');
let code = `from sqlalchemy import create_engine, Column, ${imports}\n`; let code = `from sqlalchemy import create_engine, Column, ${imports}\n`;
code += `from sqlalchemy.ext.declarative import declarative_base\nfrom sqlalchemy.orm import sessionmaker\n\n`; code += `from sqlalchemy.orm import declarative_base, sessionmaker\n\n`;
code += `DATABASE_URL = "sqlite:///./app.db"\n`; code += `DATABASE_URL = "sqlite:///./app.db"\n`;
code += `engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})\n`; code += `engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})\n`;
code += `SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)\nBase = declarative_base()\n\n`; code += `SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)\nBase = declarative_base()\n\n`;
for (const e of spec.entities) { for (const e of spec.entities) {
code += `class ${e.name}(Base):\n __tablename__ = "${e.table_name}"\n id = Column(Integer, primary_key=True, index=True)\n`; code += `class ${e.name}(Base):\n __tablename__ = "${e.table_name}"\n id = Column(Integer, primary_key=True, index=True)\n`;
for (const f of e.fields) { for (const f of e.fields) {
let parts = [`Column(${f.sa_type}`]; const fkTarget = relMap[`${e.name}.${f.name}`];
let parts = fkTarget ? [`Column(${f.sa_type}, ForeignKey("${fkTarget}.id")` ] : [`Column(${f.sa_type}`];
if (!f.nullable) parts.push('nullable=False'); if (!f.nullable) parts.push('nullable=False');
if (f.default !== null && f.default !== undefined) parts.push(`default=${pyLiteral(f.default)}`); if (f.default !== null && f.default !== undefined) parts.push(`default=${pyLiteral(f.default)}`);
code += ` ${f.name} = ${parts.join(', ')})\n`; code += ` ${f.name} = ${parts.join(', ')})\n`;
@@ -1232,7 +1241,7 @@ Blog → Author: name,email,bio(Text|None) / Post: title, content(Text), author_
if (/\bdatetime\b/i.test(f.py_type)) dtTypes.add('datetime'); if (/\bdatetime\b/i.test(f.py_type)) dtTypes.add('datetime');
} }
let code = 'from pydantic import BaseModel\n'; let code = 'from pydantic import BaseModel, ConfigDict\n';
if (dtTypes.size > 0) code += `from datetime import ${[...dtTypes].sort().join(', ')}\n`; if (dtTypes.size > 0) code += `from datetime import ${[...dtTypes].sort().join(', ')}\n`;
// extra_imports: suodata pois pelkät nimet kuten "datetime" (jo käsitelty yllä) // extra_imports: suodata pois pelkät nimet kuten "datetime" (jo käsitelty yllä)
@@ -1249,7 +1258,7 @@ Blog → Author: name,email,bio(Text|None) / Post: title, content(Text), author_
else if (f.nullable && f.py_type.includes('None')) code += ` ${f.name}: ${f.py_type} = None\n`; else if (f.nullable && f.py_type.includes('None')) code += ` ${f.name}: ${f.py_type} = None\n`;
else code += ` ${f.name}: ${f.py_type}\n`; else code += ` ${f.name}: ${f.py_type}\n`;
} }
code += `\nclass ${e.name}Response(${e.name}Create):\n id: int\n\n class Config:\n from_attributes = True\n\n`; code += `\nclass ${e.name}Response(${e.name}Create):\n id: int\n model_config = ConfigDict(from_attributes=True)\n\n`;
} }
return code; return code;
} }