or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

development-tools.mdextension-setup.mdindex.mdmodels-tables.mdpagination.mdquery-interface.mdsession-management.md

models-tables.mddocs/

0

# Models and Tables

1

2

Declarative model base classes with automatic table naming, bind key support, and Flask integration features. Includes table creation utilities and metadata management.

3

4

## Capabilities

5

6

### Model Base Class

7

8

The declarative base class for defining database models with Flask-SQLAlchemy enhancements.

9

10

```python { .api }

11

class Model:

12

"""

13

Base class for declarative database models.

14

15

Provides Flask-SQLAlchemy specific functionality including

16

automatic table naming and query property integration.

17

"""

18

19

__fsa__: SQLAlchemy # Internal reference to extension

20

query_class: type[Query] # Query class for model queries

21

query: Query # Query property for this model

22

23

def __repr__(self) -> str:

24

"""String representation showing model name and primary key."""

25

```

26

27

### Query Property Implementation

28

29

Internal class that implements the `query` property on model classes.

30

31

```python { .api }

32

class _QueryProperty:

33

"""

34

A class property that creates a query object for a model.

35

36

This is the internal implementation behind Model.query. It creates

37

a Query instance bound to the model class and current session.

38

39

Note: This is an internal class but is documented for completeness

40

since users interact with it through Model.query.

41

"""

42

43

def __get__(self, obj: Model | None, cls: type[Model]) -> Query:

44

"""

45

Create and return a Query instance for the model class.

46

47

Parameters:

48

- obj: Model instance (unused, queries are class-level)

49

- cls: Model class to create query for

50

51

Returns:

52

Query instance bound to the model class and current session

53

"""

54

```

55

56

### Table Class

57

58

Enhanced Table class that automatically selects metadata based on bind keys.

59

60

```python { .api }

61

class Table(sa.Table):

62

def __init__(

63

self,

64

name: str,

65

*args: sa_sql_schema.SchemaItem,

66

bind_key: str | None = None,

67

**kwargs: Any,

68

) -> None:

69

"""

70

Create a table with automatic metadata selection.

71

72

Parameters:

73

- name: Table name

74

- args: Columns, constraints, and other schema items

75

- bind_key: Bind key to select appropriate metadata

76

- kwargs: Additional table arguments

77

"""

78

```

79

80

### Bind Key Mixins

81

82

Mixins that provide automatic metadata selection based on model bind keys.

83

84

```python { .api }

85

class BindMixin:

86

"""

87

DeclarativeBase mixin to set model metadata based on __bind_key__.

88

89

For SQLAlchemy 2.x declarative base classes.

90

"""

91

92

__fsa__: SQLAlchemy

93

metadata: sa.MetaData

94

95

@classmethod

96

def __init_subclass__(cls, **kwargs: dict[str, Any]) -> None:

97

"""Set metadata based on __bind_key__ if present."""

98

99

class BindMetaMixin(type):

100

"""

101

Metaclass mixin for automatic bind key metadata assignment.

102

103

For SQLAlchemy 1.x declarative metaclass usage.

104

"""

105

106

def __init__(

107

cls,

108

name: str,

109

bases: tuple[type, ...],

110

d: dict[str, Any],

111

**kwargs: Any,

112

) -> None:

113

"""Set metadata based on __bind_key__ during class creation."""

114

```

115

116

### Table Naming Mixins

117

118

Mixins that provide automatic table name generation from class names.

119

120

```python { .api }

121

class NameMixin:

122

"""

123

DeclarativeBase mixin for automatic __tablename__ generation.

124

125

Converts CamelCase model names to snake_case table names.

126

For SQLAlchemy 2.x declarative base classes.

127

"""

128

129

@classmethod

130

def __init_subclass__(cls, **kwargs: dict[str, Any]) -> None:

131

"""Generate __tablename__ if not explicitly set."""

132

133

@classmethod

134

def __table_cls__(cls, *args: Any, **kwargs: Any) -> sa.Table | None:

135

"""Determine final table object for the model."""

136

137

class NameMetaMixin(type):

138

"""

139

Metaclass mixin for automatic table naming.

140

141

For SQLAlchemy 1.x declarative metaclass usage.

142

"""

143

144

def __init__(

145

cls,

146

name: str,

147

bases: tuple[type, ...],

148

d: dict[str, Any],

149

**kwargs: Any,

150

) -> None:

151

"""Generate __tablename__ during class creation."""

152

153

def __table_cls__(cls, *args: Any, **kwargs: Any) -> sa.Table | None:

154

"""Determine final table object for the model."""

155

```

156

157

### Default Metaclasses

158

159

Combined metaclasses that provide both bind key and naming functionality.

160

161

```python { .api }

162

class DefaultMeta(BindMetaMixin, NameMetaMixin, sa_orm.DeclarativeMeta):

163

"""

164

SQLAlchemy declarative metaclass with __bind_key__ and __tablename__ support.

165

166

Combines bind key metadata selection and automatic table naming.

167

"""

168

169

class DefaultMetaNoName(BindMetaMixin, sa_orm.DeclarativeMeta):

170

"""

171

SQLAlchemy declarative metaclass with __bind_key__ support only.

172

173

Provides bind key functionality without automatic table naming.

174

"""

175

```

176

177

### Utility Functions

178

179

Helper functions for table naming and model configuration.

180

181

```python { .api }

182

def should_set_tablename(cls: type) -> bool:

183

"""

184

Determine whether __tablename__ should be generated for a model.

185

186

Parameters:

187

- cls: Model class to check

188

189

Returns:

190

True if __tablename__ should be auto-generated

191

"""

192

193

def camel_to_snake_case(name: str) -> str:

194

"""

195

Convert CamelCase name to snake_case.

196

197

Parameters:

198

- name: CamelCase string to convert

199

200

Returns:

201

snake_case version of the name

202

"""

203

```

204

205

## Usage Examples

206

207

### Basic Model Definition

208

209

```python

210

class User(db.Model):

211

id = db.Column(db.Integer, primary_key=True)

212

username = db.Column(db.String(80), unique=True, nullable=False)

213

email = db.Column(db.String(120), unique=True, nullable=False)

214

215

# Table name automatically generated as 'user'

216

```

217

218

### SQLAlchemy 2.x Style Models

219

220

```python

221

from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

222

223

class Base(DeclarativeBase):

224

pass

225

226

db = SQLAlchemy(app, model_class=Base)

227

228

class User(db.Model):

229

id: Mapped[int] = mapped_column(db.Integer, primary_key=True)

230

username: Mapped[str] = mapped_column(db.String(80), unique=True)

231

```

232

233

### Multiple Database Models

234

235

```python

236

class User(db.Model):

237

__bind_key__ = 'users'

238

id = db.Column(db.Integer, primary_key=True)

239

username = db.Column(db.String(80), unique=True)

240

241

class Log(db.Model):

242

__bind_key__ = 'logs'

243

id = db.Column(db.Integer, primary_key=True)

244

message = db.Column(db.Text)

245

timestamp = db.Column(db.DateTime, default=datetime.utcnow)

246

```

247

248

### Custom Table Names

249

250

```python

251

class UserAccount(db.Model):

252

__tablename__ = 'accounts' # Override automatic naming

253

id = db.Column(db.Integer, primary_key=True)

254

name = db.Column(db.String(100))

255

```

256

257

### Direct Table Creation

258

259

```python

260

users_table = db.Table(

261

'users',

262

db.Column('id', db.Integer, primary_key=True),

263

db.Column('name', db.String(50)),

264

bind_key='users' # Specify bind key for metadata selection

265

)

266

```

267

268

### Disabling Automatic Naming

269

270

```python

271

# Disable automatic table naming globally

272

db = SQLAlchemy(app, disable_autonaming=True)

273

274

class User(db.Model):

275

__tablename__ = 'users' # Must specify explicitly

276

id = db.Column(db.Integer, primary_key=True)

277

```

278

279

## Model Querying

280

281

All models automatically get a `query` property for database queries:

282

283

```python

284

# Query using the model's query property

285

user = User.query.get(1)

286

users = User.query.filter_by(active=True).all()

287

288

# The query property uses the configured query_class

289

users = User.query.filter(User.age > 18).paginate(page=1, per_page=10)

290

```