33from django .utils .html import format_html
44from django .utils .text import slugify
55
6+
67class Author (models .Model ):
78 """
89 Represents an author of a post.
910 If you use Django’s built-in User, you can instead
1011 point to settings.AUTH_USER_MODEL via ForeignKey.
1112 """
13+
1214 name = models .CharField (max_length = 100 )
1315 email = models .EmailField (unique = True )
1416 bio = models .TextField (blank = True )
1517 avatar = models .ImageField (
16- upload_to = ' authors/avatars/' ,
18+ upload_to = " authors/avatars/" ,
1719 null = True ,
1820 blank = True ,
19- help_text = "Optional profile picture for the author"
21+ help_text = "Optional profile picture for the author" ,
2022 )
2123
2224 @admin .display
2325 def image_tag (self ):
24- return format_html ('<img src="{}" alt="author img" height="100" />' ,
25- self .image .url )
26+ return format_html ('<img src="{}" alt="author img" height="100" />' , self .image .url )
2627
27- image_tag .short_description = ' Image'
28+ image_tag .short_description = " Image"
2829 image_tag .allow_tags = True
2930
3031 def __str__ (self ):
@@ -36,6 +37,7 @@ class Category(models.Model):
3637 A simple Category model. If you prefer to keep category
3738 as a CharField, you can skip this and use a choices tuple instead.
3839 """
40+
3941 title = models .CharField (max_length = 50 , unique = True )
4042 slug = models .SlugField (max_length = 60 , unique = True )
4143
@@ -56,6 +58,7 @@ class Tag(models.Model):
5658 """
5759 Tags for posts. Many-to-many relationship from Post to Tag.
5860 """
61+
5962 name = models .CharField (max_length = 30 , unique = True )
6063 slug = models .SlugField (max_length = 40 , unique = True )
6164
@@ -85,49 +88,35 @@ class Post(models.Model):
8588 tags: string[];
8689 content: string;
8790 """
91+
8892 slug = models .SlugField (
8993 max_length = 150 ,
9094 unique = True ,
91- help_text = "A URL-friendly identifier derived from title."
95+ help_text = "A URL-friendly identifier derived from title." ,
9296 )
9397 title = models .CharField (max_length = 200 )
94- excerpt = models .TextField (
95- help_text = "Short summary of the post (e.g. first 1–2 sentences)."
96- )
98+ excerpt = models .TextField (help_text = "Short summary of the post (e.g. first 1–2 sentences)." )
9799 image = models .ImageField (
98- upload_to = 'posts/images/' ,
99- null = True , blank = True ,)
100+ upload_to = "posts/images/" ,
101+ null = True ,
102+ blank = True ,
103+ )
100104 category = models .ForeignKey (
101105 Category ,
102106 on_delete = models .PROTECT ,
103107 related_name = "posts" ,
104- help_text = "Select a category for this post."
108+ help_text = "Select a category for this post." ,
105109 )
106110 published_at = models .DateTimeField (
107111 db_index = True ,
108112 help_text = "When the post was (or will be) published." ,
109113 null = True ,
110- blank = True
111- )
112- author = models .ForeignKey (
113- Author ,
114- on_delete = models .CASCADE ,
115- related_name = "posts"
116- )
117- featured = models .BooleanField (
118- default = False ,
119- help_text = "Mark as featured post (e.g. for homepage slider)."
120- )
121- read_time = models .CharField (
122- max_length = 20 ,
123114 blank = True ,
124- help_text = "Estimated read time, e.g. '5 min read'."
125- )
126- tags = models .ManyToManyField (
127- Tag ,
128- related_name = "posts" ,
129- blank = True
130115 )
116+ author = models .ForeignKey (Author , on_delete = models .CASCADE , related_name = "posts" )
117+ featured = models .BooleanField (default = False , help_text = "Mark as featured post (e.g. for homepage slider)." )
118+ read_time = models .CharField (max_length = 20 , blank = True , help_text = "Estimated read time, e.g. '5 min read'." )
119+ tags = models .ManyToManyField (Tag , related_name = "posts" , blank = True )
131120 content = models .TextField (help_text = "Full HTML or Markdown content of the post." )
132121
133122 class Meta :
@@ -142,10 +131,9 @@ def __str__(self):
142131
143132 @admin .display
144133 def image_tag (self ):
145- return format_html ('<img src="{}" height="100" />' ,
146- self .image .url )
134+ return format_html ('<img src="{}" height="100" />' , self .image .url )
147135
148- image_tag .short_description = ' Image'
136+ image_tag .short_description = " Image"
149137 image_tag .allow_tags = True
150138
151139 @property
@@ -165,20 +153,14 @@ class Comment(models.Model):
165153 Represents a comment on a Post. Adjust fields as needed
166154 (e.g. if you want to link comments to registered users).
167155 """
168- post = models .ForeignKey (
169- Post ,
170- on_delete = models .CASCADE ,
171- related_name = "comments"
172- )
156+
157+ post = models .ForeignKey (Post , on_delete = models .CASCADE , related_name = "comments" )
173158 name = models .CharField (max_length = 80 , help_text = "Display name of the commenter" )
174159 email = models .EmailField (help_text = "Email of the commenter" )
175160 content = models .TextField (help_text = "Comment text" )
176161 created_at = models .DateTimeField (auto_now_add = True )
177162
178- is_public = models .BooleanField (
179- default = True ,
180- help_text = "Uncheck to hide comment without deleting."
181- )
163+ is_public = models .BooleanField (default = True , help_text = "Uncheck to hide comment without deleting." )
182164
183165 class Meta :
184166 ordering = ["created_at" ]
0 commit comments