{{ post.title }}
- + +{{ post.description }}
+{{ post.content|markdown|safe }}
diff --git a/apps/blog/choices.py b/apps/blog/choices.py new file mode 100644 index 0000000..d008ee8 --- /dev/null +++ b/apps/blog/choices.py @@ -0,0 +1,6 @@ +from django.db.models import TextChoices + + +class StatusChoice(TextChoices): + DRAFT = 'df', 'Draft' + PUBLISHED = 'pb', 'Published' diff --git a/apps/blog/forms.py b/apps/blog/forms.py index 338c1fd..0a472e4 100644 --- a/apps/blog/forms.py +++ b/apps/blog/forms.py @@ -11,56 +11,40 @@ } -class PostCreateForm(forms.ModelForm): +class PostCreateUpdateForm(forms.ModelForm): class Meta: model = Post - fields = ("title", "content", "is_active") + fields = ("title", "description", "content", "status") widgets = { "title": forms.TextInput( attrs={ "class": "form-control", + "name": "title", "placeholder": "Enter you`r post title...", } ), - "content": forms.Textarea( + "description": forms.Textarea( attrs={ "class": "form-control", - "placeholder": "Enter you`r post content...", + "name": "description", + "placeholder": "Enter you`r post description...", } ), - "is_active": forms.CheckboxInput( - attrs={"name": "is_active", "class": "form-check-input"} - ), - } - - -class PostUpdateForm(forms.ModelForm): - - class Meta: - model = Post - fields = ("title", "content", "is_active") - - widgets = { - "title": forms.TextInput( - attrs={ - "name": "title", - "class": "form-control", - "placeholder": "Title....", - }, - ), "content": forms.Textarea( attrs={ - "name": "content", - "cols": "40", - "rows": "10", "class": "form-control", - "placeholder": "Content....", - }, + "name": "content", + "placeholder": "Enter you`r post content...", + } ), - "is_active": forms.CheckboxInput( - attrs={"name": "is_active", "class": "form-check-input"} + "status": forms.Select( + attrs={ + "class": "form-select", + "name": "status", + "placeholder": "Enter you`r post status...", + } ), } diff --git a/apps/blog/managers.py b/apps/blog/managers.py new file mode 100644 index 0000000..eb1878c --- /dev/null +++ b/apps/blog/managers.py @@ -0,0 +1,9 @@ +from django.db import models +from .choices import StatusChoice + + +class PublishedManager(models.Manager): + def get_queryset(self) -> models.QuerySet: + return ( + super().get_queryset().filter(status=StatusChoice.PUBLISHED, is_active=True) + ) diff --git a/apps/blog/migrations/0002_post_description_post_status.py b/apps/blog/migrations/0002_post_description_post_status.py new file mode 100644 index 0000000..e607ee2 --- /dev/null +++ b/apps/blog/migrations/0002_post_description_post_status.py @@ -0,0 +1,24 @@ +# Generated by Django 5.1.1 on 2024-11-13 09:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('blog', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='post', + name='description', + field=models.CharField(default=1, max_length=300, verbose_name='description'), + preserve_default=False, + ), + migrations.AddField( + model_name='post', + name='status', + field=models.CharField(choices=[('df', 'Draft'), ('pb', 'Published')], default='df', max_length=2, verbose_name='status'), + ), + ] diff --git a/apps/blog/migrations/0003_alter_post_description.py b/apps/blog/migrations/0003_alter_post_description.py new file mode 100644 index 0000000..c1f99a5 --- /dev/null +++ b/apps/blog/migrations/0003_alter_post_description.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.1 on 2024-11-13 10:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('blog', '0002_post_description_post_status'), + ] + + operations = [ + migrations.AlterField( + model_name='post', + name='description', + field=models.CharField(blank=True, max_length=300, null=True, verbose_name='description'), + ), + ] diff --git a/apps/blog/migrations/0004_alter_post_is_active.py b/apps/blog/migrations/0004_alter_post_is_active.py new file mode 100644 index 0000000..2358e66 --- /dev/null +++ b/apps/blog/migrations/0004_alter_post_is_active.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.1 on 2024-11-13 10:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('blog', '0003_alter_post_description'), + ] + + operations = [ + migrations.AlterField( + model_name='post', + name='is_active', + field=models.BooleanField(default=True, verbose_name='active'), + ), + ] diff --git a/apps/blog/models.py b/apps/blog/models.py index fe9569a..75c7a0c 100644 --- a/apps/blog/models.py +++ b/apps/blog/models.py @@ -4,17 +4,30 @@ from django.utils.text import slugify from apps.shared.models import TimestempedAbstractModel from apps.shared.utils import get_random_text +from .managers import PublishedManager +from .choices import StatusChoice class Post(TimestempedAbstractModel): + title = models.CharField(_("title"), max_length=120, db_index=True) slug = models.SlugField(_("slug"), max_length=255, unique=True, db_index=True) + status = models.CharField( + _("status"), + max_length=2, + choices=StatusChoice.choices, + default=StatusChoice.DRAFT.value + ) + description = models.CharField(_("description"), max_length=300, blank=True, null=True) content = models.TextField(_("content")) publisher_at = models.DateField(_("publisher at")) - is_active = models.BooleanField(_("active"), default=False) + is_active = models.BooleanField(_("active"), default=True) author = models.ForeignKey("users.User", models.CASCADE, "posts", db_index=True) watching = models.BigIntegerField(_("watching"), default=0) + objects = models.Manager() + published = PublishedManager() + def delete(self, *args, **kwargs): print(self.post_comments.all().delete()) return super().delete(*args, **kwargs) diff --git a/apps/blog/views.py b/apps/blog/views.py index 31af7fd..d0e3f74 100644 --- a/apps/blog/views.py +++ b/apps/blog/views.py @@ -9,8 +9,7 @@ from apps.users.models import User from .forms import ( - PostUpdateForm, - PostCreateForm, + PostCreateUpdateForm, SettingsUserForm, SettingsUserProfileForm, ) @@ -42,9 +41,9 @@ class HomePageView(TemplateView): def get(self, request): if request.user is not None and request.user.is_authenticated: - posts = Post.objects.exclude(author=request.user) + posts = Post.published.exclude(author=request.user) else: - posts = Post.objects.all() + posts = Post.published.all() search_query = request.GET.get("search_query", None) page = request.GET.get("page", 1) @@ -74,6 +73,7 @@ class PostDetailPageView(View): def get(self, request, slug): post = get_object_or_404(Post, slug=slug) + post_comments = post.post_comments.all().order_by("-created_at") post.watching += 1 post.save() @@ -88,17 +88,18 @@ class PostCreatePageView(LoginRequiredMixin, TemplateView): template_name = "blog/post_create.html" def get(self, request): - return render(request, "blog/post_create.html", {"form": PostCreateForm()}) + return render(request, "blog/post_create.html", {"form": PostCreateUpdateForm()}) def post(self, request): - form = PostCreateForm(request.POST) + form = PostCreateUpdateForm(request.POST) if form.is_valid(): cd = form.cleaned_data post = Post.objects.create( title=cd.get("title"), + status=cd.get("status"), + description=cd.get("description"), content=cd.get("content"), - is_active=cd.get("is_active"), author=request.user, publisher_at=datetime.datetime.now().strftime("%Y-%m-%d"), ) @@ -122,7 +123,7 @@ def get(self, request): search_query_for_user_posts = request.GET.get( "search_query_for_user_posts", None ) - posts = Post.objects.filter(author=request.user) + posts = Post.objects.filter(author=request.user, is_active=True) if search_query_for_user_posts is not None: posts = get_search_model_queryset(posts, search_query_for_user_posts) @@ -134,13 +135,14 @@ class PostUpdateView(LoginRequiredMixin, View): template_name = "blog/post_update.html" def get(self, request, slug): - post = get_object_or_404(Post, slug=slug) - form = PostUpdateForm(instance=post) + post = get_object_or_404(Post, slug=slug, is_active=True) + + form = PostCreateUpdateForm(instance=post) return render(request, "blog/post_update.html", {"form": form, "post": post}) def post(self, request, slug): post = get_object_or_404(Post, slug=slug) - form = PostUpdateForm(request.POST, instance=post) + form = PostCreateUpdateForm(request.POST, instance=post) if form.is_valid(): form.save() messages.success(request, "Post succsessfully updated") @@ -156,8 +158,8 @@ class PostDeletePageView(LoginRequiredMixin, DeleteView): def post(self, request, slug): post = get_object_or_404(Post, slug=slug) - messages.success(request, "post successfully deleted") post.delete() + messages.success(request, "post successfully deleted") return redirect("blog:user_posts") @@ -214,7 +216,6 @@ def post_message(request, slug): return redirect(reverse("users:login")) post_message_input = request.GET.get("post_message_input", None) - print(post_message_input) if post_message_input is not None: set_post_comment(request.user, slug, post_message_input) diff --git a/apps/users/views.py b/apps/users/views.py index 8e1008f..920f822 100644 --- a/apps/users/views.py +++ b/apps/users/views.py @@ -84,7 +84,7 @@ class UserProfilePageView(View): def get(self, request, username): user = get_object_or_404(User, username=username) - posts = Post.objects.filter(author=user, is_active=True).all().order_by("id") + posts = Post.published.filter(author=user).all().order_by("-created_at") search_query = request.GET.get("search_query_for_user_profile", None) diff --git a/templates/blog/home.html b/templates/blog/home.html index 38a1f0c..c69b228 100644 --- a/templates/blog/home.html +++ b/templates/blog/home.html @@ -31,8 +31,13 @@
{{ post.content|truncatewords_html:30 }}
+{{ post.description|truncatewords_html:30 }}
Continue reading +{{ post.description }}
+{{ post.content|markdown|safe }}
{{ post.description|truncatewords_html:30 }}
+ Continue reading{{ post.content|truncatewords_html:30 }}
- Continue reading{{ post.content|truncatewords_html:30 }}
+{{ post.description|truncatewords_html:30 }}
Continue reading