Install django-summernote.
pip install django-summernote
django_summernote to INSTALLED_APP in settings.py.
INSTALLED_APPS += ('django_summernote', )
django_summernote.urls to urls.py.
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('summernote/', include('django_summernote.urls')),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Media settings
X_FRAME_OPTIONS = 'SAMEORIGIN'
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
To explore more configuration read the official documentation of the package, https://github.com/summernote/django-summernote
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | / / blogsite / settings.py INSTALLED_APPS = [ 'django.contrib.admin' , 'django.contrib.auth' , 'django.contrib.contenttypes' , 'django.contrib.sessions' , 'django.contrib.messages' , 'django.contrib.staticfiles' , 'myapp' , #add myapp ] INSTALLED_APPS + = ( 'django_summernote' , ) X_FRAME_OPTIONS = 'SAMEORIGIN' |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | / / myapp / views.py from django.shortcuts import render, redirect from django.contrib.auth import authenticate, login, logout from django.contrib.auth.models import User from django.contrib import messages from myapp.models import Category, Post category_list = Category.objects.exclude(status = 2 ). all () context = { 'page_title' : 'Simple Blog Site' , 'category_list' : category_list, 'category_list_limited' : category_list[: 3 ] } # Create your views here. #Logout def logoutuser(request): logout(request) return redirect( '/' ) def home(request): context[ 'page_title' ] = 'Home' posts = Post.objects. filter (status = 1 ). all () context[ 'posts' ] = posts return render(request, 'home.html' ,context) def view_post(request,pk = None ): context[ 'page_title' ] = "" if pk is None : messages.error(request, "Unabale to view Post" ) return redirect( 'home-page' ) else : post = Post.objects. filter ( id = pk).first() context[ 'page_title' ] = post.title context[ 'post' ] = post return render(request, 'view_post.html' ,context) def post_by_category(request,pk = None ): if pk is None : messages.error(request, "Unabale to view Post" ) return redirect( 'home-page' ) else : category = Category.objects. filter ( id = pk).first() context[ 'page_title' ] = category.name context[ 'category' ] = category posts = Post.objects. filter (category = category). all () context[ 'posts' ] = posts return render(request, 'by_categories.html' ,context) def categories(request): categories = Category.objects. filter (status = 1 ). all () context[ 'page_title' ] = "Category Management" context[ 'categories' ] = categories return render(request, 'categories.html' ,context) |
1 2 3 4 5 6 7 8 9 10 11 12 | / / blogsite / urls.py from django.contrib import admin from django.urls import include, path from django.conf import settings from django.conf.urls.static import static urlpatterns = [ path( 'admin/' , admin.site.urls), path(' ', include(' myapp.urls')), path( 'summernote/' , include( 'django_summernote.urls' )), ] + static(settings.MEDIA_URL, document_root = settings.MEDIA_ROOT) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | / / myspp / urls.py from . import views from django.contrib import admin from django.urls import path, re_path from django.contrib.auth import views as auth_views from django.views.generic.base import RedirectView urlpatterns = [ path( 'redirect-admin' , RedirectView.as_view(url = "/admin" ),name = "redirect-admin" ), path('', views.home, name = "home-page" ), path( 'logout' ,views.logoutuser,name = 'logout' ), path(r 'view_post/<int:pk>' ,views.view_post,name = 'view-post' ), path(r '<int:pk>' ,views.post_by_category,name = 'category-post' ), path( 'categories' ,views.categories,name = 'category-page' ), ] |
Run the commands below to make migrations:
python manage.py makemigrations
python manage.py migrate
C:\django\blogsite>python manage.py makemigrations
C:\django\blogsite>python manage.py migrate
myapp/models.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | / / myapp / models.py from django.db import models from unicodedata import category from django.db import models from django.contrib.auth.models import User from django.utils import timezone class Category(models.Model): name = models.CharField(max_length = 250 ) description = models.TextField(blank = True , null = True ) status = models.IntegerField(default = 1 ) date_added = models.DateTimeField(default = timezone.now) date_updated = models.DateTimeField(auto_now = True ) def __str__( self ): return self .name class Post(models.Model): category = models.ForeignKey(Category,on_delete = models.CASCADE) title = models.TextField() author = models.ForeignKey(User,on_delete = models.CASCADE) blog_post = models.TextField() banner = models.ImageField(blank = True , null = True , upload_to = 'images/' ) status = models.IntegerField(default = 0 ) date_added = models.DateTimeField(default = timezone.now) date_updated = models.DateTimeField(auto_now = True ) def __str__( self ): return self .title + " - " + self .category.name |
https://getbootstrap.com/docs/5.0/getting-started/introduction/
https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css
myapp/templates/home.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | //myapp/templates/home.html {% extends "base.html" %} {% block pageContent %} <section class = "text-center" > <h4 class = "mb-5" ><strong>All Posts</strong></h4> <div class = "row" > {% for post in posts %} <div class = "col-lg-4 col-md-6 mb-4" > <div class = "card shadow border" > <div class = "bg-image hover-overlay ripple" data-mdb-ripple-color= "light" > <img src= "{% if post.banner %}{{ post.banner.url }}{% else %}{{ MEDIA_URL}}/media/default/python-django.png{% endif %}" class = "img-fluid post-banner bg-gradient bg-dark" /> <a href= "#!" > <div class = "mask" style= "background-color: rgba(251, 251, 251, 0.15);" ></div> </a> </div> <div class = "card-body" > <h5 class = "card-title" >{{ post.title }}</h5> <div class = "card-text truncate-3" >{{ post.blog_post|safe }} </div> <a href= "{% url 'view-post' post.id %}" class = "btn btn-primary" >Read</a> </div> </div> </div> {% endfor %} </div> {% if not posts %} <center>No Bogs has been posted yet</center> {% endif %} </section> </div> {% endblock pageContent %} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | //myapp/templates/base.html {% load static %} <!DOCTYPE html> <html lang= "en" > <head> <meta charset= "UTF-8" > <meta http-equiv= "X-UA-Compatible" content= "IE=edge" > <meta name= "viewport" content= "width=device-width, initial-scale=1.0" > {% if page_title %} <title>{{ page_title }} | Blog Site</title> {% else %} <title>Blog Site</title> {% endif %} <link rel= "stylesheet" href= "{% static 'blogApp/assets/bootstrap/css/bootstrap.min.css' %}" > </head> <body> {% block TopNavigation %} {% include "TopNavigation.html" %} {% endblock TopNavigation %} <main class = "my-5" > <div class = "container" style= "padding-top: 50px;" > {% block pageContent %} {% endblock pageContent %} </div> </main> {% block ScriptBlock %} {% endblock ScriptBlock %} <footer class = "bg-light text-lg-start" > <div class = "text-center p-3" style= "background-color: rgba(0, 0, 0, 0.2);" > © {% now 'Y' %} Copyright: <a class = "text-dark" href= "#" target= "_blank" >Cairocoders</a> </div> </footer> </body> </html> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | //myapp/templates/TopNavigation.html {% load static %} <header> <nav class = "navbar navbar-expand-lg navbar-light bg-white fixed-top" > <div class = "container" > <a class = "navbar-brand" target= "_blank" href= "#" >Cairocoders</a> <button class = "navbar-toggler" type= "button" data-mdb-toggle= "collapse" data-mdb-target= "#navbarExample01" aria-controls= "navbarExample01" aria-expanded= "false" aria-label= "Toggle navigation" > <i class = "fas fa-bars" ></i> </button> <div class = "collapse navbar-collapse" id= "navbarExample01" > <ul class = "navbar-nav me-auto mb-2 mb-lg-0" > <li class = "nav-item active" > <a class = "nav-link" aria-current= "page" href= "{% url 'home-page' %}" >Home</a> </li> {% for category in category_list_limited %} <li class = "nav-item" > <a class = "nav-link" href= "{% url 'category-post' category.pk %}" >{{ category.name }}</a> </li> {% endfor %} <li class = "nav-item" > <a class = "nav-link" href= "{% url 'category-page' %}" >All Categories</a> </li> </ul> <ul class = "navbar-nav d-flex flex-row" > {% if user.id %} <li class = "nav-item me-3 me-lg-0" > Hello, {{ user.first_name }} {{user.last_name}} </li> <li class = "nav-item me-3 me-lg-0" > <a class = "nav-link" href= "{% url 'logout' %}" >Logout</a> </li> {% endif %} </ul> </div> </div> </nav> </header> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | //myapp/templates/view_post.html {% extends "base.html" %} {% block pageContent %} <section class = "text-center" > <div class = "col-lg-12 col-md-12 col-sm-12 col-xs-12" > <div class = "row justify-content-center" > <div class = " col-lg-12 col-md-12 col-sm-12 col-xs-12 card card-default rounded-0 shadow" > <div class = "card-body" > <center> <img src= "{% if post.banner %}{{ post.banner.url }}{% else %}{{ MEDIA_URL}}/media/default/python-django.png{% endif %}" alt= "" class = "img-fluid bg-gradient" id= "view-post-banner" > </center> <h4 class = "fw-bolder mt-4 text-start" >{{ post.title }}</h4> <hr> <div class = "lh-1 text-start" > <span class = "me-5" ><small>Author: <b>{{ post.author }}</b></small></span> <span class = "me-5" ><small>Category: <b>{{ post.category }}</b></small></span> <span><small><i class = "fa fa-calendar-day" ></i> Published: <b>{{ post.date_added| date : "F d, Y h:i A" }}</b></small></span> </div> <div class = "clear-fix py-3" ></div> <div>{{ post.blog_post|safe }}</div> </div> </div> </div> </div> </section> </div> {% endblock pageContent %} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | //myapp/templates/by_categories.html {% extends "base.html" %} {% block pageContent %} <section class = "text-center" > <h4 class = "mb-5" ><strong> '{{ category }}' Posts</strong></h4> <div class = "row" > {% for post in posts %} <div class = "col-lg-4 col-md-6 mb-4" > <div class = "card shadow border" > <div class = "bg-image hover-overlay ripple" data-mdb-ripple-color= "light" > <img src= "{% if post.banner %}{{ post.banner.url }}{% else %}{{ MEDIA_URL}}/media/default/python-django.png{% endif %}" class = "img-fluid post-banner bg-gradient bg-dark" /> <a href= "#!" > <div class = "mask" style= "background-color: rgba(251, 251, 251, 0.15);" ></div> </a> </div> <div class = "card-body" > <h5 class = "card-title" >{{ post.title }}</h5> <div class = "card-text truncate-3" >{{ post.blog_post|safe }} </div> <a href= "{% url 'view-post' post.id %}" class = "btn btn-primary" >Read</a> </div> </div> </div> {% endfor %} </div> {% if not posts %} <center>No Bogs has been posted yet</center> {% endif %} </section> </div> {% endblock pageContent %} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | //myapp/templates/categories.html {% extends 'base.html' %} {% block pageContent %} <div class = "col-lg-12 col-md-12 col-sm-12 col-xs-12" > <div class = "card card-default rounded-0 shadow " > <div class = "card-header" > <div class = "d-flex w-100 align-items-center justify-content-between" > <h4 class = "card-title fw-bold" >Category Management</h4> </div> </div> <div class = "card-body" > <div class = "container-fluid" > <div id= "list" class = "list-group" > {% for category in categories %} <a href= "{% url 'category-post' category.id %}" class = "list-group-item list-group-item-action" > <h4><b>{{ category.name }}</b></h4> <hr> <p>{{ category.description }}</p> </a> {% endfor %} </div> {% if not categories %} <center>No Category Listed Yet</center> {% endif %} </div> </div> </div> </div> {% endblock pageContent %} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | / / myapp / admin.py import django from django.contrib import admin from myapp.models import Category, Post from django_summernote.admin import SummernoteModelAdmin # Register your models here. admin.site.register(Category) #admin.site.register(Post) class PostAdmin(SummernoteModelAdmin): summernote_fields = ( 'blog_post' ,) admin.site.register(Post, PostAdmin) |