or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

admin-forms.mdcms-integration.mdconfiguration.mdfeeds-sitemaps.mdindex.mdmodels.mdtemplates-utilities.mdviews.md

models.mddocs/

0

# Models and Data Management

1

2

Core data models for blog functionality including posts, categories, and CMS plugins with full multilingual support and SEO integration.

3

4

## Imports

5

6

```python

7

from typing import Optional, List, Dict, Any

8

from datetime import datetime

9

from django.db import models

10

from django.db.models import QuerySet

11

from django.contrib.auth.models import AbstractUser

12

from django.http import HttpRequest

13

from django.utils.functional import cached_property

14

from cms.models import CMSPlugin, PlaceholderField

15

from parler.models import TranslatableModel

16

from meta.models import ModelMeta

17

from aldryn_apphooks_config.fields import AppHookConfigField

18

from aldryn_apphooks_config.managers.parler import AppHookConfigTranslatableManager

19

from djangocms_blog.models import Post, BlogCategory

20

from djangocms_blog.cms_appconfig import BlogConfig

21

from djangocms_blog.managers import GenericDateTaggedManager

22

from djangocms_blog.settings import get_setting

23

```

24

25

## Capabilities

26

27

### Blog Post Model

28

29

The main Post model provides comprehensive blog post functionality with multilingual content, placeholder fields, meta tag support, and extensive relationship management.

30

31

```python { .api }

32

class Post(KnockerModel, BlogMetaMixin, TranslatableModel):

33

"""

34

Main blog post model with multilingual and meta support.

35

36

Translated fields (via django-parler):

37

- title: CharField(max_length=752)

38

- slug: SlugField(max_length=752, blank=True, default='')

39

- abstract: HTMLField(blank=True, default='')

40

- meta_description: TextField(blank=True, default='')

41

- meta_keywords: TextField(blank=True, default='')

42

- meta_title: CharField(max_length=2000, blank=True, default='')

43

- post_text: HTMLField(blank=True, default='')

44

- subtitle: CharField(max_length=767, blank=True, default='')

45

46

Non-translated fields:

47

- author: ForeignKey(User, on_delete=PROTECT, null=True, blank=True)

48

- date_created: DateTimeField(auto_now_add=True)

49

- date_modified: DateTimeField(auto_now=True)

50

- date_published: DateTimeField(null=True, blank=True)

51

- date_published_end: DateTimeField(null=True, blank=True)

52

- date_featured: DateTimeField(null=True, blank=True)

53

- publish: BooleanField(default=False)

54

- featured: BooleanField(default=False)

55

- include_in_rss: BooleanField(default=True)

56

- enable_comments: BooleanField(default=get_setting('ENABLE_COMMENTS'))

57

- enable_liveblog: BooleanField(default=False)

58

- sites: ManyToManyField(Site, blank=True)

59

- app_config: AppHookConfigField(BlogConfig, null=True)

60

- categories: ManyToManyField(BlogCategory, blank=True)

61

- tags: TaggableManager(blank=True)

62

- related: SortedManyToManyField('self', blank=True, symmetrical=False)

63

- main_image: FilerImageField(null=True, blank=True, on_delete=SET_NULL)

64

- main_image_thumbnail: ForeignKey(ThumbnailOption, null=True, blank=True, on_delete=SET_NULL)

65

- main_image_full: ForeignKey(ThumbnailOption, null=True, blank=True, on_delete=SET_NULL)

66

- content: PlaceholderField('post_content', related_name='post_content')

67

- media: PlaceholderField('media', related_name='media')

68

- liveblog: PlaceholderField('live_blog', related_name='live_blog')

69

"""

70

71

# Key methods

72

def get_absolute_url(self, lang: Optional[str] = None) -> str:

73

"""Return the absolute URL for the post."""

74

75

def get_full_url(self) -> str:

76

"""Return the full URL including domain."""

77

78

def get_image_full_url(self) -> str:

79

"""Return full URL of the main image."""

80

81

def get_image_width(self) -> Optional[int]:

82

"""Return main image width in pixels."""

83

84

def get_image_height(self) -> Optional[int]:

85

"""Return main image height in pixels."""

86

87

def get_title(self) -> str:

88

"""Return post title with meta fallback."""

89

90

def get_description(self) -> str:

91

"""Return meta description with abstract fallback."""

92

93

def get_keywords(self) -> List[str]:

94

"""Return meta keywords as list."""

95

96

def get_tags(self) -> str:

97

"""Return tags as comma-separated string."""

98

99

def get_author(self) -> Optional[AbstractUser]:

100

"""Return author user object."""

101

102

def thumbnail_options(self) -> Dict[str, Any]:

103

"""Return thumbnail configuration options."""

104

105

def full_image_options(self) -> Dict[str, Any]:

106

"""Return full image configuration options."""

107

108

def get_admin_url(self) -> str:

109

"""Return admin edit URL for the post."""

110

111

def should_knock(self, signal_type: str, created: bool = False) -> bool:

112

"""Return whether to send notification for this post."""

113

114

def get_cache_key(self, language: str, prefix: str) -> str:

115

"""Generate cache key for post in given language."""

116

117

@property

118

def is_published(self) -> bool:

119

"""Check if post is published."""

120

121

@property

122

def guid(self) -> str:

123

"""Return unique post identifier hash."""

124

125

@property

126

def date(self) -> datetime:

127

"""Return featured date or published date."""

128

129

@property

130

def liveblog_group(self) -> str:

131

"""Return liveblog group identifier."""

132

133

# Manager (accessed via Post.objects)

134

objects: GenericDateTaggedManager

135

136

# Manager methods:

137

# Post.objects.published(current_site=True) - Return QuerySet of published posts

138

# Post.objects.published_on_rss(current_site=True) - Return RSS-enabled posts

139

# Post.objects.published_future(current_site=True) - Return published including future

140

# Post.objects.archived(current_site=True) - Return QuerySet of archived posts

141

# Post.objects.available(current_site=True) - Return QuerySet of available posts for current site

142

# Post.objects.filter_by_language(language, current_site=True) - Language filtering

143

# Post.objects.on_site(site=None) - Site filtering

144

# Post.objects.get_months(queryset=None, current_site=True) - Archive months with counts

145

# Post.objects.tagged(other_model=None, queryset=None) - Get tagged items

146

# Post.objects.tag_list(other_model=None, queryset=None) - Get common tags

147

# Post.objects.tag_cloud(other_model=None, queryset=None, published=True, on_site=False) - Generate tag cloud

148

```

149

150

### Blog Category Model

151

152

Multilingual category model for organizing blog posts with SEO support and hierarchical relationships.

153

154

```python { .api }

155

class BlogCategory(BlogMetaMixin, TranslatableModel):

156

"""

157

Blog category model with multilingual support.

158

159

Translated fields:

160

- name: CharField(max_length=752)

161

- slug: SlugField(max_length=752, blank=True, db_index=True)

162

- meta_description: TextField(blank=True, default='')

163

164

Non-translated fields:

165

- parent: ForeignKey('self', null=True, blank=True, on_delete=CASCADE, related_name='children')

166

- date_created: DateTimeField(auto_now_add=True)

167

- date_modified: DateTimeField(auto_now=True)

168

- app_config: AppHookConfigField(BlogConfig, null=True)

169

"""

170

171

def get_absolute_url(self, lang: Optional[str] = None) -> str:

172

"""Return the absolute URL for the category."""

173

174

def get_full_url(self) -> str:

175

"""Return the full URL including domain."""

176

177

def descendants(self) -> List['BlogCategory']:

178

"""Return all descendant categories recursively."""

179

180

def get_title(self) -> str:

181

"""Return category title."""

182

183

def get_description(self) -> str:

184

"""Return category meta description."""

185

186

@cached_property

187

def linked_posts(self) -> QuerySet:

188

"""Return posts in this category for current namespace."""

189

190

@cached_property

191

def count(self) -> int:

192

"""Return count of posts in this category."""

193

194

@cached_property

195

def count_all_sites(self) -> int:

196

"""Return count of posts across all sites."""

197

198

# Manager (accessed via BlogCategory.objects)

199

objects: AppHookConfigTranslatableManager

200

```

201

202

### CMS Plugin Models

203

204

Models for CMS plugins that embed blog content in CMS pages.

205

206

```python { .api }

207

class BasePostPlugin(CMSPlugin):

208

"""Base model for blog-related CMS plugins."""

209

app_config: AppHookConfigField(BlogConfig, null=True, blank=True)

210

current_site: BooleanField(default=True)

211

212

def optimize(self, qs: QuerySet) -> QuerySet:

213

"""Apply select_related/prefetch_related optimizations to queryset."""

214

215

def post_queryset(self, request: Optional[HttpRequest] = None, published_only: bool = True, selected_posts: Optional[List[int]] = None) -> QuerySet:

216

"""Get filtered post queryset based on plugin configuration."""

217

218

class LatestPostsPlugin(BasePostPlugin):

219

"""Plugin model for latest posts display."""

220

latest_posts: IntegerField(default=get_setting('LATEST_POSTS'))

221

tags: SortedManyToManyField(Tag, blank=True)

222

categories: SortedManyToManyField(BlogCategory, blank=True)

223

224

def get_posts(self, request: HttpRequest, published_only: bool = True) -> QuerySet:

225

"""Get posts for latest entries plugin."""

226

227

class AuthorEntriesPlugin(BasePostPlugin):

228

"""Plugin model for author posts display."""

229

authors: SortedManyToManyField(User, verbose_name=_('Authors'), blank=True)

230

latest_posts: IntegerField(default=get_setting('LATEST_POSTS'))

231

232

def get_posts(self, request: HttpRequest, published_only: bool = True) -> QuerySet:

233

"""Get posts for author entries plugin."""

234

235

def get_authors(self, request: HttpRequest) -> QuerySet:

236

"""Get authors with post counts."""

237

238

class FeaturedPostsPlugin(BasePostPlugin):

239

"""Plugin model for featured posts display."""

240

featured_posts: IntegerField(default=get_setting('LATEST_POSTS'))

241

242

def get_posts(self, request: HttpRequest, published_only: bool = True) -> QuerySet:

243

"""Get posts for featured posts plugin."""

244

245

class GenericBlogPlugin(BasePostPlugin):

246

"""Generic blog plugin model base."""

247

cache: BooleanField(default=True)

248

```

249

250

### Meta Mixin

251

252

Base mixin providing SEO meta tag functionality via django-meta integration.

253

254

```python { .api }

255

class BlogMetaMixin(ModelMeta):

256

"""

257

Meta mixin for SEO meta tags using django-meta.

258

259

Provides meta tag functionality for models including:

260

- OpenGraph tags

261

- Twitter Card tags

262

- Google+ tags

263

- Schema.org structured data

264

"""

265

266

def get_meta_title(self) -> str:

267

"""Return meta title for SEO."""

268

269

def get_meta_description(self) -> str:

270

"""Return meta description for SEO."""

271

272

def get_meta_keywords(self) -> str:

273

"""Return meta keywords for SEO."""

274

275

def get_meta_url(self) -> str:

276

"""Return canonical URL for meta tags."""

277

278

def get_meta_image(self) -> str:

279

"""Return meta image URL for social sharing."""

280

```

281

282

## Model Usage Examples

283

284

```python

285

# Creating and managing blog posts

286

from djangocms_blog.models import Post, BlogCategory

287

from django.contrib.auth import get_user_model

288

from django.utils import timezone

289

290

User = get_user_model()

291

292

# Create a category

293

category = BlogCategory.objects.create()

294

category.set_current_language('en')

295

category.name = 'Technology'

296

category.slug = 'technology'

297

category.meta_description = 'Technology related posts'

298

category.save()

299

300

# Create a blog post

301

post = Post.objects.create(

302

author=User.objects.first(),

303

app_config=BlogConfig.objects.first(),

304

date_published=timezone.now(),

305

enable_comments=True,

306

featured=True

307

)

308

309

# Set translated content

310

post.set_current_language('en')

311

post.title = 'Introduction to Django CMS'

312

post.slug = 'introduction-django-cms'

313

post.abstract = '<p>Learn the basics of Django CMS</p>'

314

post.post_text = '<p>Django CMS is a powerful content management system...</p>'

315

post.meta_description = 'Learn Django CMS basics in this comprehensive guide'

316

post.meta_title = 'Django CMS Tutorial - Complete Guide'

317

post.save()

318

319

# Add to category and tags

320

post.categories.add(category)

321

post.tags.add('django', 'cms', 'tutorial')

322

323

# Query posts

324

published_posts = Post.objects.published()

325

featured_posts = Post.objects.published().filter(featured=True)

326

category_posts = Post.objects.published().filter(categories=category)

327

author_posts = Post.objects.published().filter(author=some_user)

328

329

# Access post URLs and metadata

330

url = post.get_absolute_url()

331

full_url = post.get_full_url()

332

meta_title = post.get_meta_title()

333

is_published = post.is_published

334

```