article

Tuesday, May 19, 2020

Django Creating Comments System to Blog Application


Django Creating Comments System to Blog Application

Django Build a blog application with bootstrap and Automatically Generate slugs

Comment Model

Open The models.py file of blog application and below the Post model create the Comment model.
 
#models.py
from django.db import models
 
from django.contrib.auth.models import User
from django.utils.text import slugify

STATUS = (
    (0,"Draft"),
    (1,"Publish")
)

class Post(models.Model):
    title = models.CharField(max_length=200, unique=True)
    slug = models.SlugField(max_length=200, unique=True)
    author = models.ForeignKey(User, on_delete= models.CASCADE,related_name='myapp_post')
    updated_on = models.DateTimeField(auto_now= True)
    content = models.TextField()
    created_on = models.DateTimeField(auto_now_add=True)
    status = models.IntegerField(choices=STATUS, default=0)
 
    class Meta:
        ordering = ['-created_on']

    def __str__(self):
        return self.title
  
    class Meta:  
        db_table = "myapp_post"
  
    def save(self, *args, **kwargs):
        value = self.title
        self.slug = slugify(value, allow_unicode=True)
        super().save(*args, **kwargs)

class Comment(models.Model):
    post = models.ForeignKey(Post,on_delete=models.CASCADE,related_name='comments')
    name = models.CharField(max_length=80)
    email = models.EmailField()
    body = models.TextField()
    created_on = models.DateTimeField(auto_now_add=True)
    active = models.BooleanField(default=False)

    class Meta:
        ordering = ['created_on']

    def __str__(self):
        return 'Comment {} by {}'.format(self.body, self.name)
  
    class Meta:  
        db_table = "myapp_comment"

Database Table
CREATE TABLE myapp_comment (
id INTEGER PRIMARY KEY,
post_id INTEGER,
name STRING (250),
email STRING (200),
body TEXT,
created_on DATETIME,
active STRING (50)
);
we have a Foreign key relation that establishes a many-to-one relationship with the Post model

need to synchronize this comment model into the database by running migrations to reflects the changes in the database.

(django) $ python manage.py makemigrations
(django) $ python manage.py migrate

Adding Comments Model To The Administration Site
Open admins.py file and write the following code.
 
#admin.py
from django.contrib import admin

from myapp.models import Post, Comment 
from django_summernote.admin import SummernoteModelAdmin

#admin.site.register(Post)

class PostAdmin(SummernoteModelAdmin):
    list_display = ('title', 'slug', 'status','created_on')
    list_filter = ("status",)
    search_fields = ['title', 'content']
    prepopulated_fields = {'slug': ('title',)}
    summernote_fields = ('content',)
 
admin.site.register(Post, PostAdmin)

@admin.register(Comment)
class CommentAdmin(admin.ModelAdmin):
    list_display = ('name', 'body', 'post', 'created_on', 'active')
    list_filter = ('active', 'created_on')
    search_fields = ('name', 'email', 'body')
    actions = ['approve_comments']

    def approve_comments(self, request, queryset):
        queryset.update(active=True)
Creating forms from models forms.py
 
#forms.py
from django import forms
from myapp.models import Comment


class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        fields = ('name', 'email', 'body')
Building Views views.py
 
#views.py
from django.shortcuts import render, redirect

from django.views import generic
from myapp.models import Post

from myapp.forms import CommentForm
from django.shortcuts import render, get_object_or_404

from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage

def index(request):
    object_list = Post.objects.filter(status=1).order_by('-created_on')
    paginator = Paginator(object_list, 3)  # 3 posts in each page
    page = request.GET.get('page')
    try:
        post_list = paginator.page(page)
    except PageNotAnInteger:
            # If page is not an integer deliver the first page
        post_list = paginator.page(1)
    except EmptyPage:
        # If page is out of range deliver last page of results
        post_list = paginator.page(paginator.num_pages)
    return render(request,
                  'index.html',
                  {'page': page,
                   'post_list': post_list})
 
# class PostDetail(generic.DetailView):
    # model = Post
    # template_name = 'post_detail.html'
 
def post_detail(request, slug):
    template_name = 'post_detail.html'
    post = get_object_or_404(Post, slug=slug)
    comments = post.comments.filter(active=True)
    new_comment = None
    # Comment posted
    if request.method == 'POST':
        comment_form = CommentForm(data=request.POST)
        if comment_form.is_valid():

            # Create Comment object but don't save to database yet
            new_comment = comment_form.save(commit=False)
            # Assign the current post to the comment
            new_comment.post = post
            # Save the comment to the database
            new_comment.save()
    else:
        comment_form = CommentForm()

    return render(request, template_name, {'post': post,
                                           'comments': comments,
                                           'new_comment': new_comment,
                                           'comment_form': comment_form}) 
Adding URL patterns for Views
 
from django.contrib import admin  
from django.urls import path, include
from myapp import views  

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [  
    path('admin/', admin.site.urls),  
    path('',views.index),
 #path('/', views.PostDetail.as_view(), name='post_detail'),
    path('/', views.post_detail, name='post_detail'),
    path('summernote/', include('django_summernote.urls')),
]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Templates For The Views post_deatail.html
//templates/post_detail.html
{% extends 'base.html' %}

{% block content %}
 <div class="card-body">
        <h1>{% block title %} {{ post.title }} {% endblock title %}</h1>
        <p class=" text-muted">{{ post.author }} | {{ post.created_on }}</p>
        <p class="card-text ">{{ post.content | safe }}</p>
    </div>
 
 <h2>{{ comments.count }} comments</h2>
    {% for comment in comments %}
        <div class="comments" style="padding: 10px;">
          <p class="font-weight-bold">
            {{ comment.name }}
            <span class=" text-muted font-weight-normal">
              {{ comment.created_on }}
            </span>
          </p>
          {{ comment.body | linebreaks }}
    <hr/>
        </div>
        {% endfor %}
  
  
  <div class="card-body">
        {% if new_comment %}
        <div class="alert alert-success" role="alert">
          Your comment is awaiting moderation
        </div>
        {% else %}
        <h3>Leave a comment</h3>
        <form method="post" style="margin-top: 1.3em;">
          {{ comment_form.as_p }}
          {% csrf_token %}
          <button type="submit" class="btn btn-primary">Submit</button>
        </form>
        {% endif %}
  </div>
   
{% endblock %}

Related Post