Vue.js + Python + MongoDB CRUD example - Full stack development example

Hello everyone, today we will learn how to develop a  web application that is a basic User Management Application using MongoDB, Vue.js, Python, and Flask.GitHub repository link is provided at the end of this tutorial. You can download the source code.


After completing this tutorial what we will build?

We will build a full-stack web application that is a basic User Management Application with CRUD features:
 
    • Create User
    • List User
    • Update User
    • Delete User


Following is the screenshot of our application -

-Retrieve all Users:


-Add a User:


-Update User:



We divided this tutorial into two parts. 

PART 1 - Rest APIs Development using Python and Flask

PART 2 - UI development using Vue.js

PART 1 - Rest APIs Development using Python and Flask

These are APIs that Flask App will export:

  1. GET all User's        :     /api/v1/users
  2. GET User by ID     :     /api/v1/users/{_id}
  3. POST User             :     /api/v1/users 
  4. PUT User               :     /api/v1/users/{_id} 
  5. DELETE User       :     /api/v1/users/{_id}
Back end project directory(simple)


In this project, I'm using flask, flask_cors & pymongo dependencies, use the following command to install the same.

pip install flask flask_cors pymongo

database.yaml

uri: 'mongodb://localhost:27017/knf-dev'

app.py

from flask import Flask, render_template, request, jsonify
from pymongo import MongoClient
from bson.objectid import ObjectId
from flask_cors import CORS
import yaml

app = Flask(__name__)
config = yaml.load(open('database.yaml'))
client = MongoClient(config['uri'])
# db = client.lin_flask
db = client['knf-dev']
CORS(app)

@app.route('/')
def index():
return render_template('home.html')

@app.route('/api/v1/users', methods=['POST', 'GET'])
def data():
# POST a data to database
if request.method == 'POST':
body = request.json
firstName = body['firstName']
lastName = body['lastName']
emailId = body['emailId']
# db.users.insert_one({
db['users'].insert_one({
"firstName": firstName,
"lastName": lastName,
"emailId":emailId
})
return jsonify({
'status': 'Data is posted to MongoDB!',
'firstName': firstName,
'lastName': lastName,
'emailId':emailId
})
# GET all data from database
if request.method == 'GET':
allData = db['users'].find()
dataJson = []
for data in allData:
id = data['_id']
firstName = data['firstName']
lastName = data['lastName']
emailId = data['emailId']
dataDict = {
'id': str(id),
'firstName': firstName,
'lastName': lastName,
'emailId': emailId
}
dataJson.append(dataDict)
print(dataJson)
return jsonify(dataJson)

@app.route('/api/v1/users/<string:id>', methods=['GET', 'DELETE', 'PUT'])
def onedata(id):

# GET a specific data by id
if request.method == 'GET':
data = db['users'].find_one({'_id': ObjectId(id)})
id = data['_id']
firstName = data['firstName']
lastName = data['lastName']
emailId = data['emailId']
dataDict = {
'id': str(id),
'firstName': firstName,
'lastName': lastName,
'emailId':emailId
}
print(dataDict)
return jsonify(dataDict)
# DELETE a data
if request.method == 'DELETE':
db['users'].delete_many({'_id': ObjectId(id)})
print('\n # Deletion successful # \n')
return jsonify({'status': 'Data id: ' + id + ' is deleted!'})

# UPDATE a data by id
if request.method == 'PUT':
body = request.json
firstName = body['firstName']
lastName = body['lastName']
emailId = body['emailId']

db['users'].update_one(
{'_id': ObjectId(id)},
{
"$set": {
"firstName":firstName,
"lastName":lastName,
"emailId": emailId
}
}
)

print('\n # Update successful # \n')
return jsonify({'status': 'Data id: ' + id + ' is updated!'})

if __name__ == '__main__':
app.debug = True
app.run()

Run the server file. Make sure your MongoDB server is still running. Your application server will run locally at http://localhost:5000 : 

$ python3 app.py

Console output:

* Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 307-094-932

PART 2 - UI development using Vue.js

Now we are going to develop a Vue.js web application. 

package structure - Front end




The package.json file

{
"name": "frontend-vuejs",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.18.0",
"vue": "^2.6.6",
"vue-router": "^3.0.2"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.5.0",
"@vue/cli-plugin-eslint": "^3.5.0",
"@vue/cli-service": "^3.5.0",
"babel-eslint": "^10.0.1",
"eslint": "^5.8.0",
"eslint-plugin-vue": "^5.0.0",
"vue-template-compiler": "^2.5.21"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"rules": {},
"parserOptions": {
"parser": "babel-eslint"
}
},
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}

Components

Vue Components are one of the important features of VueJS that creates custom elements, which can be reused in HTML

User.vue

<template>
<div>
<h3>User</h3>
<div class="container">
<form @submit="validateAndSubmit">
<div v-if="errors.length">
<div
class="alert alert-danger"
v-bind:key="index"
v-for="(error, index) in errors"
>
{{ error }}
</div>
</div>
<fieldset class="form-group">
<label>First Name</label>
<input type="text" class="form-control" v-model="firstName" />
</fieldset>
<fieldset class="form-group">
<label>Last Name</label>
<input type="text" class="form-control" v-model="lastName" />
</fieldset>
<fieldset class="form-group">
<label>Email Id</label>
<input type="text" class="form-control" v-model="emailId" />
</fieldset>
<button class="btn btn-success" type="submit">Save</button>
</form>
</div>
</div>
</template>
<script>
import UserDataService from "../service/UserDataService";

export default {
name: "User",
data() {
return {
firstName: "",
lastName: "",
emailId: "",
errors: [],
};
},
computed: {
id() {
return this.$route.params.id;
},
},
methods: {
refreshUserDetails() {
UserDataService.retrieveUser(this.id).then((res) => {
this.firstName = res.data.firstName;
this.lastName = res.data.lastName;
this.emailId = res.data.emailId;
});
},
validateAndSubmit(e) {
e.preventDefault();
this.errors = [];
if (!this.firstName) {
this.errors.push("Enter valid values");
} else if (this.firstName.length < 5) {
this.errors.push("Enter atleast 5 characters in First Name");
}
if (!this.lastName) {
this.errors.push("Enter valid values");
} else if (this.lastName.length < 5) {
this.errors.push("Enter atleast 5 characters in Last Name");
}
if (this.errors.length === 0) {
if (this.id == -1) {
UserDataService.createUser({
firstName: this.firstName,
lastName: this.lastName,
emailId: this.emailId,
}).then(() => {
this.$router.push("/users");
});
} else {
UserDataService.updateUser(this.id, {
id: this.id,
firstName: this.firstName,
lastName: this.lastName,
emailId: this.emailId,
}).then(() => {
this.$router.push("/users");
});
}
}
},
},
created() {
this.refreshUserDetails();
},
};
</script>

Users.vue

<template>
<div class="container">
<h3>All Users</h3>
<div v-if="message" class="alert alert-success">{{ this.message }}</div>
<div class="container">
<table class="table">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email Id</th>
<th>Update</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
<tr v-for="user in users" v-bind:key="user.id">
<td>{{ user.firstName }}</td>
<td>{{ user.lastName }}</td>
<td>{{ user.emailId }}</td>
<td>
<button class="btn btn-warning" v-on:click="updateUser(user.id)">
Update
</button>
</td>
<td>
<button class="btn btn-danger" v-on:click="deleteUser(user.id)">
Delete
</button>
</td>
</tr>
</tbody>
</table>
<div class="row">
<button class="btn btn-success" v-on:click="addUser()">Add</button>
</div>
</div>
</div>
</template>
<script>
import UserDataService from "../service/UserDataService";

export default {
name: "Users",
data() {
return {
users: [],
message: "",
};
},
methods: {
refreshUsers() {
UserDataService.retrieveAllUsers().then((res) => {
this.users = res.data;
});
},
addUser() {
this.$router.push(`/user/-1`);
},
updateUser(id) {
this.$router.push(`/user/${id}`);
},
deleteUser(id) {
UserDataService.deleteUser(id).then(() => {
this.refreshUsers();
});
},
},
created() {
this.refreshUsers();
},
};
</script>

UserDataService.js

import axios from 'axios'


const USER_API_URL = 'http://localhost:5000/api/v1'


class UserDataService {


retrieveAllUsers() {

return axios.get(`${USER_API_URL}/users`);
}


retrieveUser(id) {

return axios.get(`${USER_API_URL}/users/${id}`);
}


deleteUser(id) {

return axios.delete(`${USER_API_URL}/users/${id}`);
}


updateUser(id, user) {

return axios.put(`${USER_API_URL}/users/${id}`, user);
}


createUser(user) {

return axios.post(`${USER_API_URL}/users`, user);
}


}

export default new UserDataService()

App.vue

<template>
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">Python + Flask + Mongo DB
+ Vue.js CRUD Application</a><br/><br/>
</div>
<router-view/>
</div>
</template>

<script>
export default {
name: "app"
};
</script>

<style>
@import url(https://stackpath.bootstrapcdn.com/bootstrap/4.3.1
/css/bootstrap.min.css);

</style>

routes.js

import Vue from "vue";
import Router from "vue-router";

Vue.use(Router);

const router = new Router({
mode: 'history',
routes: [
{
path: "/",
name: "Users",
component: () => import("./components/Users"),
},
{
path: "/users",
name: "Users",
component: () => import("./components/Users"),
},
{
path: "/user/:id",
name: "User",
component: () => import("./components/User"),
},
]
});

export default router;

main.js

import Vue from 'vue'
import App from './App.vue'
import router from './routes';

Vue.config.productionTip = false

new Vue({
router,
render: h => h(App),
}).$mount('#app')


## Project setup
npm install

### Run the application in local
npm run serve

Popular posts from this blog

Spring boot video streaming example-HTML5

DataTable-Pagination example with Spring boot, jQuery and ajax

10 Best Job Posting Sites 2021-2022

Spring boot web project free download:User Registration System

Spring Boot + JPA/Hibernate One to Many mapping example

5 Hardest Puzzle,100% fail answers

Java security AES,SHA256,SHA512,MD5-Spring Boot Project Free Download

Spring Boot-AngularJS-Bootstrap-JPA-CRUD

ReactJS - Bootstrap - Buttons

Spring Boot file upload/download example