1+ from algoliasearch_django import AlgoliaIndex
2+ from algoliasearch_django .decorators import register
3+ from .article import Article
4+ from .author import Author
5+ from .category import Category
6+ from bs4 import BeautifulSoup
7+
8+ def truncate_text (text , max_chars = 8000 ):
9+ """Truncate text to stay within Algolia's size limits"""
10+ if not text :
11+ return ""
12+ if len (text ) <= max_chars :
13+ return text
14+ return text [:max_chars ] + "..."
15+
16+ @register (Article )
17+ class ArticleIndex (AlgoliaIndex ):
18+ index_queryset = Article .objects .filter (status = 'ready' )
19+
20+ fields = [
21+ 'title' ,
22+ 'slug' ,
23+ 'status' ,
24+ 'views' ,
25+ 'is_sponsored' ,
26+ ]
27+
28+ settings = {
29+ 'searchableAttributes' : [
30+ 'title' ,
31+ 'content_excerpt' ,
32+ 'summary' ,
33+ ],
34+ 'attributesToSnippet' : [
35+ 'content_excerpt:50' ,
36+ 'summary:30' ,
37+ ],
38+ 'snippetEllipsisText' : '...' ,
39+ 'attributesForFaceting' : [
40+ 'status' ,
41+ 'is_sponsored' ,
42+ 'categories' ,
43+ 'authors' ,
44+ ]
45+ }
46+
47+ def get_raw_record (self , instance ):
48+ record = super ().get_raw_record (instance )
49+
50+ # Convert UUID to string
51+ record ['objectID' ] = str (instance .id )
52+
53+ # Clean and truncate HTML content
54+ if instance .content :
55+ soup = BeautifulSoup (instance .content , 'html.parser' )
56+ clean_content = soup .get_text (separator = ' ' , strip = True )
57+ record ['content_excerpt' ] = truncate_text (clean_content , 8000 )
58+
59+ if instance .summary :
60+ record ['summary' ] = truncate_text (instance .summary , 1000 )
61+
62+ # Add thumbnail URL
63+ if instance .thumb :
64+ record ['thumb_url' ] = instance .thumb .url
65+
66+ # Handle datetime fields
67+ if instance .scheduled_publish_time :
68+ record ['scheduled_publish_time' ] = instance .scheduled_publish_time .isoformat ()
69+
70+ if instance .created_at :
71+ record ['created_at' ] = instance .created_at .isoformat ()
72+
73+ if instance .updated_at :
74+ record ['updated_at' ] = instance .updated_at .isoformat ()
75+
76+ # Handle relationships
77+ if instance .categories .exists ():
78+ record ['categories' ] = [
79+ {
80+ 'name' : category .name ,
81+ 'slug' : category .slug ,
82+ 'id' : str (category .id )
83+ }
84+ for category in instance .categories .all ()
85+ ]
86+
87+ if instance .authors .exists ():
88+ record ['authors' ] = [
89+ {
90+ 'name' : author .full_name or author .user .get_full_name (),
91+ 'username' : author .user .username ,
92+ 'id' : str (author .id )
93+ }
94+ for author in instance .authors .all ()
95+ ]
96+
97+ return record
98+
99+ @register (Category )
100+ class CategoryIndex (AlgoliaIndex ):
101+ fields = [
102+ 'name' ,
103+ 'slug' ,
104+ 'is_primary' ,
105+ ]
106+
107+ def get_raw_record (self , instance ):
108+ record = super ().get_raw_record (instance )
109+ record ['objectID' ] = str (instance .id )
110+
111+ if instance .created_at :
112+ record ['created_at' ] = instance .created_at .isoformat ()
113+
114+ if instance .updated_at :
115+ record ['updated_at' ] = instance .updated_at .isoformat ()
116+
117+ return record
118+
119+ settings = {
120+ 'searchableAttributes' : ['name' ],
121+ 'attributesForFaceting' : ['is_primary' ]
122+ }
123+
124+ @register (Author )
125+ class AuthorIndex (AlgoliaIndex ):
126+ fields = [
127+ 'full_name' ,
128+ 'bio' ,
129+ 'twitter_username' ,
130+ ]
131+
132+ def get_raw_record (self , instance ):
133+ record = super ().get_raw_record (instance )
134+ record ['objectID' ] = str (instance .id )
135+
136+ if instance .bio :
137+ record ['bio' ] = truncate_text (instance .bio , 1000 )
138+
139+ if instance .created_at :
140+ record ['created_at' ] = instance .created_at .isoformat ()
141+
142+ if instance .updated_at :
143+ record ['updated_at' ] = instance .updated_at .isoformat ()
144+
145+ return record
146+
147+ settings = {
148+ 'searchableAttributes' : [
149+ 'full_name' ,
150+ 'bio'
151+ ]
152+ }
0 commit comments