or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

bulk-operations.mdcustom-types.mddocuments.mdevents-actions.mdfields-types.mdindex.mdinitialization.mdmigrations.mdquery-operations.mdtime-series.md

events-actions.mddocs/

0

# Events & Actions

1

2

Pre/post event hooks for document lifecycle events with action type constants, enabling flexible business logic integration and data validation workflows.

3

4

## Capabilities

5

6

### Event Decorators

7

8

Decorators that register functions to run before or after specific document lifecycle events.

9

10

```python { .api }

11

def before_event(*actions):

12

"""

13

Decorator to register functions that run before document events.

14

15

Args:

16

*actions: Event action types (Insert, Update, Save, Delete, etc.)

17

18

Returns:

19

Decorator function for event handlers

20

"""

21

...

22

23

def after_event(*actions):

24

"""

25

Decorator to register functions that run after document events.

26

27

Args:

28

*actions: Event action types (Insert, Update, Save, Delete, etc.)

29

30

Returns:

31

Decorator function for event handlers

32

"""

33

...

34

```

35

36

### Action Type Constants

37

38

Event type constants that specify which document lifecycle events to handle.

39

40

```python { .api }

41

class Insert:

42

"""Document insertion event type."""

43

...

44

45

class Replace:

46

"""Document replacement event type."""

47

...

48

49

class Save:

50

"""Document save event type (insert or update)."""

51

...

52

53

class SaveChanges:

54

"""Document save changes event type."""

55

...

56

57

class ValidateOnSave:

58

"""Document validation on save event type."""

59

...

60

61

class Delete:

62

"""Document deletion event type."""

63

...

64

65

class Update:

66

"""Document update event type."""

67

...

68

```

69

70

### Action Direction Constants

71

72

Constants that specify timing of event execution relative to the document operation.

73

74

```python { .api }

75

class Before:

76

"""Before event timing constant."""

77

...

78

79

class After:

80

"""After event timing constant."""

81

...

82

```

83

84

## Usage Examples

85

86

### Basic Event Handlers

87

88

```python

89

from beanie import Document, before_event, after_event

90

from beanie import Insert, Update, Save, Delete

91

from datetime import datetime

92

import logging

93

94

class User(Document):

95

name: str

96

email: str

97

created_at: datetime = None

98

updated_at: datetime = None

99

100

class Settings:

101

collection = "users"

102

103

# Before event handlers

104

@before_event(Insert)

105

async def set_creation_time(self):

106

"""Set creation timestamp before insert."""

107

self.created_at = datetime.utcnow()

108

self.updated_at = datetime.utcnow()

109

110

@before_event(Update, Save)

111

async def set_update_time(self):

112

"""Set update timestamp before modifications."""

113

self.updated_at = datetime.utcnow()

114

115

@before_event(Delete)

116

async def log_deletion(self):

117

"""Log before deleting document."""

118

logging.info(f"Deleting user: {self.name} ({self.email})")

119

120

# After event handlers

121

@after_event(Insert)

122

async def welcome_new_user(self):

123

"""Send welcome email after inserting user."""

124

await send_welcome_email(self.email)

125

logging.info(f"New user registered: {self.name}")

126

127

@after_event(Update)

128

async def audit_changes(self):

129

"""Audit user changes after update."""

130

await log_user_changes(self.id, self.get_changes())

131

132

@after_event(Delete)

133

async def cleanup_user_data(self):

134

"""Clean up related data after user deletion."""

135

await cleanup_user_posts(self.id)

136

await cleanup_user_sessions(self.id)

137

```

138

139

### Multiple Event Types

140

141

```python

142

from beanie import Document, before_event, after_event

143

from beanie import Insert, Update, Save, Delete, Replace

144

145

class Product(Document):

146

name: str

147

price: float

148

stock: int

149

active: bool = True

150

151

class Settings:

152

collection = "products"

153

154

# Handle multiple event types

155

@before_event(Insert, Update, Replace, Save)

156

async def validate_product(self):

157

"""Validate product data before any write operation."""

158

if self.price < 0:

159

raise ValueError("Price cannot be negative")

160

if self.stock < 0:

161

raise ValueError("Stock cannot be negative")

162

163

@after_event(Update, Save)

164

async def update_search_index(self):

165

"""Update search index after product changes."""

166

if self.active:

167

await add_to_search_index(self)

168

else:

169

await remove_from_search_index(self.id)

170

171

@after_event(Insert, Update, Replace)

172

async def invalidate_cache(self):

173

"""Invalidate product cache after modifications."""

174

await cache.delete(f"product:{self.id}")

175

await cache.delete("products:all")

176

```

177

178

### Conditional Event Handling

179

180

```python

181

from beanie import Document, before_event, after_event

182

from beanie import Update, Save

183

import asyncio

184

185

class Order(Document):

186

status: str

187

total: float

188

customer_email: str

189

items: List[Dict] = []

190

191

class Settings:

192

collection = "orders"

193

194

@before_event(Update, Save)

195

async def handle_status_change(self):

196

"""Handle order status changes."""

197

# Get previous state if available

198

if hasattr(self, '_previous_status'):

199

old_status = self._previous_status

200

new_status = self.status

201

202

# Only act on status changes

203

if old_status != new_status:

204

if new_status == "shipped":

205

await self.send_shipping_notification()

206

elif new_status == "delivered":

207

await self.send_delivery_confirmation()

208

elif new_status == "cancelled":

209

await self.restore_inventory()

210

211

async def send_shipping_notification(self):

212

"""Send shipping notification email."""

213

await send_email(

214

to=self.customer_email,

215

subject="Your order has shipped!",

216

body=f"Order #{self.id} is on its way."

217

)

218

219

async def send_delivery_confirmation(self):

220

"""Send delivery confirmation."""

221

await send_email(

222

to=self.customer_email,

223

subject="Order delivered",

224

body=f"Order #{self.id} has been delivered."

225

)

226

227

async def restore_inventory(self):

228

"""Restore inventory for cancelled order."""

229

for item in self.items:

230

await restore_item_stock(item['product_id'], item['quantity'])

231

```

232

233

### Event Handler Registration

234

235

```python

236

# Register event handlers on document classes

237

class BlogPost(Document):

238

title: str

239

content: str

240

author_id: str

241

published: bool = False

242

view_count: int = 0

243

244

class Settings:

245

collection = "posts"

246

247

# Method-based event handlers

248

@before_event(Insert)

249

async def generate_slug(self):

250

"""Generate URL slug before insert."""

251

self.slug = self.title.lower().replace(" ", "-")

252

253

@after_event(Update)

254

async def notify_subscribers(self):

255

"""Notify subscribers when post is published."""

256

if self.published and hasattr(self, '_was_draft'):

257

subscribers = await get_subscribers(self.author_id)

258

await notify_post_published(subscribers, self)

259

260

# External event handlers

261

@before_event(Delete)

262

async def archive_post_content(doc: BlogPost):

263

"""Archive post content before deletion."""

264

await archive_content(doc.id, doc.content)

265

266

@after_event(Insert, Update)

267

async def update_author_stats(doc: BlogPost):

268

"""Update author statistics after post changes."""

269

await update_author_post_count(doc.author_id)

270

```

271

272

## Types

273

274

```python { .api }

275

from typing import Callable, Any, Awaitable

276

from enum import Enum

277

278

# Event handler type

279

EventHandler = Callable[[Any], Awaitable[None]]

280

281

# Action type enumeration

282

class ActionType(Enum):

283

INSERT = "INSERT"

284

UPDATE = "UPDATE"

285

REPLACE = "REPLACE"

286

SAVE = "SAVE"

287

SAVE_CHANGES = "SAVE_CHANGES"

288

VALIDATE_ON_SAVE = "VALIDATE_ON_SAVE"

289

DELETE = "DELETE"

290

291

# Direction type enumeration

292

class ActionDirection(Enum):

293

BEFORE = "BEFORE"

294

AFTER = "AFTER"

295

```