-- Table: user
CREATE TABLE user (
id INTEGER NOT NULL,
name VARCHAR (80) NOT NULL,
username VARCHAR (80) NOT NULL,
email VARCHAR (120) NOT NULL,
password VARCHAR (200) NOT NULL,
profile VARCHAR (180),
PRIMARY KEY (
id
),
UNIQUE (
username
),
UNIQUE (
email
)
);
INSERT INTO user (id, name, username, email, password, profile) VALUES (3, 'admin', 'admin', 'cairocoders@gmail.com', X'243262243132244A4A757A326B696734342E6835706B4A43303533382E6D315A53687369393631505278526A4D5767373337746939526372314C3761', 'profile.jpg');
-- Table: post
CREATE TABLE post (
id INTEGER NOT NULL,
title VARCHAR (200) NOT NULL,
slug VARCHAR (200) NOT NULL,
body TEXT NOT NULL,
category VARCHAR (100) NOT NULL,
image VARCHAR (150) NOT NULL,
user_id INTEGER NOT NULL,
views INTEGER,
comments INTEGER,
feature VARCHAR NOT NULL,
date_pub DATETIME NOT NULL,
PRIMARY KEY (
id
),
UNIQUE (
title
),
UNIQUE (
slug
),
FOREIGN KEY (
user_id
)
REFERENCES user (id) ON DELETE CASCADE
);
-- Table: comments
CREATE TABLE comments (
id INTEGER NOT NULL,
name VARCHAR (200) NOT NULL,
email VARCHAR (200) NOT NULL,
message TEXT NOT NULL,
post_id INTEGER NOT NULL,
feature BOOLEAN NOT NULL,
date_pub DATETIME NOT NULL,
PRIMARY KEY (
id
),
FOREIGN KEY (
post_id
)
REFERENCES post (id) ON DELETE CASCADE,
CHECK (feature IN (0, 1) )
);
URL
http://127.0.0.1:5000/login
Username : admin
password : cairocoders
http://127.0.0.1:5000/signup
http://127.0.0.1:5000/admin
http://127.0.0.1:5000/addpost
http://127.0.0.1:5000/update/3
http://127.0.0.1:5000/comments/
http://127.0.0.1:5000/search?q=python
http://127.0.0.1:5000/news/7-essential-vs-code-extensions-for-python-developers-in-2021
pip install Flask-Bcrypt = https://pypi.org/project/Flask-Bcrypt/
pip install Flask-Login = https://pypi.org/project/Flask-Login/
pip install flask-msearch = https://pypi.org/project/flask-msearch/
pip install Flask-SQLAlchemy = https://pypi.org/project/Flask-SQLAlchemy/
#app.py from flaskblog import app if __name__ == "__main__": app.run(debug=True)flaskblog/__init__.py
#flaskblog/__init__.py from flask import Flask from flask_bcrypt import Bcrypt #pip install Flask-Bcrypt https://pypi.org/project/Flask-Bcrypt/ from flask_sqlalchemy import SQLAlchemy #pip install Flask-SQLAlchemy = https://pypi.org/project/Flask-SQLAlchemy/ from flask_login import LoginManager #pip install Flask-Login = https://pypi.org/project/Flask-Login/ from flask_msearch import Search #pip install flask-msearch = https://pypi.org/project/flask-msearch/ app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db' app.config['SECRET_KEY']='cairocoders-ednalan' app.config['SQLALCHEMY_TRACK_MODIFICATIONS']=True db = SQLAlchemy(app) bcrypt = Bcrypt(app) search = Search() search.init_app(app) login_manager = LoginManager(app) login_manager.login_view = "login" login_manager.login_message_category = "info" from flaskblog import routesflaskblog/routes.py
#flaskblog/routes.py from flask import render_template, redirect, url_for, request, flash,current_app,abort from flask_login import login_user, login_required,logout_user,current_user from flaskblog import app, bcrypt,db,search from .forms import SignUpForm,LoginForm,PostForm from .models import User, Post,Comments import os import secrets def save_photo(photo): rand_hex = secrets.token_hex(10) _, file_extention = os.path.splitext(photo.filename) file_name = rand_hex + file_extention file_path = os.path.join(current_app.root_path, 'static/images', file_name) photo.save(file_path) return file_name @app.route('/') def index(): posts = Post.query.order_by(Post.id.desc()).all() return render_template('post/index.html', posts=posts) @app.route('/news/<string:slug>', methods=['POST','GET']) def news(slug): post = Post.query.filter_by(slug=slug).first() comment = Comments.query.filter_by(post_id=post.id).filter_by(feature=True).all() post.views = post.views + 1 db.session.commit() Thanks ="" if request.method =="POST": post_id = post.id name = request.form.get('name') email = request.form.get('email') message = request.form.get('message') comment = Comments(name=name,email=email,message=message,post_id=post_id) db.session.add(comment) post.comments = post.comments + 1 db.session.commit() flash('Your comment has been submited submitted will be published after aproval of admin', 'success') return redirect(request.url) return render_template('post/news-details.html', post=post, comment=comment, Thanks=Thanks) @app.route('/search') def search(): keyword = request.args.get('q') posts = Post.query.msearch(keyword,fields=['title'],limit=6) return render_template('post/search.html', posts=posts) @app.route('/admin') @login_required def admin(): posts = Post.query.order_by(Post.id.desc()).all() return render_template('admin/home.html',posts = posts) @app.route('/comments/', methods=['POST','GET']) def comments(): comments =Comments.query.order_by(Comments.id.desc()).all() return render_template('admin/comment.html',comments=comments) @app.route('/check/<int:id>', methods=['POST','GET']) @login_required def check(id): comment = Comments.query.get_or_404(id) if (comment.feature == True): comment.feature = False db.session.commit() else: comment.feature = True db.session.commit() return redirect(url_for('comments')) return redirect(url_for('comments')) @app.route('/addpost',methods=['POST','GET']) @login_required def addpost(): form = PostForm(request.form) if request.method =="POST" and form.validate(): photo = save_photo(request.files.get('photo')) post = Post(title=form.title.data, body=form.content.data,category=request.form.get('category'),image=photo,author=current_user) db.session.add(post) db.session.commit() flash('Your post has been added ','success') return redirect(url_for('admin')) return render_template('admin/addpost.html', form=form) @app.route('/update/<int:id>',methods=['POST','GET']) @login_required def update(id): form = PostForm(request.form) post = Post.query.get_or_404(id) form.title.data = post.title form.content.data = post.body if request.method=='POST' and form.validate(): if request.files.get('photo'): try: os.unlink(os.path.join(current_app.root_path, 'static/images/'+ post.image)) post.image = save_photo(request.files.get('photo')) except: post.image = save_photo(request.files.get('photo')) post.title = form.title.data post.body = form.content.data post.category = request.form.get('category') flash('Post has been updated', 'success') db.session.commit() return redirect(url_for('admin')) return render_template('admin/addpost.html', form=form, post=post) @app.route('/delete/<int:id>') @login_required def delete(id): post = Post.query.get_or_404(id) try: os.unlink(os.path.join(current_app.root_path,'static/images/'+ post.image)) db.session.delete(post) except: db.session.delete(post) flash('Post has deleted ','success') db.session.commit() return redirect(url_for('admin')) @app.route('/delcomment/<int:id>') @login_required def delcomment(id): comment = Comments.query.get_or_404(id) db.session.delete(comment) db.session.commit() flash('Comment has deleted ','success') return redirect(url_for('admin')) @app.route('/signup', methods=['POST','GET']) def signup(): form = SignUpForm(request.form) if request.method == 'POST' and form.validate(): hashed_password = bcrypt.generate_password_hash(form.password.data) user = User(name=form.name.data,username=form.username.data, email=form.email.data,password=hashed_password) db.session.add(user) db.session.commit() flash('Thanks for registering, you able to login now','success') return redirect(url_for('login')) return render_template('admin/signup.html', form=form) @app.route('/login', methods=['POST','GET']) def login(): #username : admin pass: cairocoders if current_user.is_authenticated: next = request.args.get('next') return redirect(next or url_for('admin')) form = LoginForm(request.form) if request.method == 'POST' and form.validate(): user = User.query.filter_by(username=form.username.data).first() if not user: flash('This user not exists','warning') return redirect(url_for('login')) if user and bcrypt.check_password_hash(user.password, form.password.data): login_user(user) flash('Logged in successfully.','success') next = request.args.get('next') return redirect(next or url_for('admin')) flash('Invalid password','danger') return render_template('admin/login.html', form=form) @app.route('/logout') @login_required def logout(): logout_user() flash('you are logout','success') return redirect(url_for('login'))flaskblog/models.py
#flaskblog/models.py from flaskblog import db, login_manager from datetime import datetime from flask_login import UserMixin from sqlalchemy import event from slugify import slugify @login_manager.user_loader def load_user(user_id): return User.query.filter_by(id=user_id).first() class User(db.Model,UserMixin): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(80), nullable=False) username = db.Column(db.String(80), unique=True, nullable=False) email = db.Column(db.String(120), unique=True, nullable=False) password = db.Column(db.String(200), nullable=False) profile = db.Column(db.String(180), default="profile.jpg") def __repr__(self): return '<User %r>' % self.username class Post(db.Model): __searchable__ = ['title', 'body'] id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(200), unique=True, nullable=False) slug = db.Column(db.String(200), unique=True, nullable=False) body = db.Column(db.Text, nullable=False) category = db.Column(db.String(100), nullable=False) image = db.Column(db.String(150), nullable=False, default='no-image.jpg') user_id = db.Column(db.Integer, db.ForeignKey('user.id', ondelete='CASCADE'), nullable=False) author = db.relationship('User', backref=db.backref('posts',lazy=True, passive_deletes=True)) views = db.Column(db.Integer,default=0) comments = db.Column(db.Integer,default=0) feature = db.Column(db.String, default=1, nullable=False) date_pub = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) def __repr__(self): return '<Post %r' % self.title @staticmethod def generate_slug(target, value, oldvalue, initiator): if value and (not target.slug or value != oldvalue): target.slug = slugify(value) db.event.listen(Post.title, 'set',Post.generate_slug, retval=False) class Comments(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(200), unique=False, nullable=False) email = db.Column(db.String(200), unique=False, nullable=False) message = db.Column(db.Text, nullable=False) post_id = db.Column(db.Integer, db.ForeignKey('post.id', ondelete='CASCADE'), nullable=False) post = db.relationship('Post', backref=db.backref('posts',lazy=True, passive_deletes=True)) feature = db.Column(db.Boolean, default=False, nullable=False) date_pub = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) def __repr__(self): return '<Post %r' % self.nameflaskblog/forms.py
#flaskblog/forms.py from wtforms import Form, BooleanField, StringField,FileField, PasswordField, validators, TextAreaField,ValidationError from flask_wtf.file import FileField, FileAllowed, FileRequired class SignUpForm(Form): name = StringField('Name', [validators.Length(min=2, max=25)]) username = StringField('Username', [validators.Length(min=4, max=25)]) email = StringField('Email Address', [validators.Length(min=6, max=35)]) password = PasswordField('Password', [validators.DataRequired(), validators.EqualTo('confirm', message='Passwords must match')]) confirm = PasswordField('Repeat Password') class LoginForm(Form): username = StringField('Username', [validators.Length(min=4, max=25)]) password = PasswordField('Password',[validators.DataRequired()]) class PostForm(Form): title = StringField('Title',[validators.DataRequired()]) content = TextAreaField('Content', [validators.DataRequired()]) photo = FileField()flaskblog/templates/post/base.html
//flaskblog/templates/post/base.html <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <link rel="icon" href="{{ url_for('static', filename='img/favicon.png')}}" type="image/png"> <title>Python Flask Blog with Admin using flask_sqlalchemy, flask_login, flask_bcrypt and flask_msearch</title> <link rel="stylesheet" href="{{url_for('static', filename='css/bootstrap.css')}}"> <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css"> <link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}"> <link rel="stylesheet" href="{{url_for('static', filename='css/responsive.css')}}"> </head> <body> <header class="header_area"> <div class="logo_part"> <div class="container"> <div class="float-left"> <a class="logo" href="#"><img src="{{ url_for('static', filename='images/logo.png')}}" alt=""></a> </div> </div> </div> <div class="main_menu"> <nav class="navbar navbar-expand-lg navbar-light"> <div class="container"> <div class="container_inner"> <div class="collapse navbar-collapse offset" id="navbarSupportedContent"> <ul class="nav navbar-nav menu_nav"> <li class="nav-item active"><a class="nav-link" href="/">Home</a></li> <li class="nav-item"><a class="nav-link" href="#">About</a></li> <li class="nav-item"><a class="nav-link" href="#">Contact</a></li> </ul> <ul class="nav navbar-nav navbar-right ml-auto"> <form action="{{ url_for('search')}}" method="GET" class="input-group mr-2"> <input type="text" class="form-control" name="q"> <div class="input-group-append"> <input type="submit" class="btn btn-outline-info" value="Search"> </div> </form> </ul> </div> </div> </div> </nav> </div> </header> {% block content %} {% endblock content %} <footer class="footer-area"> <div class="container"> <p> Copyright ©<script> document.write(new Date().getFullYear()); </script> All rights reserved </p> </div> </div> </footer> <script src="{{url_for('static', filename='js/jquery-3.2.1.min.js')}}"></script> <script src="{{url_for('static', filename='js/popper.js')}}"></script> <script src="{{url_for('static', filename='js/bootstrap.min.js')}}"></script> </body> </html>flaskblog/templates/post/index.html
#flaskblog/templates/post/index.html {% extends 'post/base.html' %} {% block content %} {% include 'post/slider.html'%} <br> <section class="news_area"> <div class="container"> <div class="row"> <div class="col-lg-8"> <div class="main_title2"> <h2>Latest Blog</h2> </div> <div class="latest_news"> {% for post in posts %} <div class="media"> <div class="d-flex"> <img class="img-fluid" src="{{url_for('static',filename='images/' + post.image)}}" style="width:200px; height:200px;"> </div> <div class="media-body"> <div class="choice_text"> <div class="date"> <a class="" href="#">{{post.author.name}}</a> <a href="#"><i class="fa fa-calendar" aria-hidden="true"></i>March 14, 2018</a> <a href="#"><i class="fa fa-comments-o" aria-hidden="true"></i> Views {{post.views }} | {{post.comments}} Comennts</a> </div> <a href="{{url_for('news', slug=post.slug)}}"> <h4>{{post.title}}</h4> </a> <p>{{post.body |truncate(200, True) }}</p> </div> </div> </div> {% endfor %} </div> </div> </div> </div> </section> {% endblock content %}flaskblog/templates/post/news-details.html
#flaskblog/templates/post/news-details.html {% extends 'post/base.html' %} {% block content %} <section class="news_area single-post-area p_100"> <div class="container"> <div class="row"> <div class="col-lg-8"> <div class="main_blog_details"> <img class="img-fluid" src="{{url_for('static',filename='images/' + post.image)}}" alt="" style="width:100%; height: 400px;"> <h4> {{post.title}} </h4> <div class="user_details"> <div class="float-left"> <a href="#">Python</a> <a href="#">Flask</a> </div> <div class="float-right"> <div class="media"> <div class="media-body"> <h5>Cairocoder</h5> <p>12 Dec, 2020 11:21 am</p> </div> </div> </div> </div> <p>{{post.body}}</p> <div class="news_d_footer"> <a href="#"><i class="lnr lnr lnr-heart"></i>cairocoders and 4 people like this</a> <a class="justify-content-center ml-auto" href="#"><i class="lnr lnr lnr-bubble"></i> {{post.views }} Views | {{post.comments}} Comments</a> <div class="news_socail ml-auto"> <a href="#"><i class="fa fa-facebook"></i></a> <a href="#"><i class="fa fa-twitter"></i></a> <a href="#"><i class="fa fa-youtube-play"></i></a> <a href="#"><i class="fa fa-pinterest"></i></a> <a href="#"><i class="fa fa-rss"></i></a> </div> </div> </div> <div class="comments-area"> <h4>{{post.comments}} Comments</h4> {% for message in comment %} <div class="comment-list"> <div class="single-comment justify-content-between d-flex"> <div class="user justify-content-between d-flex"> <div class="thumb"> <img src="img/blog/c1.jpg" alt=""> </div> <div class="desc"> <h5><a href="#">{{message.name}}</a></h5> <p class="date">{{message.date_pub.strftime('%Y')}}</p> <p class="comment"> {{message.message}} </p> </div> </div> <div class="reply-btn"> <!-- <a href="" class="btn-reply text-uppercase">reply</a> --> </div> </div> </div> {% endfor %} </div> <div class="comment-form"> {% include 'admin/messages.html' %} <h4>Leave a Comment</h4> <form method="POST"> <div class="form-group form-inline"> <div class="form-group col-lg-6 col-md-6 name"> <input type="text" name="name" class="form-control" id="name" placeholder="Enter Name" onfocus="this.placeholder = ''" onblur="this.placeholder = 'Enter Name'"> </div> <div class="form-group col-lg-6 col-md-6 email"> <input type="email" name="email" class="form-control" id="email" placeholder="Enter email address" onfocus="this.placeholder = ''" onblur="this.placeholder = 'Enter email address'"> </div> </div> <div class="form-group"> <textarea name="message" class="form-control mb-10" rows="5" name="message" placeholder="Messege" onfocus="this.placeholder = ''" onblur="this.placeholder = 'Messege'" required=""></textarea> </div> <button type="submit" class="primary-btn submit_btn">Post Comment</button> </form> </div> </div> <div class="col-lg-4"> Right Side </div> </div> </div> </section> {% endblock content %}flaskblog/post/search.html
//flaskblog/post/search.html {% extends 'post/base.html' %} {% block content %} <section class="news_area single-post-area p_100"> <div class="container"> <div class="row"> <div class="col-lg-8"> <div class="main_blog_details"> <div class="latest_news"> {% for post in posts %} <div class="media"> <div class="d-flex"> <img class="img-fluid" src="{{url_for('static',filename='images/' + post.image)}}" style="width:200px; height:200px;"> </div> <div class="media-body"> <div class="choice_text"> <div class="date"> <a class="" href="#">{{post.author.name}}</a> <a href="#"><i class="fa fa-calendar" aria-hidden="true"></i>March 14, 2020</a> <a href="#"><i class="fa fa-comments-o" aria-hidden="true"></i> Views {{post.views }} | {{post.comments}} Comennts</a> </div> <a href="{{url_for('news', slug=post.slug)}}"> <h4>{{post.title}}</h4> </a> <p>{{post.body |truncate(200, True) }}</p> </div> </div> </div> {% endfor %} </div> </div> </div> <div class="col-lg-4"> Right </div> </div> </div> </section> {% endblock content %}flaskblog/templates/post/slider.html
//flaskblog/templates/post/slider.html <section class="home_banner_area"> <div class="banner_inner d-flex align-items-center bg-light"> <div class="container"> <div id="carouselExampleIndicators" class="carousel slide" data-ride="carousel"> <ol class="carousel-indicators" style="position:absolute; bottom:0%;"> <li data-target="#carouselExampleIndicators" data-slide-to="0" class="active"></li> <li data-target="#carouselExampleIndicators" data-slide-to="1"></li> <li data-target="#carouselExampleIndicators" data-slide-to="2"></li> <li data-target="#carouselExampleIndicators" data-slide-to="3"></li> </ol> <div class="carousel-inner"> {% for post in posts %} {% if loop.index == 1 %} <div class="carousel-item active"> {% else %} <div class="carousel-item"> {% endif %} <div class="background_image banner_inner" style="background-image:url('{{url_for('static', filename='images/'+ post.image)}}');"> <div class="banner_content text-center" style="position:absolute; right:25%; top: 50%;"> <div class="date"> <a href="#">Gadgets</a> <a href="#"><i class="fa fa-calendar" aria-hidden="true"></i>{{post.date_pub.strftime('%B %Y %d')}}</a> <a href="#"><i class="fa fa-comments-o" aria-hidden="true"></i>05</a> </div> <h4><a href="{{url_for('news', slug=post.slug)}}" class="text-white" style="text-shadow:5px 5px 10px black;">{{post.title}}</a> </h4> <p style="text-shadow:5px 5px 10px black;">{{post.body| truncate(150, True)}}</p> </div> </div> </div> {% endfor %} </div> </div> </div> </div> </section>flaskblog/templates/admin/login.html
//flaskblog/templates/admin/login.html <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <link rel="icon" href="static/web.jpg"> <title> Login</title> </head> <body> <h1 class="text-center"> Login now </h1> {% from "admin/_formhelpers.html" import render_field %} <div class="container"> <div class="row"> <div class="col-md-3"></div> <div class="col-md-6"> {% include 'admin/messages.html' %} <form method="post"> <div> {{ render_field(form.username, class="form-control") }} {{ render_field(form.password, class="form-control") }} </div> <p><input type=submit value="Login" class="btn btn-info"> </form> </div> <div class="col-md-3"></div> </div> </div> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> </body> </html>flaskblog/templates/admin/signup.html
//flaskblog/templates/admin/signup.html <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <link rel="icon" href="static/web.jpg"> <title> Sign Up</title> </head> <body> <h1 class="text-center"> Sign up now </h1> {% from "admin/_formhelpers.html" import render_field %} <div class="container"> <div class="row"> <div class="col-md-3"></div> <div class="col-md-6"> {% include 'admin/messages.html' %} <form method="post"> <div> {{ render_field(form.name, class="form-control")}} {{ render_field(form.username, class="form-control") }} {{ render_field(form.email, class="form-control") }} {{ render_field(form.password, class="form-control") }} {{ render_field(form.confirm, class="form-control") }} </div> <p><input type=submit value="Register" class="btn btn-info"> </form> </div> <div class="col-md-3"></div> </div> </div> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> </body> </html>flaskblog/templates/admin/home.html
//flaskblog/templates/admin/home.html <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <title> Dashboard </title> </head> <body> <h2 class="text-center">User Dashboard </h2> {% include 'admin/messages.html' %} <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="{{url_for('admin')}}">Navbar</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav mr-auto"> <li class="nav-item active"> <a class="nav-link" href="{{url_for('admin')}}">Home <span class="sr-only">(current)</span></a> </li> <li class="nav-item"> <a class="nav-link" href="{{url_for('addpost')}}">Add post</a> </li> <li class="nav-item"> <a class="nav-link" href="{{url_for('comments')}}">Comments</a> </li> </ul> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="{{ url_for('logout')}}"aria-disabled="true">Logout</a> </li> </ul> </div> </nav> <table class="table table-striped table-bordered table-sm"> <thead class="bg-dark text-white"> <th>Sr</th> <th>Title</th> <th>Category</th> <th>Author</th> <th>Date</th> <th>Image</th> <th>Edit</th> <th>Delete</th> </thead> <tbody> {% for post in posts %} <tr> <td>{{loop.index}}</td> <td>{{post.title}}</td> <td>{{post.category}}</td> <td>{{post.author.name}}</td> <td>{{post.date_pub.strftime('%Y %B %d')}}</td> <td> <img src="{{url_for('static', filename='images/' + post.image)}}" alt="{{post.category}}" width="40"></td> <td> <a href="update/{{ post.id}}" class="btn btn-sm btn-info">Edit</a> </td> <td><button type="button" class="btn btn-danger btn-sm" data-toggle="modal" data-target="#del{{post.id}}"> delete </button></td> </tr> <!-- The Modal --> <div class="modal" id="del{{post.id}}"> <div class="modal-dialog"> <div class="modal-content"> <!-- Modal Header --> <div class="modal-header"> <h4 class="modal-title text-danger"> Are you do you want delete this post </h4> <button type="button" class="close" data-dismiss="modal">×</button> </div> <div class="modal-body"> {{post.title}} </div> <div class="modal-footer"> <div class="mr-auto"> <a href="delete/{{ post.id}}" class="btn btn-danger btn-sm"> Delete </a></div> <button type="button" class="btn btn-primary btn-sm" data-dismiss="modal">Cancel</button> </div> </div> </div> </div> {% endfor %} </tbody> </table> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> </body> </html>flaskblog/templates/admin/comment.html
//flaskblog/templates/admin/comment.html <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"> <script src="https://code.jquery.com/jquery-3.4.0.js"> </script> <title> Dashboard-Comments </title> </head> <body> <h2 class="text-center">Dashboard-Comments </h2> {% include 'admin/messages.html' %} <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="{{url_for('admin')}}">Navbar</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav mr-auto"> <li class="nav-item active"> <a class="nav-link" href="{{url_for('admin')}}">Home <span class="sr-only">(current)</span></a> </li> <li class="nav-item"> <a class="nav-link" href="{{url_for('addpost')}}">Add post</a> </li> </ul> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="{{ url_for('logout')}}" aria-disabled="true">Logout</a> </li> </ul> </div> </nav> <table class="table table-striped table-bordered table-sm"> <thead class="bg-dark text-white"> <th>Sr</th> <th>Name</th> <th>Comments</th> <th>Post ID</th> <th>Date</th> <th>Status</th> <td>Delete</td> </thead> <tbody> {% for comment in comments %} <tr> <td>{{loop.index}}</td> <td>{{comment.name}}</td> <td>{{comment.message | truncate(100, True)}}</td> <td>{{comment.post.id}}</td> <!-- <td>{{comment.feature}}</td> --> <td>{{comment.date_pub.strftime('%Y %B %d')}} </td> {% if comment.feature == False %} <td> <a href="{{ url_for('check', id=comment.id) }}" class="text-center text-danger"> Pandding </a> </td> {% else %} <td> <a href="{{ url_for('delcomment', id=comment.id) }}" class="text-success"> Aproved </a> </td> {% endif %} <td> <a href="{{ url_for('check', id=comment.id) }}" class="btn btn-sm btn-danger"> Delete </a> </td> </tr> {% endfor %} </tbody> </table> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"> </script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"> </script> </body> </html>flaskblog/templates/admin/messages.html
//flaskblog/templates/admin/messages.html {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} <div class=flashes> {% for category, message in messages %} <div class=" alert alert-{{ category }}">{{ message }}</div> {% endfor %} </div> {% endif %} {% endwith %}flaskblog/templates/admin/_formhelpers.html
//flaskblog/templates/admin/_formhelpers.html {% macro render_field(field) %} <dt>{{ field.label }} <dd>{{ field(**kwargs)|safe }} {% if field.errors %} <ul class=errors> {% for error in field.errors %} <li class="text-danger">{{ error }}</li> {% endfor %} </ul> {% endif %} </dd> {% endmacro %}