Hey Folks 👋🏻!!
I am back!! again haha!
So today, we’ll code together the CRUD of Post/Articles that we did together in this blog. So, as usual, we’ll open our backend/app.py file and post our make our code look like this:
'''Flask App For PyGuy WebSite'''
from flask import (Flask, jsonify, render_template,
request, session, make_response, abort, Response)
from flask_jwt_extended import (
JWTManager, jwt_required, create_access_token,
get_jwt_identity
)
from flask_pymongo import PyMongo
from flask_bcrypt import Bcrypt
from bson.objectid import ObjectId
from http import HTTPStatus
# App Definitions & Configs
app = Flask(__name__, root_path='../frontend')
bcrypt = Bcrypt(app)
jwt = JWTManager(app)
app.config["MONGO_DBNAME"] = 'pysite'
app.config["MONGO_URI"] = "mongodb://localhost:27017/pysite"
app.secret_key = 'dawudawudbawbfawbfawc3241241j1jnjkjkn141nj4'
app.config['JWT_SECRET_KEY'] = "dawudawudbawbfawbfawc3241241j1jnjkjkn141nj4"
mongo = PyMongo(app)
# This will be the index route ....
@app.route("/api")
def index():
return render_template("index.html")
@app.route('/api/v1/posts', methods=['GET'])
def articles():
articles = mongo.db.articles
output = []
for q in articles.find():
output.append(
{'title': q['title'], 'description': q['description'], 'tags': q['tags']})
return make_response({'code': 200, 'result': output})
@app.route("/api/v1/add_articles", methods=["POST"])
def add_articles():
"""
add_articles [Adds new article]
[Saves it to databases, with tags, description etc...]
:return: [description]
:rtype: [type]
"""
article = mongo.db.articles
title = request.json['title']
description = request.json['description']
tags = request.json['tags']
article_id = article.insert(
{'title': title, 'description': description, 'tags': tags})
new_article = article.find_one({'_id': article_id})
output = {'title': new_article['title'],
'description': new_article['description'], 'tags': new_article['tags']}
return make_response({'code': 201, 'result': output})
@app.route("/api/v1/edit_article/<article_id>", methods=["GET", "POST"])
def edit_article(article_id):
article = mongo.db.articles
title = request.json['title']
description = request.json['description']
tags = request.json['tags']
for art in article.find({"_id": ObjectId(article_id)}):
if art['_id'] == ObjectId(article_id):
updated_data = {
'title': title,
'description': description,
'tags': tags
}
existing_data = {"title": art['title'],
"description": art['description'], "tags": art['tags']}
if updated_data != existing_data:
update_article = article.update(
{"_id": art['_id']},
{"$set": updated_data}, upsert=False)
return make_response({'code': 200, "Message": update_article})
else:
return make_response({'code': 404, 'Message': 'No Code Updated'})
return make_response({'code': 404, "Message": "Article Not Found"})
@app.route("/api/v1/delete/<article_id>", methods=["DELETE"])
def delete(article_id):
article = mongo.db.articles
for art in article.find({"_id": ObjectId(article_id)}):
if art['_id'] == ObjectId(article_id):
article.remove(
{"_id": art['_id']})
return make_response({'code': 200, "Message": "Article Deleted Successfully"})
def new_user_creation():
"""[User Creation]
Params: Username
Params: Password
Uses: Bcrypt to generate Password
Uses: Users Table
"""
user = mongo.db.users
gen_hashpass = bcrypt.generate_password_hash(request.json['password'])
user.insert(
{'username': request.json['username'], 'password': gen_hashpass})
session['username'] = request.json['username']
@app.route("/api/v1/login", methods=['POST', 'GET'])
def login():
"""[Logins The User]
Returns:
[Access Token] -- [Returns access token, with code 200]
[!Access Token] -- [Returns code 404]
"""
user = mongo.db.users
username = request.json['username']
password = request.json['password']
for user_details in user.find():
if user_details['username'] == username and bcrypt.check_password_hash(user_details['password'], password):
access_token = create_access_token(identity=username)
return make_response({'code': 200, 'access_token': access_token, "Message": "Ok"})
return make_response({'code': 404, 'Message': "User Not Found, would you like to create one?"})
@app.route("/protected", methods=["GET"])
@jwt_required
def protected():
"""
protected [JWT]
[extended_summary]
Returns:
[Success] -- [Return Current User If Login Is Successful]
"""
current_user = get_jwt_identity()
return make_response({'code': 200, "logged_in_as": current_user})
@app.route("/api/v1/register", methods=['POST', 'GET'])
def create_user():
"""
create_user [Route call to create a user]
[Uses the new_user_creation method]
:return: [201, successfully created + Username]
:rtype: [In case of failure, returns, 403]
"""
user = mongo.db.users
# Users table definition for MongoDB
if request.method == 'POST':
user_exists = user.find_one({'username': request.json['username']})
if user_exists is None:
new_user_creation()
return make_response({'code': 201, "Message": "User {} has been created successfully".format(session['username'])})
return make_response({'code': 403, "Message": 'Already Exists'})
if __name__ == "__main__":
app.run(debug=True)
Now, let’s walk through code as we alwaaaaaays do 😁.
First, we’ll do some facelifting(dunno how i got to use word every now and then)
we will introduce, docstring because we’ll be introducing swagger later for documentation. so we did something like:
"""
add_articles [Adds new article]
[Saves it to databases, with tags, description etc...]
:return: [description]
:rtype: [type]
"""
EDIT POST
Now, We’ll now make our Edit/Update route in our CRUD. Let’s do that now…
@app.route(“/api/v1/edit_article/<article_id>”, _methods_=[“GET”, “POST”])
_def_ edit_article(_article_id_):
article = mongo.db.articles
title = request.json[‘title’]
description = request.json[‘description’]
tags = request.json[‘tags’]
The code above is pretty much same in every article route. So we don’t can simply skip that and go to next part ….
So, in the code below I will loop through articles using art keyword(not much good keyword usage by me 😒) and look for the ID we’ll pass as parameter in
@app.route(“/api/v1/edit_article/<article_id>”, _methods_=[“GET”, “POST”])
notice, article_id passed as param here, we will use it next.
Than we’ll compare if article_id that we’re passing does matches with the article id in collection. If yes, we’ll define the dictionary of update_data which will be the data that we’ll hold the data that we’ll be updating.
for art in article.find({“_id”: ObjectId(article_id)}):
if art[‘_id’] == ObjectId(article_id):
updated_data = {
‘title’: title,
‘description’: description,
‘tags’: tags
}
Now, next we will define our existing dictionary, which means the data we currently have saved in our db..
existing_data = {"title": art['title'],
"description": art['description'], "tags": art['tags']}
Okay, next step is we’ll check if our data that we’re passing as data to be updated is equal to or not equal to our existing data. If data is not same as our existing data it will get updated, with upsert set to False (will explain what upsert is).
if updated_data != existing_data:
update_article = article.update(
{"_id": art['_id']},
{"$set": updated_data}, _upsert_=False)
return make_response({'code': 200, "Message": update_article})
else:
return make_response({'code': 404, 'Message': 'No Code Updated'})
We can check the same in our database, let me show you to confirm that’s working.
This is the data I am seeing when I am browsing my collection
{
"title": "Hi this is the blacksheep post",
"description": "This ïś the aæaãaæaãaæaãaæaãaæaãaæaã",
"tags": "hi, testing, zero post"
}
To check if data is getting updated.
we will send new request data set like this.
{
"title": "Hi this is the this is awesome post",
"description": "This ïś the awesome post",
"tags": "hi, testing, awesome post"
}
Do a request for update article like this from our edit_article path, your article ID would be different case in my case it’s 5dbb07a99b5d9fc1d7127fa8
So this shall get updated right? let’s see in our DB if that’s updated
YAY!! our data got updated 🙌🏻.
Delete Post
So next stop.. DELETE. To this we will use “DELETE” method. Let’s check the code to delete. The code below uses delete method with article_id as parameter.
@app.route("/api/v1/delete/<article_id>", _methods_=["DELETE"])
def delete(_article_id_):
article = mongo.db.articles
for art in article.find({"_id": ObjectId(article_id)}):
if art['_id'] == ObjectId(article_id):
article.remove(
{"_id": art['_id']})
return make_response({'code': 200, "Message": "Article Deleted Successfully"})
so we’ll again use a loop with .find method looking for id key which have article_id as value. P.S ObjectID is method imported from bson.ObjectID to actually convert parameter id as mongo compatible and do a comparison.
We than did an if/else block to do the comparison and than called .remove method to remove the respective post with that article.
Let’s see how we did that delete call in postman, pass the relative article id
When you hit send it will delete the related post. You can check the collection to see if the post actually go deleted.
Awesome!!! we deleted our post….
That’s it folks.. We’ve successfull done the CRUD implementation on our Posts.
Top comments (0)