Vue.js + Python + MongoDB CRUD 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.
More Related Topics,
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
User Interfaces
-Retrieve all Users:
-Add a 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 2 - UI development using Vue.js
PART 1 - Rest APIs Development using Python and Flask
These are APIs that Flask App will export:
- GET all User's : /api/v1/users
- GET User by ID : /api/v1/users/{_id}
- POST User : /api/v1/users
- PUT User : /api/v1/users/{_id}
- DELETE User : /api/v1/users/{_id}
Back end project directory:
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.
$ python3 app.py
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')
Run
## Project setup
npm install
### Run the application in local
npm run serve
App running at:
- Local: http://localhost:8080/