or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

admin-extensions.mdindex.mdmanagement-commands.mdmodel-base-classes.mdmodel-fields.mdtemplate-tags.mdvalidators.md

model-base-classes.mddocs/

0

# Model Base Classes

1

2

Django Extensions provides abstract model classes that implement common functionality patterns including timestamps, activation status, and title/description/slug combinations. These base classes reduce boilerplate code and provide consistent implementations of frequently needed model patterns.

3

4

## Capabilities

5

6

### TimeStampedModel

7

8

Abstract base class that provides self-managed "created" and "modified" fields with automatic timestamp handling.

9

10

```python { .api }

11

class TimeStampedModel(models.Model):

12

created: CreationDateTimeField # Automatically set on creation

13

modified: ModificationDateTimeField # Automatically updated on save

14

15

def save(self, update_modified=True, **kwargs):

16

"""

17

Save the model instance.

18

19

Parameters:

20

- update_modified: If False, prevents modification timestamp update

21

"""

22

23

class Meta:

24

get_latest_by = 'modified'

25

abstract = True

26

```

27

28

Usage examples:

29

30

```python

31

from django.db import models

32

from django_extensions.db.models import TimeStampedModel

33

34

class Article(TimeStampedModel):

35

title = models.CharField(max_length=200)

36

content = models.TextField()

37

# created and modified fields are automatically added

38

39

class BlogPost(TimeStampedModel):

40

title = models.CharField(max_length=200)

41

author = models.ForeignKey('auth.User', on_delete=models.CASCADE)

42

43

def save_without_timestamp_update(self, *args, **kwargs):

44

# Save without updating the modified timestamp

45

self.update_modified = False

46

self.save(*args, **kwargs)

47

48

# Usage

49

article = Article.objects.create(title="My Article", content="Content")

50

print(article.created) # DateTime when created

51

print(article.modified) # Same as created initially

52

53

article.content = "Updated content"

54

article.save()

55

print(article.modified) # Updated to current time

56

57

# Get latest article

58

latest = Article.objects.latest() # Uses 'modified' field by default

59

```

60

61

### TitleDescriptionModel

62

63

Abstract base class that provides standard title and description fields.

64

65

```python { .api }

66

class TitleDescriptionModel(models.Model):

67

title: CharField # max_length=255

68

description: TextField # blank=True, null=True

69

70

class Meta:

71

abstract = True

72

```

73

74

Usage examples:

75

76

```python

77

from django.db import models

78

from django_extensions.db.models import TitleDescriptionModel

79

80

class Category(TitleDescriptionModel):

81

# Inherits title and description fields

82

color = models.CharField(max_length=7) # For hex color codes

83

84

class Product(TitleDescriptionModel):

85

price = models.DecimalField(max_digits=10, decimal_places=2)

86

sku = models.CharField(max_length=50, unique=True)

87

88

# Usage

89

category = Category.objects.create(

90

title="Electronics",

91

description="Electronic devices and accessories",

92

color="#3498db"

93

)

94

```

95

96

### TitleSlugDescriptionModel

97

98

Abstract base class that extends TitleDescriptionModel with an auto-generated slug field.

99

100

```python { .api }

101

class TitleSlugDescriptionModel(TitleDescriptionModel):

102

title: CharField # Inherited from TitleDescriptionModel

103

description: TextField # Inherited from TitleDescriptionModel

104

slug: AutoSlugField # Auto-populated from 'title'

105

106

# Custom slugify function can be defined on the model

107

def slugify_function(self, content):

108

"""

109

Optional: Define custom slugification logic.

110

111

Parameters:

112

- content: The content to be slugified

113

114

Returns:

115

- str: The slugified content

116

"""

117

118

class Meta:

119

abstract = True

120

```

121

122

Usage examples:

123

124

```python

125

from django.db import models

126

from django_extensions.db.models import TitleSlugDescriptionModel

127

128

class Page(TitleSlugDescriptionModel):

129

content = models.TextField()

130

is_published = models.BooleanField(default=False)

131

132

class CustomSlugPage(TitleSlugDescriptionModel):

133

content = models.TextField()

134

135

def slugify_function(self, content):

136

# Custom slugification: use underscores instead of hyphens

137

return content.replace(' ', '_').lower()

138

139

# Usage

140

page = Page.objects.create(

141

title="About Us",

142

description="Information about our company",

143

content="We are a great company..."

144

)

145

print(page.slug) # "about-us" (automatically generated)

146

147

# With custom slugify function

148

custom_page = CustomSlugPage.objects.create(

149

title="Contact Info",

150

content="Our contact information"

151

)

152

print(custom_page.slug) # "contact_info" (uses custom function)

153

```

154

155

### ActivatorModel System

156

157

A complete system for managing model activation status with querysets and managers.

158

159

```python { .api }

160

class ActivatorQuerySet(models.QuerySet):

161

def active(self):

162

"""Return queryset filtered to active instances only."""

163

164

def inactive(self):

165

"""Return queryset filtered to inactive instances only."""

166

167

class ActivatorModelManager(models.Manager):

168

def get_queryset(self):

169

"""Use ActivatorQuerySet for all queries."""

170

171

def active(self):

172

"""Return active instances: Model.objects.active()"""

173

174

def inactive(self):

175

"""Return inactive instances: Model.objects.inactive()"""

176

177

class ActivatorModel(models.Model):

178

INACTIVE_STATUS: int = 0

179

ACTIVE_STATUS: int = 1

180

STATUS_CHOICES: tuple = (

181

(INACTIVE_STATUS, 'Inactive'),

182

(ACTIVE_STATUS, 'Active')

183

)

184

185

status: IntegerField # choices=STATUS_CHOICES, default=ACTIVE_STATUS

186

activate_date: DateTimeField # blank=True, null=True

187

deactivate_date: DateTimeField # blank=True, null=True

188

objects: ActivatorModelManager

189

190

def save(self, *args, **kwargs):

191

"""Automatically set activate_date if not provided."""

192

193

class Meta:

194

ordering = ('status', '-activate_date')

195

abstract = True

196

```

197

198

Usage examples:

199

200

```python

201

from django.db import models

202

from django_extensions.db.models import ActivatorModel

203

from django.utils import timezone

204

205

class Campaign(ActivatorModel):

206

name = models.CharField(max_length=200)

207

budget = models.DecimalField(max_digits=10, decimal_places=2)

208

209

class Promotion(ActivatorModel):

210

title = models.CharField(max_length=200)

211

discount_percent = models.IntegerField()

212

213

# Usage - Creating instances

214

campaign = Campaign.objects.create(

215

name="Summer Sale",

216

budget=5000.00,

217

# status defaults to ACTIVE_STATUS

218

# activate_date is automatically set to now()

219

)

220

221

# Deactivating a campaign

222

campaign.status = Campaign.INACTIVE_STATUS

223

campaign.deactivate_date = timezone.now()

224

campaign.save()

225

226

# Querying active/inactive instances

227

active_campaigns = Campaign.objects.active()

228

inactive_campaigns = Campaign.objects.inactive()

229

230

# Using in templates or serializers

231

for campaign in Campaign.objects.active():

232

print(f"Active: {campaign.name}")

233

234

# Scheduled activation

235

future_campaign = Campaign.objects.create(

236

name="Holiday Sale",

237

budget=10000.00,

238

activate_date=timezone.now() + timezone.timedelta(days=30)

239

)

240

```

241

242

## Combining Base Classes

243

244

Base classes can be combined to create models with multiple features:

245

246

```python

247

from django.db import models

248

from django_extensions.db.models import TimeStampedModel, ActivatorModel

249

250

# Multiple inheritance

251

class ManagedContent(TimeStampedModel, ActivatorModel):

252

title = models.CharField(max_length=200)

253

content = models.TextField()

254

255

class Meta:

256

# Inherit ordering from ActivatorModel, add created

257

ordering = ('status', '-activate_date', '-created')

258

259

# Custom combination with TitleSlugDescriptionModel

260

class PublishableArticle(TitleSlugDescriptionModel, TimeStampedModel, ActivatorModel):

261

author = models.ForeignKey('auth.User', on_delete=models.CASCADE)

262

featured_image = models.ImageField(upload_to='articles/', blank=True)

263

264

def is_published(self):

265

return self.status == self.ACTIVE_STATUS

266

267

@classmethod

268

def published(cls):

269

return cls.objects.active()

270

271

# Usage

272

article = PublishableArticle.objects.create(

273

title="Django Best Practices",

274

description="A guide to Django development",

275

author=request.user

276

)

277

# Has: title, slug, description, created, modified, status, activate_date, deactivate_date

278

279

published_articles = PublishableArticle.published()

280

```

281

282

## Model Patterns and Best Practices

283

284

```python

285

# Pattern 1: Timestamped content with soft delete

286

class SoftDeleteTimeStampedModel(TimeStampedModel):

287

is_deleted = models.BooleanField(default=False)

288

deleted_at = models.DateTimeField(null=True, blank=True)

289

290

def delete(self, using=None, keep_parents=False):

291

# Soft delete instead of actual deletion

292

self.is_deleted = True

293

self.deleted_at = timezone.now()

294

self.save()

295

296

class Meta:

297

abstract = True

298

299

# Pattern 2: Hierarchical categories with timestamps

300

class Category(TitleSlugDescriptionModel, TimeStampedModel):

301

parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE)

302

order = models.PositiveIntegerField(default=0)

303

304

class Meta:

305

ordering = ['order', 'title']

306

verbose_name_plural = 'categories'

307

308

# Pattern 3: User-owned content with activation

309

class UserContent(TitleDescriptionModel, ActivatorModel, TimeStampedModel):

310

owner = models.ForeignKey('auth.User', on_delete=models.CASCADE)

311

is_public = models.BooleanField(default=False)

312

313

def can_view(self, user):

314

if self.status != self.ACTIVE_STATUS:

315

return False

316

return self.is_public or self.owner == user or user.is_staff

317

318

class Meta:

319

abstract = True

320

```

321

322

## Manager and QuerySet Customization

323

324

```python

325

# Extending ActivatorModel with custom methods

326

class PublishedQuerySet(ActivatorQuerySet):

327

def published(self):

328

return self.active().filter(publish_date__lte=timezone.now())

329

330

def featured(self):

331

return self.published().filter(is_featured=True)

332

333

class PublishedManager(ActivatorModelManager):

334

def get_queryset(self):

335

return PublishedQuerySet(self.model, using=self._db)

336

337

def published(self):

338

return self.get_queryset().published()

339

340

def featured(self):

341

return self.get_queryset().featured()

342

343

class Article(TitleSlugDescriptionModel, ActivatorModel, TimeStampedModel):

344

content = models.TextField()

345

publish_date = models.DateTimeField(default=timezone.now)

346

is_featured = models.BooleanField(default=False)

347

348

objects = PublishedManager()

349

350

class Meta:

351

ordering = ['-publish_date']

352

353

# Usage

354

Article.objects.published() # Active articles with publish_date <= now

355

Article.objects.featured() # Published + featured articles

356

```